From 84f37b6b1af70688892d8863d963a9387cba4800 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Tue, 28 Nov 2023 19:19:29 +0000 Subject: [PATCH 001/353] Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/2973 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 662aadc4939cf..ccc4160ea834e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-11-28 +leanprover/lean4-pr-releases:pr-release-2973 From 4ad58da2ee472fe039b14d1e432343d570d47f22 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Tue, 28 Nov 2023 12:05:57 -0800 Subject: [PATCH 002/353] direct manifest to use my std4 branch --- lake-manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index fad26333341b3..51638590646ab 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -1,10 +1,10 @@ {"version": 7, "packagesDir": ".lake/packages", "packages": - [{"url": "https://github.com/leanprover/std4", + [{"url": "https://github.com/kmill/std4", "type": "git", "subDir": null, - "rev": "8f543b17ad95f3741d5e449723466f1f3d02bc8f", + "rev": "7ca1c2c8232a72a10ba14e69869d1efc6666b043", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "nightly-testing", From c47c1e2fa7b5c518ed0ef24aa687356960858a16 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Tue, 28 Nov 2023 12:08:37 -0800 Subject: [PATCH 003/353] fix clean tactic --- Mathlib/Tactic/Clean.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Tactic/Clean.lean b/Mathlib/Tactic/Clean.lean index 2e04153ea5d0e..d1c1bb02bc2d4 100644 --- a/Mathlib/Tactic/Clean.lean +++ b/Mathlib/Tactic/Clean.lean @@ -29,8 +29,8 @@ def clean (e : Expr) : Expr := | .app (.app (.const n _) _) e' => if n ∈ cleanConsts then some e' else none | .app (.lam _ _ (.bvar 0) _) e' => some e' | e => - match letFunAnnotation? e with - | some (.app (.lam _ _ (.bvar 0) _) e') => some e' + match e.letFun? with + | some (_n, _t, v, .bvar 0) => some v | _ => none end Lean.Expr From 48c16a3164150bf797007433a3ed67e043d73af9 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Tue, 28 Nov 2023 13:08:31 -0800 Subject: [PATCH 004/353] updated manifest for qq fixes --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index 51638590646ab..84a9bfda475b1 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -13,7 +13,7 @@ {"url": "https://github.com/leanprover-community/quote4", "type": "git", "subDir": null, - "rev": "d3a1d25f3eba0d93a58d5d3d027ffa78ece07755", + "rev": "ed2e76b58dae0149b99d11faa66b68974d741003", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", From fea383e9d36b969700beae48cdab714c75fb942e Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Tue, 28 Nov 2023 15:57:25 -0800 Subject: [PATCH 005/353] fixes --- Mathlib/Data/Nat/Bits.lean | 4 +--- Mathlib/Data/PFun.lean | 2 +- Mathlib/Init/Data/Nat/Bitwise.lean | 6 +++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Mathlib/Data/Nat/Bits.lean b/Mathlib/Data/Nat/Bits.lean index d9bbf827e7dd5..e4ce421787d94 100644 --- a/Mathlib/Data/Nat/Bits.lean +++ b/Mathlib/Data/Nat/Bits.lean @@ -174,9 +174,7 @@ theorem binaryRec_eq' {C : ℕ → Sort*} {z : C 0} {f : ∀ b n, C n → C (bit simp only [imp_false, or_false_iff, eq_self_iff_true, not_true] at h exact h.symm · dsimp only [] - -- Porting note: this line was `generalize_proofs e`: - generalize @id (C (bit b n) = C (bit (bodd (bit b n)) (div2 (bit b n)))) - (Eq.symm (bit_decomp (bit b n)) ▸ Eq.refl (C (bit b n))) = e + generalize_proofs e revert e rw [bodd_bit, div2_bit] intros diff --git a/Mathlib/Data/PFun.lean b/Mathlib/Data/PFun.lean index 8fba62f35965d..da0cca946ca7e 100644 --- a/Mathlib/Data/PFun.lean +++ b/Mathlib/Data/PFun.lean @@ -342,7 +342,7 @@ theorem fixInduction_spec {C : α → Sort*} {f : α →. Sum β α} {b : β} {a @fixInduction _ _ C _ _ _ h H = H a h fun a' h' => fixInduction (fix_fwd h h') H := by unfold fixInduction -- Porting note: `generalize` required to address `generalize_proofs` bug - generalize (Part.mem_assert_iff.1 h).fst = ha + generalize @fixInduction.proof_1 α β f b a h = ha induction ha rfl #align pfun.fix_induction_spec PFun.fixInduction_spec diff --git a/Mathlib/Init/Data/Nat/Bitwise.lean b/Mathlib/Init/Data/Nat/Bitwise.lean index 5d8d5c74da67e..fd649272448e7 100644 --- a/Mathlib/Init/Data/Nat/Bitwise.lean +++ b/Mathlib/Init/Data/Nat/Bitwise.lean @@ -9,6 +9,7 @@ import Mathlib.Data.Bool.Basic import Mathlib.Init.Data.Bool.Lemmas import Mathlib.Init.ZeroOne import Mathlib.Tactic.Cases +import Mathlib.Tactic.GeneralizeProofs #align_import init.data.nat.bitwise from "leanprover-community/lean"@"53e8520d8964c7632989880372d91ba0cecbaf00" @@ -333,9 +334,8 @@ theorem binaryRec_eq {C : Nat → Sort u} {z : C 0} {f : ∀ b n, C n → C (bit rfl case neg h' => simp only [dif_neg h] - generalize @id (C (bit b n) = C (bit (bodd (bit b n)) (div2 (bit b n)))) - (Eq.symm (bit_decomp (bit b n)) ▸ Eq.refl (C (bit b n))) = e - revert e + generalize_proofs h + revert h rw [bodd_bit, div2_bit] intros; rfl #align nat.binary_rec_eq Nat.binaryRec_eq From ca8f3a7fdb4943cb60cabe248d8bb92d274d4c19 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Tue, 28 Nov 2023 16:34:15 -0800 Subject: [PATCH 006/353] change file to trigger rebuild --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index 84a9bfda475b1..5a815ab7e86d6 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -13,7 +13,7 @@ {"url": "https://github.com/leanprover-community/quote4", "type": "git", "subDir": null, - "rev": "ed2e76b58dae0149b99d11faa66b68974d741003", + "rev": "ef960ea064deebe84c5655a1a5e7142403f88f82", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", From 9fc7d4f5ff8e8dc68696363ca8ce81c6337325f3 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Tue, 28 Nov 2023 18:49:30 -0800 Subject: [PATCH 007/353] lint --- Mathlib/Data/List/Func.lean | 1 - Mathlib/Data/Stream/Init.lean | 1 - 2 files changed, 2 deletions(-) diff --git a/Mathlib/Data/List/Func.lean b/Mathlib/Data/List/Func.lean index 0c0ff33a59db9..5b078a11ff3e1 100644 --- a/Mathlib/Data/List/Func.lean +++ b/Mathlib/Data/List/Func.lean @@ -106,7 +106,6 @@ theorem length_set : ∀ {m : ℕ} {as : List α}, as {m ↦ a}.length = max as. · simp [Nat.le_add_right] exact Nat.succ_le_succ (Nat.zero_le _) | m + 1, [] => by - have := @length_set m [] simp [set, length, @length_set m, Nat.zero_max] | m + 1, _ :: as => by simp [set, length, @length_set m, Nat.succ_max_succ] diff --git a/Mathlib/Data/Stream/Init.lean b/Mathlib/Data/Stream/Init.lean index 24eaf6b30e45c..e427f9af4baa2 100644 --- a/Mathlib/Data/Stream/Init.lean +++ b/Mathlib/Data/Stream/Init.lean @@ -432,7 +432,6 @@ theorem get_interleave_left : ∀ (n : Nat) (s₁ s₂ : Stream' α), | n + 1, s₁, s₂ => by change get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n) rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons] - have : n < succ n := Nat.lt_succ_self n rw [get_interleave_left n (tail s₁) (tail s₂)] rfl #align stream.nth_interleave_left Stream'.get_interleave_left From d8476476232a6811a248fc2b4c84c727d0a664ed Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 14 Dec 2023 09:55:31 +1100 Subject: [PATCH 008/353] chore: update Std dependency to match leanprover/std4#397 --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index 397f4d21cb731..729abf9497ffc 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "483fd2846f9fe5107011ece0cc3d8d88af1a8603", + "rev": "16d8352f7ed0d38cbc58ace03b3429d693cf50c6", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", From 1c53872d042f8c1e2eb453d74cc420c255e4dc1e Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 14 Dec 2023 00:11:43 +0000 Subject: [PATCH 009/353] chore: adaptations for leanprover/lean4#2923 (#9011) This PR is targeting the `bump/v4.5.0` branch. It contains the adaptations required for leanprover/lean4#2923, which have now landed in the `2023-12-12` nightly toolchain. The only changes are in `simp [...] says ...` statements, where some spurious lemmas are now no longer reported. *Many* further `simp only` statements in Mathlib contain spurious lemmas which would now no longer be produced by a fresh `simp?`, and I would strongly encourage anyone interested in removing these! For now such changes will need to be made in a PR targeting `bump/v4.5.0` (like this PR), or in January they can be done on `master`. Co-authored-by: Scott Morrison --- .../IfNormalization/WithoutAesop.lean | 10 +++++----- .../CategoryTheory/Monoidal/Preadditive.lean | 11 +++++----- lean-toolchain | 2 +- test/abel.lean | 9 +-------- test/matrix.lean | 20 +++++++++---------- 5 files changed, 21 insertions(+), 31 deletions(-) diff --git a/Archive/Examples/IfNormalization/WithoutAesop.lean b/Archive/Examples/IfNormalization/WithoutAesop.lean index 79cda7b878191..d497e0d6f32ac 100644 --- a/Archive/Examples/IfNormalization/WithoutAesop.lean +++ b/Archive/Examples/IfNormalization/WithoutAesop.lean @@ -92,21 +92,21 @@ def normalize' (l : AList (fun _ : ℕ => Bool)) : · simp_all · have := ht₃ v have := he₃ v - simp_all? says simp_all only [Option.elim, ne_eq, normalized, Bool.and_eq_true, + simp_all? says simp_all only [Option.elim, normalized, Bool.and_eq_true, Bool.not_eq_true', AList.lookup_insert, imp_false] obtain ⟨⟨⟨tn, tc⟩, tr⟩, td⟩ := ht₂ split <;> rename_i h' · subst h' simp_all - · simp_all? says simp_all only [ne_eq, hasNestedIf, Bool.or_self, hasConstantIf, - and_self, hasRedundantIf, Bool.or_false, beq_eq_false_iff_ne, not_false_eq_true, + · simp_all? says simp_all only [hasNestedIf, Bool.or_self, hasConstantIf, and_self, + hasRedundantIf, Bool.or_false, beq_eq_false_iff_ne, ne_eq, not_false_eq_true, disjoint, List.disjoint, decide_True, Bool.and_self] · have := ht₃ w have := he₃ w by_cases h : w = v · subst h; simp_all - · simp_all? says simp_all only [Option.elim, ne_eq, normalized, Bool.and_eq_true, - Bool.not_eq_true', not_false_eq_true, AList.lookup_insert_ne] + · simp_all? says simp_all only [Option.elim, normalized, Bool.and_eq_true, + Bool.not_eq_true', ne_eq, not_false_eq_true, AList.lookup_insert_ne] obtain ⟨⟨⟨en, ec⟩, er⟩, ed⟩ := he₂ split at b <;> rename_i h' · subst h'; simp_all diff --git a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean index 2cd3cb0892697..de09694784229 100644 --- a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean +++ b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean @@ -283,9 +283,8 @@ theorem leftDistributor_ext_left {J : Type} [Fintype J] {X Y : C} {f : J → C} apply (cancel_epi (leftDistributor X f).inv).mp ext simp? [leftDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp] says - simp only [leftDistributor_inv, Preadditive.comp_sum_assoc, ne_eq, biproduct.ι_π_assoc, - dite_comp, zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, - ite_true] + simp only [leftDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp, + zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, ite_true] apply w @[ext] @@ -295,7 +294,7 @@ theorem leftDistributor_ext_right {J : Type} [Fintype J] {X Y : C} {f : J → C} ext simp? [leftDistributor_hom, Preadditive.sum_comp, Preadditive.comp_sum_assoc, biproduct.ι_π, comp_dite] says - simp only [leftDistributor_hom, Category.assoc, Preadditive.sum_comp, ne_eq, biproduct.ι_π, + simp only [leftDistributor_hom, Category.assoc, Preadditive.sum_comp, biproduct.ι_π, comp_dite, comp_zero, Finset.sum_dite_eq', Finset.mem_univ, eqToHom_refl, Category.comp_id, ite_true] apply w @@ -327,7 +326,7 @@ theorem rightDistributor_ext_left {J : Type} [Fintype J] apply (cancel_epi (rightDistributor f X).inv).mp ext simp? [rightDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp] says - simp only [rightDistributor_inv, Preadditive.comp_sum_assoc, ne_eq, biproduct.ι_π_assoc, + simp only [rightDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp, zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, ite_true] apply w @@ -340,7 +339,7 @@ theorem rightDistributor_ext_right {J : Type} [Fintype J] ext simp? [rightDistributor_hom, Preadditive.sum_comp, Preadditive.comp_sum_assoc, biproduct.ι_π, comp_dite] says - simp only [rightDistributor_hom, Category.assoc, Preadditive.sum_comp, ne_eq, biproduct.ι_π, + simp only [rightDistributor_hom, Category.assoc, Preadditive.sum_comp, biproduct.ι_π, comp_dite, comp_zero, Finset.sum_dite_eq', Finset.mem_univ, eqToHom_refl, Category.comp_id, ite_true] apply w diff --git a/lean-toolchain b/lean-toolchain index 91ccf6ac0908c..44fb7b41b9811 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.4.0-rc1 +leanprover/lean4:nightly-2023-12-12 diff --git a/test/abel.lean b/test/abel.lean index 873a6732ef674..153832f337024 100644 --- a/test/abel.lean +++ b/test/abel.lean @@ -98,15 +98,8 @@ error: abel_nf made no progress example [AddCommGroup α] (x y z : α) (_w : x = y + z) : False := by abel_nf at * -/-- -error: no goals to be solved --/ --- This error message is confusing: it is saying that it closed the main goal, --- and so then had nothing to do on the hypotheses. --- The user has to guess that they should remove the `at *`. -#guard_msgs in example [AddCommGroup α] (x y z : α) (_w : x = y + z) : x - x = 0 := by - abel_nf at * + abel_nf /-- error: abel_nf made no progress diff --git a/test/matrix.lean b/test/matrix.lean index deac900999aea..373088b059c88 100644 --- a/test/matrix.lean +++ b/test/matrix.lean @@ -10,8 +10,6 @@ import Std.Tactic.GuardExpr open Qq --- TODO: uncomment above imports when they are ported - variable {α β : Type} [Semiring α] [Ring β] namespace Matrix @@ -138,10 +136,10 @@ example {a b c d e f g h : α} : ![a, b, c, d, e, f, g, h] 99 = d := by simp example {α : Type _} [CommRing α] {a b c d : α} : Matrix.det !![a, b; c, d] = a * d - b * c := by simp? [Matrix.det_succ_row_zero, Fin.sum_univ_succ] says - simp only [det_succ_row_zero, Nat.odd_iff_not_even, of_apply, cons_val', empty_val', + simp only [det_succ_row_zero, of_apply, cons_val', empty_val', cons_val_fin_one, cons_val_zero, det_unique, Fin.default_eq_zero, submatrix_apply, - Fin.succ_zero_eq_one, ne_eq, cons_val_one, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, - pow_zero, one_mul, not_true_eq_false, Fin.zero_succAbove, head_cons, Finset.univ_unique, + Fin.succ_zero_eq_one, cons_val_one, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, + pow_zero, one_mul, Fin.zero_succAbove, head_cons, Finset.univ_unique, Fin.val_succ, Fin.coe_fin_one, zero_add, pow_one, cons_val_succ, neg_mul, Fin.succ_succAbove_zero, Finset.sum_const, Finset.card_singleton, smul_neg, one_smul] ring @@ -150,12 +148,12 @@ example {α : Type _} [CommRing α] {a b c d e f g h i : α} : Matrix.det !![a, b, c; d, e, f; g, h, i] = a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g := by simp? [Matrix.det_succ_row_zero, Fin.sum_univ_succ] says - simp only [det_succ_row_zero, Nat.odd_iff_not_even, of_apply, cons_val', empty_val', - cons_val_fin_one, cons_val_zero, submatrix_apply, Fin.succ_zero_eq_one, cons_val_one, head_cons, - submatrix_submatrix, det_unique, Fin.default_eq_zero, Function.comp_apply, Fin.succ_one_eq_two, - ne_eq, cons_val_two, tail_cons, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, pow_zero, - one_mul, not_true_eq_false, Fin.zero_succAbove, Finset.univ_unique, Fin.val_succ, - Fin.coe_fin_one, zero_add, pow_one, neg_mul, Fin.succ_succAbove_zero, Finset.sum_neg_distrib, + simp only [det_succ_row_zero, of_apply, cons_val', empty_val', + cons_val_fin_one, cons_val_zero, submatrix_apply, Fin.succ_zero_eq_one, cons_val_one, + head_cons, submatrix_submatrix, det_unique, Fin.default_eq_zero, Function.comp_apply, + Fin.succ_one_eq_two, cons_val_two, tail_cons, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, + pow_zero, one_mul, Fin.zero_succAbove, Finset.univ_unique, Fin.val_succ, Fin.coe_fin_one, + zero_add, pow_one, neg_mul, Fin.succ_succAbove_zero, Finset.sum_neg_distrib, Finset.sum_singleton, cons_val_succ, Fin.succ_succAbove_one, even_add_self, Even.neg_pow, one_pow, Finset.sum_const, Finset.card_singleton, one_smul] ring From 3c6274caf58c69cc467afc8a6e23a089e0c85a55 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 14 Dec 2023 11:15:28 +1100 Subject: [PATCH 010/353] more fixes required --- Mathlib/Data/List/Basic.lean | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index f13b3ff8ff6af..6066a632bb273 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -1103,26 +1103,26 @@ theorem indexOf_cons_self (a : α) (l : List α) : indexOf a (a :: l) = 0 := by #align list.index_of_cons_self List.indexOf_cons_self -- fun e => if_pos e -theorem indexOf_cons_eq {a b : α} (l : List α) : a = b → indexOf a (b :: l) = 0 - | e => by rw [e]; exact indexOf_cons_self b l +theorem indexOf_cons_eq {a b : α} (l : List α) : b = a → indexOf a (b :: l) = 0 + | e => by rw [← e]; exact indexOf_cons_self b l #align list.index_of_cons_eq List.indexOf_cons_eq -- fun n => if_neg n @[simp] -theorem indexOf_cons_ne {a b : α} (l : List α) : a ≠ b → indexOf a (b :: l) = succ (indexOf a l) +theorem indexOf_cons_ne {a b : α} (l : List α) : b ≠ a → indexOf a (b :: l) = succ (indexOf a l) | h => by simp only [indexOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq, h, ite_false] #align list.index_of_cons_ne List.indexOf_cons_ne -- rfl theorem indexOf_cons (a b : α) (l : List α) : - indexOf a (b :: l) = if a = b then 0 else succ (indexOf a l) := by + indexOf a (b :: l) = if b = a then 0 else succ (indexOf a l) := by simp only [indexOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq] #align list.index_of_cons List.indexOf_cons theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by induction' l with b l ih · exact iff_of_true rfl (not_mem_nil _) - simp only [length, mem_cons, indexOf_cons]; split_ifs with h + simp only [length, mem_cons, indexOf_cons, eq_comm]; split_ifs with h · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h · simp only [h, false_or_iff] rw [← ih] @@ -1137,7 +1137,7 @@ theorem indexOf_of_not_mem {l : List α} {a : α} : a ∉ l → indexOf a l = le theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by induction' l with b l ih; · rfl simp only [length, indexOf_cons] - by_cases h : a = b + by_cases h : b = a · rw [if_pos h]; exact Nat.zero_le _ · rw [if_neg h]; exact succ_le_succ ih #align list.index_of_le_length List.indexOf_le_length @@ -1152,16 +1152,16 @@ theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l · exfalso exact not_mem_nil a h rw [List.cons_append] - by_cases hh : a = d₁ + by_cases hh : d₁ = a · iterate 2 rw [indexOf_cons_eq _ hh] - rw [indexOf_cons_ne _ hh, indexOf_cons_ne _ hh, ih (mem_of_ne_of_mem hh h)] + rw [indexOf_cons_ne _ hh, indexOf_cons_ne _ hh, ih (mem_of_ne_of_mem (Ne.symm hh) h)] #align list.index_of_append_of_mem List.indexOf_append_of_mem theorem indexOf_append_of_not_mem {a : α} (h : a ∉ l₁) : indexOf a (l₁ ++ l₂) = l₁.length + indexOf a l₂ := by induction' l₁ with d₁ t₁ ih · rw [List.nil_append, List.length, zero_add] - rw [List.cons_append, indexOf_cons_ne _ (ne_of_not_mem_cons h), List.length, + rw [List.cons_append, indexOf_cons_ne _ (ne_of_not_mem_cons h).symm, List.length, ih (not_mem_of_not_mem_cons h), Nat.succ_add] #align list.index_of_append_of_not_mem List.indexOf_append_of_not_mem @@ -1341,7 +1341,7 @@ theorem ext_nthLe {l₁ l₂ : List α} (hl : length l₁ = length l₂) @[simp] theorem indexOf_get [DecidableEq α] {a : α} : ∀ {l : List α} (h), get l ⟨indexOf a l, h⟩ = a | b :: l, h => by - by_cases h' : a = b <;> + by_cases h' : b = a <;> simp only [h', if_pos, if_false, indexOf_cons, get, @indexOf_get _ _ l] @[simp, deprecated indexOf_get] From 81479a3c738d4cd6340d4d7897f1fa31539c6e6b Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 14 Dec 2023 11:18:44 +1100 Subject: [PATCH 011/353] fixes --- Mathlib.lean | 1 - Mathlib/Data/List/MinMax.lean | 4 ++-- Mathlib/Data/Multiset/Basic.lean | 2 +- Mathlib/Lean/System/IO.lean | 41 -------------------------------- 4 files changed, 3 insertions(+), 45 deletions(-) delete mode 100644 Mathlib/Lean/System/IO.lean diff --git a/Mathlib.lean b/Mathlib.lean index 6072d33d997ae..ef3f07fadd038 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2304,7 +2304,6 @@ import Mathlib.Lean.Meta.Simp import Mathlib.Lean.Name import Mathlib.Lean.PrettyPrinter.Delaborator import Mathlib.Lean.SMap -import Mathlib.Lean.System.IO import Mathlib.Lean.Thunk import Mathlib.LinearAlgebra.AdicCompletion import Mathlib.LinearAlgebra.AffineSpace.AffineEquiv diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index cd6b3406b684e..06313430b3b7d 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -218,8 +218,8 @@ theorem index_of_argmax : · rw [if_pos rfl] · rw [if_neg, if_neg] exact Nat.succ_le_succ (index_of_argmax h (by assumption) ham) - · exact ne_of_apply_ne f (lt_of_lt_of_le ‹_› ‹_›).ne' - · exact ne_of_apply_ne _ ‹f hd < f _›.ne' + · exact ne_of_apply_ne f (lt_of_lt_of_le ‹_› ‹_›).ne + · exact ne_of_apply_ne _ ‹f hd < f _›.ne · rw [if_pos rfl] exact Nat.zero_le _ #align list.index_of_argmax List.index_of_argmax diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index 8d5c273a7e529..f06e54b530b97 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -2650,7 +2650,7 @@ theorem count_map_eq_count' [DecidableEq β] (f : α → β) (s : Multiset α) ( theorem filter_eq' (s : Multiset α) (b : α) : s.filter (· = b) = replicate (count b s) b := Quotient.inductionOn s <| fun l => by simp only [quot_mk_to_coe, coe_filter, mem_coe, coe_count] - rw [List.filter_eq' l b, coe_replicate] + rw [List.filter_eq l b, coe_replicate] #align multiset.filter_eq' Multiset.filter_eq' theorem filter_eq (s : Multiset α) (b : α) : s.filter (Eq b) = replicate (count b s) b := by diff --git a/Mathlib/Lean/System/IO.lean b/Mathlib/Lean/System/IO.lean deleted file mode 100644 index df1b40d7f6eef..0000000000000 --- a/Mathlib/Lean/System/IO.lean +++ /dev/null @@ -1,41 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Mathlib.Data.List.Indexes - -/-! -# Functions for manipulating a list of tasks - -* `IO.waitAny'` is a wrapper for `IO.waitAny` that also returns the remaining tasks. -* `List.waitAll : List (Task α) → Task (List α)` gathers a list of tasks into a task returning - the list of all results. --/ - -set_option autoImplicit true - --- duplicated from `lean4/src/Init/System/IO.lean` -local macro "nonempty_list" : tactic => - `(tactic| exact Nat.zero_lt_succ _) - -/-- -Given a non-empty list of tasks, wait for the first to complete. -Return the value and the list of remaining tasks. --/ -def IO.waitAny' (tasks : List (Task α)) (h : List.length tasks > 0 := by nonempty_list) : - BaseIO (α × List (Task α)) := do - let (i, a) ← IO.waitAny - (tasks.mapIdx fun i t => t.map (prio := .max) fun a => (i, a)) - ((tasks.length_mapIdx _).symm ▸ h) - return (a, tasks.eraseIdx i) - -/-- -Given a list of tasks, create the task returning the list of results, -by waiting for each. --/ -def List.waitAll (tasks : List (Task α)) : Task (List α) := - match tasks with - | [] => .pure [] - | task::tasks => task.bind (prio := .max) fun a => - tasks.waitAll.map (prio := .max) fun as => a::as From b6ead5348af657f329228521e31463381ccbc3e9 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 14 Dec 2023 11:27:39 +1100 Subject: [PATCH 012/353] fix --- Mathlib/NumberTheory/SmoothNumbers.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/NumberTheory/SmoothNumbers.lean b/Mathlib/NumberTheory/SmoothNumbers.lean index 1d1c73e257f44..1089b4254847e 100644 --- a/Mathlib/NumberTheory/SmoothNumbers.lean +++ b/Mathlib/NumberTheory/SmoothNumbers.lean @@ -153,7 +153,7 @@ def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) : · refine (filter_congr' <| fun q hq ↦ ?_).symm have H : ¬ p < q := fun hf ↦ Nat.lt_le_asymm hf <| lt_succ_iff.mp (hm q hq) simp only [not_lt, le_iff_eq_or_lt, H, or_false, eq_comm, Bool.true_eq_decide_iff] - refine prod_eq <| (filter_eq' m.factors p).symm ▸ this ▸ perm_append_comm.trans ?_ + refine prod_eq <| (filter_eq m.factors p).symm ▸ this ▸ perm_append_comm.trans ?_ convert filter_append_perm .. simp only [not_lt] simp only [decide_not, Bool.not_not, lt_iff_not_ge] From f1a6b2dca0177c3be29ebae17acb024f7f2fd745 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Wed, 13 Dec 2023 19:40:41 -0500 Subject: [PATCH 013/353] fix --- Mathlib/Computability/Primrec.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Computability/Primrec.lean b/Mathlib/Computability/Primrec.lean index 5edab43f57ebe..09b38d22f97d7 100644 --- a/Mathlib/Computability/Primrec.lean +++ b/Mathlib/Computability/Primrec.lean @@ -776,7 +776,7 @@ theorem list_findIdx₁ {p : α → β → Bool} (hp : Primrec₂ p) : #align primrec.list_find_index₁ Primrec.list_findIdx₁ theorem list_indexOf₁ [DecidableEq α] (l : List α) : Primrec fun a => l.indexOf a := - list_findIdx₁ .beq l + list_findIdx₁ (.swap .beq) l #align primrec.list_index_of₁ Primrec.list_indexOf₁ theorem dom_fintype [Fintype α] (f : α → σ) : Primrec f := @@ -1134,7 +1134,7 @@ theorem list_findIdx {f : α → List β} {p : α → β → Bool} #align primrec.list_find_index Primrec.list_findIdx theorem list_indexOf [DecidableEq α] : Primrec₂ (@List.indexOf α _) := - to₂ <| list_findIdx snd <| Primrec.beq.comp₂ (fst.comp fst).to₂ snd.to₂ + to₂ <| list_findIdx snd <| Primrec.beq.comp₂ snd.to₂ (fst.comp fst).to₂ #align primrec.list_index_of Primrec.list_indexOfₓ theorem nat_strong_rec (f : α → ℕ → σ) {g : α → List σ → Option σ} (hg : Primrec₂ g) From c5a7449dcdefa212ffda871281b6306a11bc7414 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 14 Dec 2023 12:24:18 +1100 Subject: [PATCH 014/353] fix --- Mathlib/Data/List/Basic.lean | 5 +---- Mathlib/Data/List/DropRight.lean | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index 6066a632bb273..8c2c40d4e30bc 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -600,10 +600,7 @@ theorem reverse_eq_iff {l l' : List α} : l.reverse = l' ↔ l = l'.reverse := reverse_involutive.eq_iff #align list.reverse_eq_iff List.reverse_eq_iff -@[simp] -theorem reverse_eq_nil {l : List α} : reverse l = [] ↔ l = [] := - @reverse_inj _ l [] -#align list.reverse_eq_nil List.reverse_eq_nil +#align list.reverse_eq_nil List.reverse_eq_nil_iff theorem concat_eq_reverse_cons (a : α) (l : List α) : concat l a = reverse (a :: reverse l) := by simp only [concat_eq_append, reverse_cons, reverse_reverse] diff --git a/Mathlib/Data/List/DropRight.lean b/Mathlib/Data/List/DropRight.lean index ab4856e998b08..cfe2bfe061910 100644 --- a/Mathlib/Data/List/DropRight.lean +++ b/Mathlib/Data/List/DropRight.lean @@ -228,7 +228,7 @@ theorem rtakeWhile_eq_nil_iff : rtakeWhile p l = [] ↔ ∀ hl : l ≠ [], ¬p ( induction' l using List.reverseRecOn with l a · simp only [rtakeWhile, takeWhile, reverse_nil, true_iff] intro f; contradiction - · simp only [rtakeWhile, reverse_append, takeWhile, reverse_eq_nil, getLast_append, ne_eq, + · simp only [rtakeWhile, reverse_append, takeWhile, reverse_eq_nil_iff, getLast_append, ne_eq, append_eq_nil, and_false, not_false_eq_true, forall_true_left] refine' ⟨fun h => _ , fun h => _⟩ · intro pa; simp [pa] at h From d82683bc396291dc5973aad22051847995e54bfd Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 14 Dec 2023 15:55:35 +1100 Subject: [PATCH 015/353] fix --- Mathlib/Logic/Basic.lean | 2 -- lake-manifest.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Mathlib/Logic/Basic.lean b/Mathlib/Logic/Basic.lean index c690877f6773d..cc607fa34c5fd 100644 --- a/Mathlib/Logic/Basic.lean +++ b/Mathlib/Logic/Basic.lean @@ -1214,8 +1214,6 @@ protected theorem Ne.ite_ne_right_iff (h : a ≠ b) : ite P a b ≠ b ↔ P := variable (P Q a b) -/-- A `dite` whose results do not actually depend on the condition may be reduced to an `ite`. -/ -@[simp] theorem dite_eq_ite : (dite P (fun _ ↦ a) fun _ ↦ b) = ite P a b := rfl #align dite_eq_ite dite_eq_ite theorem dite_eq_or_eq : (∃ h, dite P A B = A h) ∨ ∃ h, dite P A B = B h := diff --git a/lake-manifest.json b/lake-manifest.json index 729abf9497ffc..3704f39175c35 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "16d8352f7ed0d38cbc58ace03b3429d693cf50c6", + "rev": "88d5e1775657bfcddba2bad0f8e2509ef22303ca", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", From efae9a52799af4a9b98f428323da8c8482648fa2 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Thu, 14 Dec 2023 12:15:49 -0800 Subject: [PATCH 016/353] have to haveI --- Mathlib/RingTheory/Localization/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/RingTheory/Localization/Basic.lean b/Mathlib/RingTheory/Localization/Basic.lean index 37893df92a30a..4a43d9787bd3d 100644 --- a/Mathlib/RingTheory/Localization/Basic.lean +++ b/Mathlib/RingTheory/Localization/Basic.lean @@ -811,7 +811,7 @@ theorem isLocalization_iff_of_algEquiv [Algebra R P] (h : S ≃ₐ[R] P) : #align is_localization.is_localization_iff_of_alg_equiv IsLocalization.isLocalization_iff_of_algEquiv theorem isLocalization_iff_of_ringEquiv (h : S ≃+* P) : - IsLocalization M S ↔ have := (h.toRingHom.comp <| algebraMap R S).toAlgebra; + IsLocalization M S ↔ haveI := (h.toRingHom.comp <| algebraMap R S).toAlgebra; IsLocalization M P := letI := (h.toRingHom.comp <| algebraMap R S).toAlgebra isLocalization_iff_of_algEquiv M { h with commutes' := fun _ => rfl } @@ -820,7 +820,7 @@ theorem isLocalization_iff_of_ringEquiv (h : S ≃+* P) : variable (S) theorem isLocalization_of_base_ringEquiv [IsLocalization M S] (h : R ≃+* P) : - have := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra; + haveI := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra; IsLocalization (M.map h.toMonoidHom) S := by letI : Algebra P S := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra constructor From df84ae03ad74f41a6762c0fe7be5ae491664c163 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Sun, 17 Dec 2023 11:17:19 +1100 Subject: [PATCH 017/353] fixes from nightly-testing --- Mathlib/Data/Finset/NoncommProd.lean | 2 +- Mathlib/Data/List/Perm.lean | 2 +- Mathlib/Data/List/Sigma.lean | 5 +---- Mathlib/Data/Seq/Parallel.lean | 2 +- Mathlib/Data/Set/Intervals/Basic.lean | 4 +--- .../MeasureTheory/Covering/BesicovitchVectorSpace.lean | 3 +-- Mathlib/MeasureTheory/Measure/Stieltjes.lean | 2 +- Mathlib/NumberTheory/Dioph.lean | 2 +- Mathlib/NumberTheory/LucasLehmer.lean | 9 ++++----- Mathlib/NumberTheory/Padics/Hensel.lean | 2 +- lean-toolchain | 2 +- test/matrix.lean | 4 ---- 12 files changed, 14 insertions(+), 25 deletions(-) diff --git a/Mathlib/Data/Finset/NoncommProd.lean b/Mathlib/Data/Finset/NoncommProd.lean index 2c6a89119baa7..ab0133e010833 100644 --- a/Mathlib/Data/Finset/NoncommProd.lean +++ b/Mathlib/Data/Finset/NoncommProd.lean @@ -478,7 +478,7 @@ theorem noncommProd_mul_single [Fintype ι] [DecidableEq ι] (x : ∀ i, M i) : noncommProd_eq_pow_card (univ.erase i), one_pow, mul_one] simp only [MonoidHom.single_apply, ne_eq, Pi.mulSingle_eq_same] · intro j hj - simp? at hj says simp only [mem_univ, not_true_eq_false, mem_erase, ne_eq, and_true] at hj + simp? at hj says simp only [mem_erase, ne_eq, mem_univ, and_true] at hj simp only [MonoidHom.single_apply, Pi.mulSingle, Function.update, Eq.ndrec, Pi.one_apply, ne_eq, dite_eq_right_iff] intro h diff --git a/Mathlib/Data/List/Perm.lean b/Mathlib/Data/List/Perm.lean index 5e60493e1b8e7..7342462419e54 100644 --- a/Mathlib/Data/List/Perm.lean +++ b/Mathlib/Data/List/Perm.lean @@ -361,7 +361,7 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) ( induction s generalizing l₁ case slnil => cases h₂ case cons r₁ r₂ b s' ih => - simp? at h₂ says simp only [Bool.not_eq_true, mem_cons] at h₂ + simp? at h₂ says simp only [mem_cons] at h₂ cases' h₂ with e m · subst b exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩ diff --git a/Mathlib/Data/List/Sigma.lean b/Mathlib/Data/List/Sigma.lean index 9107230c747c2..0103a751df8d6 100644 --- a/Mathlib/Data/List/Sigma.lean +++ b/Mathlib/Data/List/Sigma.lean @@ -28,7 +28,6 @@ If `α : Type*` and `β : α → Type*`, then we regard `s : Sigma β` as having - `List.kextract` returns a value with a given key and the rest of the values. -/ - universe u v namespace List @@ -204,9 +203,7 @@ theorem of_mem_dlookup {a : α} {b : β a} : | ⟨a', b'⟩ :: l, H => by by_cases h : a = a' · subst a' - simp? at H says - simp only [ne_eq, not_true_eq_false, dlookup_cons_eq, Option.mem_def, - Option.some.injEq] at H + simp? at H says simp only [dlookup_cons_eq, Option.mem_def, Option.some.injEq] at H simp [H] · simp only [ne_eq, h, not_false_iff, dlookup_cons_ne] at H simp [of_mem_dlookup H] diff --git a/Mathlib/Data/Seq/Parallel.lean b/Mathlib/Data/Seq/Parallel.lean index d45690861ef2a..e9196615fe148 100644 --- a/Mathlib/Data/Seq/Parallel.lean +++ b/Mathlib/Data/Seq/Parallel.lean @@ -237,7 +237,7 @@ theorem exists_of_mem_parallel {S : WSeq (Computation α)} {a} (h : a ∈ parall apply ret_mem · intro a' h rcases h with ⟨d, dm, ad⟩ - simp? at dm says simp only [Bool.not_eq_true, List.mem_cons] at dm + simp? at dm says simp only [List.mem_cons] at dm cases' dm with e dl · rw [e] at ad refine' ⟨c, List.mem_cons_self _ _, _⟩ diff --git a/Mathlib/Data/Set/Intervals/Basic.lean b/Mathlib/Data/Set/Intervals/Basic.lean index 39e39cac17983..7e76cce2b4dd5 100644 --- a/Mathlib/Data/Set/Intervals/Basic.lean +++ b/Mathlib/Data/Set/Intervals/Basic.lean @@ -28,7 +28,6 @@ for some statements it should be `LinearOrder` or `DenselyOrdered`). TODO: This is just the beginning; a lot of rules are missing -/ - open Function open OrderDual (toDual ofDual) @@ -1168,8 +1167,7 @@ theorem Ioo_subset_Ioo_iff [DenselyOrdered α] (h₁ : a₁ < b₁) : theorem Ico_eq_Ico_iff (h : a₁ < b₁ ∨ a₂ < b₂) : Ico a₁ b₁ = Ico a₂ b₂ ↔ a₁ = a₂ ∧ b₁ = b₂ := ⟨fun e => by - simp? [Subset.antisymm_iff] at e says - simp only [gt_iff_lt, not_lt, ge_iff_le, Subset.antisymm_iff] at e + simp only [Subset.antisymm_iff] at e simp only [le_antisymm_iff] cases' h with h h <;> simp only [gt_iff_lt, not_lt, ge_iff_le, Ico_subset_Ico_iff h] at e <;> diff --git a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean index 9c29756ed1b05..7ddcdff18db69 100644 --- a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean +++ b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean @@ -177,8 +177,7 @@ theorem card_le_of_separated (s : Finset E) (hs : ∀ c ∈ s, ‖c‖ ≤ 2) have K : (s.card : ℝ) ≤ (5 : ℝ) ^ finrank ℝ E := by have := ENNReal.toReal_le_of_le_ofReal (pow_nonneg ρpos.le _) J simp? [ENNReal.toReal_mul] at this says - simp only [one_div, inv_pow, ENNReal.toReal_mul, ENNReal.toReal_nat, inv_nonneg, ge_iff_le, - div_pow] at this + simp only [one_div, inv_pow, ENNReal.toReal_mul, ENNReal.toReal_nat, div_pow] at this simpa [div_eq_mul_inv, zero_le_two] using this exact mod_cast K #align besicovitch.card_le_of_separated Besicovitch.card_le_of_separated diff --git a/Mathlib/MeasureTheory/Measure/Stieltjes.lean b/Mathlib/MeasureTheory/Measure/Stieltjes.lean index 7b235e52ad43b..a5b77fdc9637c 100644 --- a/Mathlib/MeasureTheory/Measure/Stieltjes.lean +++ b/Mathlib/MeasureTheory/Measure/Stieltjes.lean @@ -361,7 +361,7 @@ theorem measure_singleton (a : ℝ) : f.measure {a} = ofReal (f a - leftLim f a) exists_seq_strictMono_tendsto a have A : {a} = ⋂ n, Ioc (u n) a := by refine' Subset.antisymm (fun x hx => by simp [mem_singleton_iff.1 hx, u_lt_a]) fun x hx => _ - simp? at hx says simp only [gt_iff_lt, not_lt, ge_iff_le, mem_iInter, mem_Ioc] at hx + simp? at hx says simp only [mem_iInter, mem_Ioc] at hx have : a ≤ x := le_of_tendsto' u_lim fun n => (hx n).1.le simp [le_antisymm this (hx 0).2] have L1 : Tendsto (fun n => f.measure (Ioc (u n) a)) atTop (𝓝 (f.measure {a})) := by diff --git a/Mathlib/NumberTheory/Dioph.lean b/Mathlib/NumberTheory/Dioph.lean index 74b7ef18f145f..08605491f4c84 100644 --- a/Mathlib/NumberTheory/Dioph.lean +++ b/Mathlib/NumberTheory/Dioph.lean @@ -360,7 +360,7 @@ theorem DiophList.forall (l : List (Set <| α → ℕ)) (d : l.Forall Dioph) : ⟨β, Poly.sumsq pl, fun v => (h v).trans <| exists_congr fun t => (Poly.sumsq_eq_zero _ _).symm⟩ induction' l with S l IH exact ⟨ULift Empty, [], fun _ => by simp⟩ - simp? at d says simp only [imp_false, List.forall_cons] at d + simp? at d says simp only [List.forall_cons] at d exact let ⟨⟨β, p, pe⟩, dl⟩ := d let ⟨γ, pl, ple⟩ := IH dl diff --git a/Mathlib/NumberTheory/LucasLehmer.lean b/Mathlib/NumberTheory/LucasLehmer.lean index 0d162b815dea4..33399d0928cc5 100644 --- a/Mathlib/NumberTheory/LucasLehmer.lean +++ b/Mathlib/NumberTheory/LucasLehmer.lean @@ -152,8 +152,8 @@ theorem residue_eq_zero_iff_sMod_eq_zero (p : ℕ) (w : 1 < p) : -- and `lucas_lehmer_residue p = 0 → 2^p - 1 ∣ s_mod p (p-2)`. intro h simp? [ZMod.int_cast_zmod_eq_zero_iff_dvd] at h says - simp only [ge_iff_le, ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, pow_pos, - cast_pred, cast_pow, cast_ofNat] at h + simp only [ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, pow_pos, cast_pred, + cast_pow, cast_ofNat] at h apply Int.eq_zero_of_dvd_of_nonneg_of_lt _ _ h <;> clear h · apply sMod_nonneg _ (Nat.lt_of_succ_lt w) · exact sMod_lt _ (Nat.lt_of_succ_lt w) (p - 2) @@ -425,9 +425,8 @@ theorem ω_pow_formula (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) : dsimp [lucasLehmerResidue] at h rw [sZMod_eq_s p'] at h simp? [ZMod.int_cast_zmod_eq_zero_iff_dvd] at h says - simp only [ge_iff_le, add_le_iff_nonpos_left, nonpos_iff_eq_zero, add_tsub_cancel_right, - ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, pow_pos, cast_pred, cast_pow, - cast_ofNat] at h + simp only [add_tsub_cancel_right, ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, + pow_pos, cast_pred, cast_pow, cast_ofNat] at h cases' h with k h use k replace h := congr_arg (fun n : ℤ => (n : X (q (p' + 2)))) h diff --git a/Mathlib/NumberTheory/Padics/Hensel.lean b/Mathlib/NumberTheory/Padics/Hensel.lean index bb4b424e11a41..dadcf261ad4be 100644 --- a/Mathlib/NumberTheory/Padics/Hensel.lean +++ b/Mathlib/NumberTheory/Padics/Hensel.lean @@ -354,7 +354,7 @@ private theorem bound : ∀ {ε}, ε > 0 → ∃ N : ℕ, ∀ {n}, n ≥ N → ‖F.derivative.eval a‖ * T ^ 2 ^ n < ε := by have := bound' hnorm simp? [Tendsto, nhds] at this says - simp only [Tendsto, nhds_def, Set.mem_setOf_eq, not_and, le_iInf_iff, le_principal_iff, mem_map, + simp only [Tendsto, nhds_def, Set.mem_setOf_eq, le_iInf_iff, le_principal_iff, mem_map, mem_atTop_sets, ge_iff_le, Set.mem_preimage, and_imp] at this intro ε hε cases' this (ball 0 ε) (mem_ball_self hε) isOpen_ball with N hN diff --git a/lean-toolchain b/lean-toolchain index 44fb7b41b9811..6f3419889f747 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-12 +leanprover/lean4:nightly-2023-12-16 diff --git a/test/matrix.lean b/test/matrix.lean index 373088b059c88..5fcf2ebf07e83 100644 --- a/test/matrix.lean +++ b/test/matrix.lean @@ -1,7 +1,3 @@ -/- -manually ported from -https://github.com/leanprover-community/mathlib/blob/4f4a1c875d0baa92ab5d92f3fb1bb258ad9f3e5b/test/matrix.lean --/ import Mathlib.Data.Matrix.Notation import Mathlib.GroupTheory.Perm.Fin import Mathlib.LinearAlgebra.Matrix.Determinant From 5541d213521e95c5b7d73066de4ad78a600e6263 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Sun, 17 Dec 2023 09:33:31 +0000 Subject: [PATCH 018/353] =?UTF-8?q?feat:=20add=20`Algebra=20=E2=84=9D=20A`?= =?UTF-8?q?=20instance=20given=20`Algebra=20=E2=84=82=20A`=20(#8991)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/Data/Complex/Module.lean | 28 ++++++++++++++++++++++++---- test/instance_diamonds.lean | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/Mathlib/Data/Complex/Module.lean b/Mathlib/Data/Complex/Module.lean index f15a6381f8d02..6995bb51fd02a 100644 --- a/Mathlib/Data/Complex/Module.lean +++ b/Mathlib/Data/Complex/Module.lean @@ -179,10 +179,20 @@ instance (priority := 900) Module.complexToReal (E : Type*) [AddCommGroup E] [Mo RestrictScalars.module ℝ ℂ E #align module.complex_to_real Module.complexToReal -instance Module.real_complex_tower (E : Type*) [AddCommGroup E] [Module ℂ E] : - IsScalarTower ℝ ℂ E := - RestrictScalars.isScalarTower ℝ ℂ E -#align module.real_complex_tower Module.real_complex_tower +/- Register as an instance (with low priority) the fact that a complex algebra is also a real +algebra. -/ +instance (priority := 900) Algebra.complexToReal {A : Type*} [Semiring A] [Algebra ℂ A] : + Algebra ℝ A := + RestrictScalars.algebra ℝ ℂ A + +-- try to make sure we're not introducing diamonds. +example : Prod.algebra ℝ ℂ ℂ = (Prod.algebra ℂ ℂ ℂ).complexToReal := rfl +example {ι : Type*} [Fintype ι] : + Pi.algebra (R := ℝ) ι (fun _ ↦ ℂ) = (Pi.algebra (R := ℂ) ι (fun _ ↦ ℂ)).complexToReal := + rfl +example {A : Type*} [Ring A] [inst : Algebra ℂ A] : + (inst.complexToReal).toModule = (inst.toModule).complexToReal := + rfl @[simp, norm_cast] theorem Complex.coe_smul {E : Type*} [AddCommGroup E] [Module ℂ E] (x : ℝ) (y : E) : @@ -197,6 +207,16 @@ instance (priority := 900) SMulCommClass.complexToReal {M E : Type*} [AddCommGro smul_comm r _ _ := (smul_comm (r : ℂ) _ _ : _) #align smul_comm_class.complex_to_real SMulCommClass.complexToReal +/-- The scalar action of `ℝ` on a `ℂ`-module `E` induced by `Module.complexToReal` associates with +another scalar action of `M` on `E` whenever the action of `ℂ` associates with the action of `M`. -/ +instance IsScalarTower.complexToReal {M E : Type*} [AddCommGroup M] [Module ℂ M] [AddCommGroup E] + [Module ℂ E] [SMul M E] [IsScalarTower ℂ M E] : IsScalarTower ℝ M E where + smul_assoc r _ _ := (smul_assoc (r : ℂ) _ _ : _) +#align module.real_complex_tower IsScalarTower.complexToReal + +-- check that the following instance is implied by the one above. +example (E : Type*) [AddCommGroup E] [Module ℂ E] : IsScalarTower ℝ ℂ E := inferInstance + instance (priority := 100) FiniteDimensional.complexToReal (E : Type*) [AddCommGroup E] [Module ℂ E] [FiniteDimensional ℂ E] : FiniteDimensional ℝ E := FiniteDimensional.trans ℝ ℂ E diff --git a/test/instance_diamonds.lean b/test/instance_diamonds.lean index 044be62e196c9..b6a5a8549d3e1 100644 --- a/test/instance_diamonds.lean +++ b/test/instance_diamonds.lean @@ -252,3 +252,27 @@ example : ZMod.commRing 0 = Int.instCommRingInt := rfl end ZMod + +/-! ## Instances involving structures over `ℝ` and `ℂ` + +Given a scalar action on `ℝ`, we have an instance which produces the corresponding scalar action on +`ℂ`. In the other direction, if there is a scalar action of `ℂ` on some type, we can get a +corresponding action of `ℝ` on that type via `RestrictScalars`. + +Obviously, this has the potential to cause diamonds when we can go in both directions. This shows +that at least some potential diamonds are avoided. -/ + +section complexToReal + +-- the two ways to get `Algebra ℝ ℂ` are definitionally equal +example : (Algebra.id ℂ).complexToReal = Complex.instAlgebraComplexInstSemiringComplex := rfl + +/- The complexification of an `ℝ`-algebra `A` (i.e., `ℂ ⊗[ℝ] A`) is a `ℂ`-algebra. Viewing this +as an `ℝ`-algebra by restricting scalars agrees with the existing `ℝ`-algebra structure on the +tensor product. -/ +open Algebra TensorProduct in +example {A : Type*} [Ring A] [Algebra ℝ A]: + (leftAlgebra : Algebra ℂ (ℂ ⊗[ℝ] A)).complexToReal = leftAlgebra := + rfl + +end complexToReal From fb1da20fc3c2ec3ac9c433e619d25557362d56b9 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 17 Dec 2023 10:02:48 +0000 Subject: [PATCH 019/353] chore: bump to nightly-2023-12-17 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 6f3419889f747..095b0ec449c07 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-16 +leanprover/lean4:nightly-2023-12-17 From af42783d740efe339ffaf4a83e4050edaf8f45d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sun, 17 Dec 2023 14:38:33 +0000 Subject: [PATCH 020/353] feat: A lin. indep. family of vectors in a fin. dim. space is finite (#9103) This is just a repackaging of existing lemmas, except that the correct name is already taken by the `Set` version, so we fix that too. From LeanAPAP --- Mathlib/Algebra/Module/Zlattice.lean | 4 ++-- Mathlib/Analysis/InnerProductSpace/PiL2.lean | 2 +- Mathlib/LinearAlgebra/FiniteDimensional.lean | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Mathlib/Algebra/Module/Zlattice.lean b/Mathlib/Algebra/Module/Zlattice.lean index 172a7b74fe320..add3590eb674c 100644 --- a/Mathlib/Algebra/Module/Zlattice.lean +++ b/Mathlib/Algebra/Module/Zlattice.lean @@ -388,7 +388,7 @@ theorem Zlattice.FG : AddSubgroup.FG L := by rw [← hs, ← h_span] exact span_mono (by simp only [Subtype.range_coe_subtype, Set.setOf_mem_eq, subset_rfl])) rw [show span ℤ s = span ℤ (Set.range b) by simp [Basis.coe_mk, Subtype.range_coe_subtype]] - have : Fintype s := Set.Finite.fintype h_lind.finite + have : Fintype s := h_lind.setFinite.fintype refine Set.Finite.of_finite_image (f := ((↑) : _ → E) ∘ Zspan.quotientEquiv b) ?_ (Function.Injective.injOn (Subtype.coe_injective.comp (Zspan.quotientEquiv b).injective) _) have : Set.Finite ((Zspan.fundamentalDomain b) ∩ L) := @@ -406,7 +406,7 @@ theorem Zlattice.FG : AddSubgroup.FG L := by exact span_le.mpr h_incl · -- `span ℤ s` is finitely generated because `s` is finite rw [ker_mkQ, inf_of_le_right (span_le.mpr h_incl)] - exact fg_span (LinearIndependent.finite h_lind) + exact fg_span (LinearIndependent.setFinite h_lind) theorem Zlattice.module_finite : Module.Finite ℤ L := Module.Finite.iff_addGroup_fg.mpr ((AddGroup.fg_iff_addSubgroup_fg L).mpr (FG K hs)) diff --git a/Mathlib/Analysis/InnerProductSpace/PiL2.lean b/Mathlib/Analysis/InnerProductSpace/PiL2.lean index a7663356774b9..a2ad682841a9e 100644 --- a/Mathlib/Analysis/InnerProductSpace/PiL2.lean +++ b/Mathlib/Analysis/InnerProductSpace/PiL2.lean @@ -805,7 +805,7 @@ theorem Orthonormal.exists_orthonormalBasis_extension (hv : Orthonormal 𝕜 (( ∃ (u : Finset E) (b : OrthonormalBasis u 𝕜 E), v ⊆ u ∧ ⇑b = ((↑) : u → E) := by obtain ⟨u₀, hu₀s, hu₀, hu₀_max⟩ := exists_maximal_orthonormal hv rw [maximal_orthonormal_iff_orthogonalComplement_eq_bot hu₀] at hu₀_max - have hu₀_finite : u₀.Finite := hu₀.linearIndependent.finite + have hu₀_finite : u₀.Finite := hu₀.linearIndependent.setFinite let u : Finset E := hu₀_finite.toFinset let fu : ↥u ≃ ↥u₀ := hu₀_finite.subtypeEquivToFinset.symm have hu : Orthonormal 𝕜 ((↑) : u → E) := by simpa using hu₀.comp _ fu.injective diff --git a/Mathlib/LinearAlgebra/FiniteDimensional.lean b/Mathlib/LinearAlgebra/FiniteDimensional.lean index 5547226bed321..fbfc8ffe2d1df 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean @@ -299,18 +299,18 @@ theorem lt_aleph0_of_linearIndependent {ι : Type w} [FiniteDimensional K V] {v apply Cardinal.nat_lt_aleph0 #align finite_dimensional.lt_aleph_0_of_linear_independent FiniteDimensional.lt_aleph0_of_linearIndependent -theorem _root_.LinearIndependent.finite [FiniteDimensional K V] {b : Set V} +lemma _root_.LinearIndependent.finite {ι : Type*} [FiniteDimensional K V] {f : ι → V} + (h : LinearIndependent K f) : Finite ι := + Cardinal.lt_aleph0_iff_finite.1 <| FiniteDimensional.lt_aleph0_of_linearIndependent h + +theorem not_linearIndependent_of_infinite {ι : Type*} [Infinite ι] [FiniteDimensional K V] + (v : ι → V) : ¬LinearIndependent K v := mt LinearIndependent.finite <| @not_finite _ _ +#align finite_dimensional.not_linear_independent_of_infinite FiniteDimensional.not_linearIndependent_of_infinite + +theorem _root_.LinearIndependent.setFinite [FiniteDimensional K V] {b : Set V} (h : LinearIndependent K fun x : b => (x : V)) : b.Finite := Cardinal.lt_aleph0_iff_set_finite.mp (FiniteDimensional.lt_aleph0_of_linearIndependent h) -#align linear_independent.finite LinearIndependent.finite - -theorem not_linearIndependent_of_infinite {ι : Type w} [inf : Infinite ι] [FiniteDimensional K V] - (v : ι → V) : ¬LinearIndependent K v := by - intro h_lin_indep - have : ¬ℵ₀ ≤ #ι := not_le.mpr (lt_aleph0_of_linearIndependent h_lin_indep) - have : ℵ₀ ≤ #ι := infinite_iff.mp inf - contradiction -#align finite_dimensional.not_linear_independent_of_infinite FiniteDimensional.not_linearIndependent_of_infinite +#align linear_independent.finite LinearIndependent.setFinite /-- A finite dimensional space has positive `finrank` iff it has a nonzero element. -/ theorem finrank_pos_iff_exists_ne_zero [FiniteDimensional K V] : 0 < finrank K V ↔ ∃ x : V, x ≠ 0 := From 51a63d81da01d6bebec6385899df986394ad4da6 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 17 Dec 2023 15:03:19 +0000 Subject: [PATCH 021/353] Update matrix.lean --- test/matrix.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/matrix.lean b/test/matrix.lean index 5fcf2ebf07e83..373088b059c88 100644 --- a/test/matrix.lean +++ b/test/matrix.lean @@ -1,3 +1,7 @@ +/- +manually ported from +https://github.com/leanprover-community/mathlib/blob/4f4a1c875d0baa92ab5d92f3fb1bb258ad9f3e5b/test/matrix.lean +-/ import Mathlib.Data.Matrix.Notation import Mathlib.GroupTheory.Perm.Fin import Mathlib.LinearAlgebra.Matrix.Determinant From 92d4b01aea279509d867744b54e70a37ff243af9 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 17 Dec 2023 15:16:28 +0000 Subject: [PATCH 022/353] feat: add topological lemmas for `ULift` (#8958) This also adds a handful of easy instances Arguably the topological space instance should be defined via `coinduced` to make these true by `Iff.rfl`, but that creates a headache with constructors for normed spaces, so is not in this PR. --- .../FundamentalGroupoid/InducedMaps.lean | 2 +- Mathlib/Topology/Constructions.lean | 10 ++++++++++ Mathlib/Topology/Separation.lean | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean index fdb14960f8315..b4d70283c0093 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean @@ -142,7 +142,7 @@ many of the paths do not have defeq starting/ending points, so we end up needing /-- Interpret a homotopy `H : C(I × X, Y)` as a map `C(ULift I × X, Y)` -/ def uliftMap : C(TopCat.of (ULift.{u} I × X), Y) := ⟨fun x => H (x.1.down, x.2), - H.continuous.comp ((continuous_induced_dom.comp continuous_fst).prod_mk continuous_snd)⟩ + H.continuous.comp ((continuous_uLift_down.comp continuous_fst).prod_mk continuous_snd)⟩ #align continuous_map.homotopy.ulift_map ContinuousMap.Homotopy.uliftMap -- This lemma has always been bad, but the linter only noticed after lean4#2644. diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index 5ce81050e5fba..e681390b4ad7e 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -1650,6 +1650,16 @@ end Sigma section ULift +theorem ULift.isOpen_iff [TopologicalSpace α] {s : Set (ULift.{v} α)} : + IsOpen s ↔ IsOpen (ULift.up ⁻¹' s) := by + unfold ULift.topologicalSpace + erw [← Equiv.ulift.coinduced_symm] + rfl + +theorem ULift.isClosed_iff [TopologicalSpace α] {s : Set (ULift.{v} α)} : + IsClosed s ↔ IsClosed (ULift.up ⁻¹' s) := by + rw [← isOpen_compl_iff, ← isOpen_compl_iff, isOpen_iff, preimage_compl] + @[continuity] theorem continuous_uLift_down [TopologicalSpace α] : Continuous (ULift.down : ULift.{v, u} α → α) := continuous_induced_dom diff --git a/Mathlib/Topology/Separation.lean b/Mathlib/Topology/Separation.lean index bccc397e77bd7..d828fd9ce59af 100644 --- a/Mathlib/Topology/Separation.lean +++ b/Mathlib/Topology/Separation.lean @@ -362,6 +362,9 @@ instance Pi.instT0Space {ι : Type*} {X : ι → Type*} [∀ i, TopologicalSpace ⟨fun _ _ h => funext fun i => (h.map (continuous_apply i)).eq⟩ #align pi.t0_space Pi.instT0Space +instance ULift.instT0Space [T0Space X] : T0Space (ULift X) := + embedding_uLift_down.t0Space + theorem T0Space.of_cover (h : ∀ x y, Inseparable x y → ∃ s : Set X, x ∈ s ∧ y ∈ s ∧ T0Space s) : T0Space X := by refine' ⟨fun x y hxy => _⟩ @@ -627,6 +630,9 @@ instance {ι : Type*} {X : ι → Type*} [∀ i, TopologicalSpace (X i)] [∀ i, T1Space (∀ i, X i) := ⟨fun f => univ_pi_singleton f ▸ isClosed_set_pi fun _ _ => isClosed_singleton⟩ +instance ULift.instT1Space [T1Space X] : T1Space (ULift X) := + embedding_uLift_down.t1Space + -- see Note [lower instance priority] instance (priority := 100) T1Space.t0Space [T1Space X] : T0Space X := ⟨fun _ _ h => h.specializes.eq⟩ @@ -1234,6 +1240,9 @@ theorem Embedding.t2Space [TopologicalSpace Y] [T2Space Y] {f : X → Y} (hf : E .of_injective_continuous hf.inj hf.continuous #align embedding.t2_space Embedding.t2Space +instance ULift.instT2Space [T2Space X] : T2Space (ULift X) := + embedding_uLift_down.t2Space + instance [T2Space X] [TopologicalSpace Y] [T2Space Y] : T2Space (X ⊕ Y) := by constructor @@ -1837,6 +1846,9 @@ instance Subtype.t3Space [T3Space X] {p : X → Prop} : T3Space (Subtype p) := embedding_subtype_val.t3Space #align subtype.t3_space Subtype.t3Space +instance ULift.instT3Space [T3Space X] : T3Space (ULift X) := + embedding_uLift_down.t3Space + instance [TopologicalSpace Y] [T3Space X] [T3Space Y] : T3Space (X × Y) := ⟨⟩ instance {ι : Type*} {X : ι → Type*} [∀ i, TopologicalSpace (X i)] [∀ i, T3Space (X i)] : @@ -1974,6 +1986,9 @@ protected theorem ClosedEmbedding.t4Space [TopologicalSpace Y] [T4Space Y] {f : toNormalSpace := hf.normalSpace #align closed_embedding.normal_space ClosedEmbedding.t4Space +instance ULift.instT4Space [T4Space X] : T4Space (ULift X) := + ULift.closedEmbedding_down.t4Space + namespace SeparationQuotient /-- The `SeparationQuotient` of a normal space is a normal space. -/ @@ -2020,6 +2035,9 @@ theorem Embedding.t5Space [TopologicalSpace Y] [T5Space Y] {e : X → Y} (he : E instance [T5Space X] {p : X → Prop} : T5Space { x // p x } := embedding_subtype_val.t5Space +instance ULift.instT5Space [T5Space X] : T5Space (ULift X) := + embedding_uLift_down.t5Space + -- see Note [lower instance priority] /-- A `T₅` space is a `T₄` space. -/ instance (priority := 100) T5Space.toT4Space [T5Space X] : T4Space X where From d84bf68500589fbbfb16dced55b78a5c297b6c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sun, 17 Dec 2023 15:16:29 +0000 Subject: [PATCH 023/353] =?UTF-8?q?feat:=20`x=20^=20n=20/=20n=20!=20?= =?UTF-8?q?=E2=89=A4=20exp=20x`=20(#9099)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also make private/delete the intermediate lemmas of the form `x + 1 ≤ Real.exp x` so that people use the more general final results instead. --- .../Convex/SpecificFunctions/Basic.lean | 4 +- .../Analysis/SpecialFunctions/Log/Basic.lean | 2 +- Mathlib/Combinatorics/Additive/Behrend.lean | 3 +- Mathlib/Data/Complex/Exponential.lean | 71 ++++++++++--------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean index f78ba29edff39..a3b4003a04041 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean @@ -52,14 +52,14 @@ theorem strictConvexOn_exp : StrictConvexOn ℝ univ exp := by calc exp y - exp x = exp y - exp y * exp (x - y) := by rw [← exp_add]; ring_nf _ = exp y * (1 - exp (x - y)) := by ring - _ < exp y * -(x - y) := by gcongr; linarith [add_one_lt_exp_of_nonzero h2.ne] + _ < exp y * -(x - y) := by gcongr; linarith [add_one_lt_exp h2.ne] _ = exp y * (y - x) := by ring · have h1 : 0 < z - y := by linarith rw [lt_div_iff h1] calc exp y * (z - y) < exp y * (exp (z - y) - 1) := by gcongr _ * ?_ - linarith [add_one_lt_exp_of_nonzero h1.ne'] + linarith [add_one_lt_exp h1.ne'] _ = exp (z - y) * exp y - exp y := by ring _ ≤ exp z - exp y := by rw [← exp_add]; ring_nf; rfl #align strict_convex_on_exp strictConvexOn_exp diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean index 487700b077ee6..9fe491de8e2d9 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean @@ -265,7 +265,7 @@ theorem log_lt_sub_one_of_pos (hx1 : 0 < x) (hx2 : x ≠ 1) : log x < x - 1 := b have h : log x ≠ 0 · rwa [← log_one, log_injOn_pos.ne_iff hx1] exact mem_Ioi.mpr zero_lt_one - linarith [add_one_lt_exp_of_nonzero h, exp_log hx1] + linarith [add_one_lt_exp h, exp_log hx1] #align real.log_lt_sub_one_of_pos Real.log_lt_sub_one_of_pos theorem eq_one_of_pos_of_log_eq_zero {x : ℝ} (h₁ : 0 < x) (h₂ : log x = 0) : x = 1 := diff --git a/Mathlib/Combinatorics/Additive/Behrend.lean b/Mathlib/Combinatorics/Additive/Behrend.lean index 0b20c91e57703..2e79d0e562e29 100644 --- a/Mathlib/Combinatorics/Additive/Behrend.lean +++ b/Mathlib/Combinatorics/Additive/Behrend.lean @@ -340,8 +340,7 @@ theorem exp_neg_two_mul_le {x : ℝ} (hx : 0 < x) : exp (-2 * x) < exp (2 - ⌈x refine' le_trans _ (div_le_div_of_le_of_nonneg (exp_le_exp.2 h₂) <| add_nonneg hx.le zero_le_one) rw [le_div_iff (add_pos hx zero_lt_one), ← le_div_iff' (exp_pos _), ← exp_sub, neg_mul, sub_neg_eq_add, two_mul, sub_add_add_cancel, add_comm _ x] - refine' le_trans _ (add_one_le_exp_of_nonneg <| add_nonneg hx.le zero_le_one) - exact le_add_of_nonneg_right zero_le_one + exact le_trans (le_add_of_nonneg_right zero_le_one) (add_one_le_exp _) #align behrend.exp_neg_two_mul_le Behrend.exp_neg_two_mul_le theorem div_lt_floor {x : ℝ} (hx : 2 / (1 - 2 / exp 1) ≤ x) : x / exp 1 < (⌊x / 2⌋₊ : ℝ) := by diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index eb88a2a8a4df1..bfa38712bcf97 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -1475,6 +1475,12 @@ theorem sum_le_exp_of_nonneg {x : ℝ} (hx : 0 ≤ x) (n : ℕ) : ∑ i in range _ = exp x := by rw [exp, Complex.exp, ← cauSeqRe, lim_re] #align real.sum_le_exp_of_nonneg Real.sum_le_exp_of_nonneg +lemma pow_div_factorial_le_exp (hx : 0 ≤ x) (n : ℕ) : x ^ n / n ! ≤ exp x := + calc + x ^ n / n ! ≤ ∑ k in range (n + 1), x ^ k / k ! := + single_le_sum (f := fun k ↦ x ^ k / k !) (fun k _ ↦ by positivity) (self_mem_range_succ n) + _ ≤ exp x := sum_le_exp_of_nonneg hx _ + theorem quadratic_le_exp_of_nonneg {x : ℝ} (hx : 0 ≤ x) : 1 + x + x ^ 2 / 2 ≤ exp x := calc 1 + x + x ^ 2 / 2 = ∑ i in range 3, x ^ i / i ! := by @@ -1485,17 +1491,13 @@ theorem quadratic_le_exp_of_nonneg {x : ℝ} (hx : 0 ≤ x) : 1 + x + x ^ 2 / 2 _ ≤ exp x := sum_le_exp_of_nonneg hx 3 #align real.quadratic_le_exp_of_nonneg Real.quadratic_le_exp_of_nonneg -theorem add_one_lt_exp_of_pos {x : ℝ} (hx : 0 < x) : x + 1 < exp x := +private theorem add_one_lt_exp_of_pos {x : ℝ} (hx : 0 < x) : x + 1 < exp x := (by nlinarith : x + 1 < 1 + x + x ^ 2 / 2).trans_le (quadratic_le_exp_of_nonneg hx.le) -#align real.add_one_lt_exp_of_pos Real.add_one_lt_exp_of_pos -/-- This is an intermediate result that is later replaced by `Real.add_one_le_exp`; use that lemma -instead. -/ -theorem add_one_le_exp_of_nonneg {x : ℝ} (hx : 0 ≤ x) : x + 1 ≤ exp x := by +private theorem add_one_le_exp_of_nonneg {x : ℝ} (hx : 0 ≤ x) : x + 1 ≤ exp x := by rcases eq_or_lt_of_le hx with (rfl | h) · simp exact (add_one_lt_exp_of_pos h).le -#align real.add_one_le_exp_of_nonneg Real.add_one_le_exp_of_nonneg theorem one_le_exp {x : ℝ} (hx : 0 ≤ x) : 1 ≤ exp x := by linarith [add_one_le_exp_of_nonneg hx] #align real.one_le_exp Real.one_le_exp @@ -1506,11 +1508,16 @@ theorem exp_pos (x : ℝ) : 0 < exp x := exact inv_pos.2 (lt_of_lt_of_le zero_lt_one (one_le_exp (neg_nonneg.2 h))) #align real.exp_pos Real.exp_pos +lemma exp_nonneg (x : ℝ) : 0 ≤ exp x := x.exp_pos.le + @[simp] theorem abs_exp (x : ℝ) : |exp x| = exp x := abs_of_pos (exp_pos _) #align real.abs_exp Real.abs_exp +lemma exp_abs_le (x : ℝ) : exp |x| ≤ exp x + exp (-x) := by + cases le_total x 0 <;> simp [abs_of_nonpos, _root_.abs_of_nonneg, exp_nonneg, *] + @[mono] theorem exp_strictMono : StrictMono exp := fun x y h => by rw [← sub_add_cancel y x, Real.exp_add] @@ -1970,48 +1977,42 @@ theorem exp_bound_div_one_sub_of_interval {x : ℝ} (h1 : 0 ≤ x) (h2 : x < 1) · exact (exp_bound_div_one_sub_of_interval' h1 h2).le #align real.exp_bound_div_one_sub_of_interval Real.exp_bound_div_one_sub_of_interval -theorem one_sub_lt_exp_minus_of_pos {y : ℝ} (h : 0 < y) : 1 - y < Real.exp (-y) := by - cases' le_or_lt 1 y with h' h' - · linarith [(-y).exp_pos] - rw [exp_neg, lt_inv _ y.exp_pos, inv_eq_one_div] - · exact exp_bound_div_one_sub_of_interval' h h' - · linarith -#align real.one_sub_le_exp_minus_of_pos Real.one_sub_lt_exp_minus_of_pos +theorem add_one_lt_exp {x : ℝ} (hx : x ≠ 0) : x + 1 < Real.exp x := by + obtain hx | hx := hx.symm.lt_or_lt + · exact add_one_lt_exp_of_pos hx + obtain h' | h' := le_or_lt 1 (-x) + · linarith [x.exp_pos] + have hx' : 0 < x + 1 := by linarith + simpa [add_comm, exp_neg, inv_lt_inv (exp_pos _) hx'] + using exp_bound_div_one_sub_of_interval' (neg_pos.2 hx) h' +#align real.add_one_lt_exp_of_nonzero Real.add_one_lt_exp +#align real.add_one_lt_exp_of_pos Real.add_one_lt_exp -theorem one_sub_le_exp_minus_of_nonneg {y : ℝ} (h : 0 ≤ y) : 1 - y ≤ Real.exp (-y) := by - rcases eq_or_lt_of_le h with (rfl | h) +theorem add_one_le_exp (x : ℝ) : x + 1 ≤ Real.exp x := by + obtain rfl | hx := eq_or_ne x 0 · simp - · exact (one_sub_lt_exp_minus_of_pos h).le -#align real.one_sub_le_exp_minus_of_nonneg Real.one_sub_le_exp_minus_of_nonneg - -theorem add_one_lt_exp_of_neg {x : ℝ} (h : x < 0) : x + 1 < Real.exp x := by - have h1 : 0 < -x := by linarith - simpa [add_comm] using one_sub_lt_exp_minus_of_pos h1 -#align real.add_one_lt_exp_of_neg Real.add_one_lt_exp_of_neg + · exact (add_one_lt_exp hx).le +#align real.add_one_le_exp Real.add_one_le_exp +#align real.add_one_le_exp_of_nonneg Real.add_one_le_exp -theorem add_one_lt_exp_of_nonzero {x : ℝ} (hx : x ≠ 0) : x + 1 < Real.exp x := by - cases' lt_or_gt_of_ne hx with h h - · exact add_one_lt_exp_of_neg h - exact add_one_lt_exp_of_pos h -#align real.add_one_lt_exp_of_nonzero Real.add_one_lt_exp_of_nonzero +lemma one_sub_lt_exp_neg {x : ℝ} (hx : x ≠ 0) : 1 - x < exp (-x) := + (sub_eq_neg_add _ _).trans_lt $ add_one_lt_exp $ neg_ne_zero.2 hx -theorem add_one_le_exp (x : ℝ) : x + 1 ≤ Real.exp x := by - cases' le_or_lt 0 x with h h - · exact Real.add_one_le_exp_of_nonneg h - exact (add_one_lt_exp_of_neg h).le -#align real.add_one_le_exp Real.add_one_le_exp +lemma one_sub_le_exp_neg (x : ℝ) : 1 - x ≤ exp (-x) := + (sub_eq_neg_add _ _).trans_le $ add_one_le_exp _ +#align real.one_sub_le_exp_minus_of_pos Real.one_sub_le_exp_neg +#align real.one_sub_le_exp_minus_of_nonneg Real.one_sub_le_exp_neg theorem one_sub_div_pow_le_exp_neg {n : ℕ} {t : ℝ} (ht' : t ≤ n) : (1 - t / n) ^ n ≤ exp (-t) := by rcases eq_or_ne n 0 with (rfl | hn) · simp rwa [Nat.cast_zero] at ht' - convert pow_le_pow_of_le_left ?_ (add_one_le_exp (-(t / n))) n using 2 - · abel + convert pow_le_pow_of_le_left ?_ (one_sub_le_exp_neg (t / n)) n using 2 · rw [← Real.exp_nat_mul] congr 1 field_simp ring_nf - · rwa [add_comm, ← sub_eq_add_neg, sub_nonneg, div_le_one] + · rwa [sub_nonneg, div_le_one] positivity #align real.one_sub_div_pow_le_exp_neg Real.one_sub_div_pow_le_exp_neg From f4794c25457269bc5b44ab0c8a8412525b466f91 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Sun, 17 Dec 2023 15:16:30 +0000 Subject: [PATCH 024/353] chore(Ideal/Operations): remove extraneous nonempty conditions (#9115) Also generalizes `Ideal.subset_union` to `Subgroup`. Co-authored-by: Junyan Xu --- Mathlib/GroupTheory/Subgroup/Basic.lean | 16 +++-- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 4 +- Mathlib/RingTheory/Ideal/Operations.lean | 69 +++++--------------- 3 files changed, 30 insertions(+), 59 deletions(-) diff --git a/Mathlib/GroupTheory/Subgroup/Basic.lean b/Mathlib/GroupTheory/Subgroup/Basic.lean index 56dec72109afb..b07dd12d3c50c 100644 --- a/Mathlib/GroupTheory/Subgroup/Basic.lean +++ b/Mathlib/GroupTheory/Subgroup/Basic.lean @@ -177,22 +177,30 @@ theorem exists_inv_mem_iff_exists_mem {P : G → Prop} : @[to_additive] theorem mul_mem_cancel_right {x y : G} (h : x ∈ H) : y * x ∈ H ↔ y ∈ H := - -- Porting note: whut? why do we need this? - haveI : SubmonoidClass S G := SubgroupClass.toSubmonoidClass ⟨fun hba => by simpa using mul_mem hba (inv_mem h), fun hb => mul_mem hb h⟩ #align mul_mem_cancel_right mul_mem_cancel_right #align add_mem_cancel_right add_mem_cancel_right @[to_additive] theorem mul_mem_cancel_left {x y : G} (h : x ∈ H) : x * y ∈ H ↔ y ∈ H := - -- Porting note: whut? why do we need this? - have : SubmonoidClass S G := SubgroupClass.toSubmonoidClass ⟨fun hab => by simpa using mul_mem (inv_mem h) hab, mul_mem h⟩ #align mul_mem_cancel_left mul_mem_cancel_left #align add_mem_cancel_left add_mem_cancel_left namespace SubgroupClass +-- Here we assume H, K, and L are subgroups, but in fact any one of them +-- could be allowed to be a subsemigroup. +-- Counterexample where K and L are submonoids: H = ℤ, K = ℕ, L = -ℕ +-- Counterexample where H and K are submonoids: H = {n | n = 0 ∨ 3 ≤ n}, K = 3ℕ + 4ℕ, L = 5ℤ +@[to_additive] +theorem subset_union {H K L : S} : (H : Set G) ⊆ K ∪ L ↔ H ≤ K ∨ H ≤ L := by + refine ⟨fun h ↦ ?_, fun h x xH ↦ h.imp (· xH) (· xH)⟩ + rw [or_iff_not_imp_left, SetLike.not_le_iff_exists] + exact fun ⟨x, xH, xK⟩ y yH ↦ (h <| mul_mem xH yH).elim + ((h yH).resolve_left fun yK ↦ xK <| (mul_mem_cancel_right yK).mp ·) + (mul_mem_cancel_left <| (h xH).resolve_left xK).mp + /-- A subgroup of a group inherits an inverse. -/ @[to_additive "An additive subgroup of an `AddGroup` inherits an inverse."] instance inv {G : Type u_1} {S : Type u_2} [DivInvMonoid G] [SetLike S G] diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 630b3c8ea701f..3a57a5a969bc0 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -369,9 +369,7 @@ theorem exists_multiset_prod_cons_le_and_prod_not_le [IsDedekindDomain A] (hNF : wellFounded_lt.has_min {Z | (Z.map PrimeSpectrum.asIdeal).prod ≤ I ∧ (Z.map PrimeSpectrum.asIdeal).prod ≠ ⊥} ⟨Z₀, hZ₀.1, hZ₀.2⟩ - have hZM : Multiset.prod (Z.map PrimeSpectrum.asIdeal) ≤ M := le_trans hZI hIM - have hZ0 : Z ≠ 0 := by rintro rfl; simp [hM.ne_top] at hZM - obtain ⟨_, hPZ', hPM⟩ := (hM.isPrime.multiset_prod_le (mt Multiset.map_eq_zero.mp hZ0)).mp hZM + obtain ⟨_, hPZ', hPM⟩ := hM.isPrime.multiset_prod_le.mp (hZI.trans hIM) -- Then in fact there is a `P ∈ Z` with `P ≤ M`. obtain ⟨P, hPZ, rfl⟩ := Multiset.mem_map.mp hPZ' classical diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index b48bbab50c5b6..04ec2ffbb4116 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -1089,71 +1089,39 @@ theorem radical_pow (n : ℕ) (H : n > 0) : radical (I ^ n) = radical I := H #align ideal.radical_pow Ideal.radical_pow -theorem IsPrime.mul_le {I J P : Ideal R} (hp : IsPrime P) : I * J ≤ P ↔ I ≤ P ∨ J ≤ P := - ⟨fun h => - or_iff_not_imp_left.2 fun hip _ hj => - let ⟨_, hi, hip⟩ := Set.not_subset.1 hip - (hp.mem_or_mem <| h <| mul_mem_mul hi hj).resolve_left hip, - fun h => - Or.casesOn h (le_trans <| le_trans mul_le_inf inf_le_left) - (le_trans <| le_trans mul_le_inf inf_le_right)⟩ +theorem IsPrime.mul_le {I J P : Ideal R} (hp : IsPrime P) : I * J ≤ P ↔ I ≤ P ∨ J ≤ P := by + rw [or_comm, Ideal.mul_le] + simp_rw [hp.mul_mem_iff_mem_or_mem, SetLike.le_def, ← forall_or_left, or_comm, forall_or_left] #align ideal.is_prime.mul_le Ideal.IsPrime.mul_le theorem IsPrime.inf_le {I J P : Ideal R} (hp : IsPrime P) : I ⊓ J ≤ P ↔ I ≤ P ∨ J ≤ P := - ⟨fun h => hp.mul_le.1 <| le_trans mul_le_inf h, fun h => - Or.casesOn h (le_trans inf_le_left) (le_trans inf_le_right)⟩ + ⟨fun h ↦ hp.mul_le.1 <| mul_le_inf.trans h, fun h ↦ h.elim inf_le_left.trans inf_le_right.trans⟩ #align ideal.is_prime.inf_le Ideal.IsPrime.inf_le -theorem IsPrime.multiset_prod_le {s : Multiset (Ideal R)} {P : Ideal R} (hp : IsPrime P) - (hne : s ≠ 0) : s.prod ≤ P ↔ ∃ I ∈ s, I ≤ P := by - suffices s.prod ≤ P → ∃ I ∈ s, I ≤ P from - ⟨this, fun ⟨i, his, hip⟩ => le_trans multiset_prod_le_inf <| le_trans (Multiset.inf_le his) hip⟩ - classical - obtain ⟨b, hb⟩ : ∃ b, b ∈ s := Multiset.exists_mem_of_ne_zero hne - obtain ⟨t, rfl⟩ : ∃ t, s = b ::ₘ t - exact ⟨s.erase b, (Multiset.cons_erase hb).symm⟩ - refine' t.induction_on _ _ - · simp only [exists_prop, Multiset.cons_zero, Multiset.prod_singleton, Multiset.mem_singleton, - exists_eq_left, imp_self] - intro a s ih h - rw [Multiset.cons_swap, Multiset.prod_cons, hp.mul_le] at h - rw [Multiset.cons_swap] - cases' h with h h - · exact ⟨a, Multiset.mem_cons_self a _, h⟩ - obtain ⟨I, hI, ih⟩ : ∃ I ∈ b ::ₘ s, I ≤ P := ih h - exact ⟨I, Multiset.mem_cons_of_mem hI, ih⟩ +theorem IsPrime.multiset_prod_le {s : Multiset (Ideal R)} {P : Ideal R} (hp : IsPrime P) : + s.prod ≤ P ↔ ∃ I ∈ s, I ≤ P := + s.induction_on (by simp [hp.ne_top]) fun I s ih ↦ by simp [hp.mul_le, ih] #align ideal.is_prime.multiset_prod_le Ideal.IsPrime.multiset_prod_le theorem IsPrime.multiset_prod_map_le {s : Multiset ι} (f : ι → Ideal R) {P : Ideal R} - (hp : IsPrime P) (hne : s ≠ 0) : (s.map f).prod ≤ P ↔ ∃ i ∈ s, f i ≤ P := by - rw [hp.multiset_prod_le (mt Multiset.map_eq_zero.mp hne)] - simp_rw [Multiset.mem_map, exists_exists_and_eq_and] + (hp : IsPrime P) : (s.map f).prod ≤ P ↔ ∃ i ∈ s, f i ≤ P := by + simp_rw [hp.multiset_prod_le, Multiset.mem_map, exists_exists_and_eq_and] #align ideal.is_prime.multiset_prod_map_le Ideal.IsPrime.multiset_prod_map_le -theorem IsPrime.prod_le {s : Finset ι} {f : ι → Ideal R} {P : Ideal R} (hp : IsPrime P) - (hne : s.Nonempty) : s.prod f ≤ P ↔ ∃ i ∈ s, f i ≤ P := - hp.multiset_prod_map_le f (mt Finset.val_eq_zero.mp hne.ne_empty) +theorem IsPrime.prod_le {s : Finset ι} {f : ι → Ideal R} {P : Ideal R} (hp : IsPrime P) : + s.prod f ≤ P ↔ ∃ i ∈ s, f i ≤ P := + hp.multiset_prod_map_le f #align ideal.is_prime.prod_le Ideal.IsPrime.prod_le -theorem IsPrime.inf_le' {s : Finset ι} {f : ι → Ideal R} {P : Ideal R} (hp : IsPrime P) - (hsne : s.Nonempty) : s.inf f ≤ P ↔ ∃ i ∈ s, f i ≤ P := - ⟨fun h => (hp.prod_le hsne).1 <| le_trans prod_le_inf h, fun ⟨_, his, hip⟩ => - le_trans (Finset.inf_le his) hip⟩ +theorem IsPrime.inf_le' {s : Finset ι} {f : ι → Ideal R} {P : Ideal R} (hp : IsPrime P) : + s.inf f ≤ P ↔ ∃ i ∈ s, f i ≤ P := + ⟨fun h ↦ hp.prod_le.1 <| prod_le_inf.trans h, fun ⟨_, his, hip⟩ ↦ (Finset.inf_le his).trans hip⟩ #align ideal.is_prime.inf_le' Ideal.IsPrime.inf_le' -- Porting note: needed to add explicit coercions (· : Set R). theorem subset_union {R : Type u} [Ring R] {I J K : Ideal R} : (I : Set R) ⊆ J ∪ K ↔ I ≤ J ∨ I ≤ K := - ⟨fun h => - or_iff_not_imp_left.2 fun hij s hsi => - let ⟨r, hri, hrj⟩ := Set.not_subset.1 hij - by_contradiction fun hsk => - Or.casesOn (h <| I.add_mem hri hsi) - (fun hj => hrj <| add_sub_cancel r s ▸ J.sub_mem hj ((h hsi).resolve_right hsk)) fun hk => - hsk <| add_sub_cancel' r s ▸ K.sub_mem hk ((h hri).resolve_left hrj), - fun h => - Or.casesOn h (fun h => Set.Subset.trans h <| Set.subset_union_left (J : Set R) K) fun h => - Set.Subset.trans h <| Set.subset_union_right (J : Set R) K ⟩ + AddSubgroupClass.subset_union #align ideal.subset_union Ideal.subset_union theorem subset_union_prime' {R : Type u} [CommRing R] {s : Finset ι} {f : ι → Ideal R} {a b : ι} @@ -1233,10 +1201,7 @@ theorem subset_union_prime' {R : Type u} [CommRing R] {s : Finset ι} {f : ι by_cases Hi : I ≤ f i · exact Or.inr (Or.inr ⟨i, Finset.mem_insert_self i t, Hi⟩) have : ¬I ⊓ f a ⊓ f b ⊓ t.inf f ≤ f i := by - rcases t.eq_empty_or_nonempty with (rfl | hsne) - · rw [Finset.inf_empty, inf_top_eq, hp.1.inf_le, hp.1.inf_le, not_or, not_or] - exact ⟨⟨Hi, Ha⟩, Hb⟩ - simp only [hp.1.inf_le, hp.1.inf_le' hsne, not_or] + simp only [hp.1.inf_le, hp.1.inf_le', not_or] exact ⟨⟨⟨Hi, Ha⟩, Hb⟩, Ht⟩ rcases Set.not_subset.1 this with ⟨r, ⟨⟨⟨hrI, hra⟩, hrb⟩, hr⟩, hri⟩ by_cases HI : (I : Set R) ⊆ f a ∪ f b ∪ ⋃ j ∈ (↑t : Set ι), f j From 4f94e7d034f6630a612dd888ea3ef79978617f2c Mon Sep 17 00:00:00 2001 From: Wrenna Robson Date: Sun, 17 Dec 2023 16:54:45 +0000 Subject: [PATCH 025/353] feat(Data/Sum/Basic): Add `LiftRel` lemmas. (#6729) Add lemmas that allow `IsLeft`/`IsRight` conclusions from `LiftRel` and allow for apply functions. This is necessary because `cases` cannot run on statements like `LiftRel r s (f t) y`. Co-authored-by: lines <34025592+linesthatinterlace@users.noreply.github.com> Co-authored-by: Wrenna Robson <34025592+linesthatinterlace@users.noreply.github.com> --- Mathlib/Data/Sum/Basic.lean | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/Mathlib/Data/Sum/Basic.lean b/Mathlib/Data/Sum/Basic.lean index 5d3ce32aa1a4b..77b16d5e073b8 100644 --- a/Mathlib/Data/Sum/Basic.lean +++ b/Mathlib/Data/Sum/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Yury G. Kudryashov -/ import Mathlib.Logic.Function.Basic +import Mathlib.Tactic.MkIffOfInductiveProp #align_import data.sum.basic from "leanprover-community/mathlib"@"bd9851ca476957ea4549eb19b40e7b5ade9428cc" @@ -188,7 +189,9 @@ theorem swap_rightInverse : Function.RightInverse (@swap α β) swap := #align sum.get_left_swap Sum.getLeft?_swap #align sum.get_right_swap Sum.getRight?_swap -section LiftRel +mk_iff_of_inductive_prop Sum.LiftRel Sum.liftRel_iff + +namespace LiftRel #align sum.lift_rel Sum.LiftRel #align sum.lift_rel_inl_inl Sum.liftRel_inl_inl @@ -201,6 +204,36 @@ section LiftRel #align sum.lift_rel.swap Sum.LiftRel.swap #align sum.lift_rel_swap_iff Sum.liftRel_swap_iff +variable {r : α → γ → Prop} {s : β → δ → Prop} {x : Sum α β} {y : Sum γ δ} + {a : α} {b : β} {c : γ} {d : δ} + +theorem isLeft_congr (h : LiftRel r s x y) : x.isLeft ↔ y.isLeft := by cases h <;> rfl +theorem isRight_congr (h : LiftRel r s x y) : x.isRight ↔ y.isRight := by cases h <;> rfl + +theorem isLeft_left (h : LiftRel r s x (inl c)) : x.isLeft := by cases h; rfl +theorem isLeft_right (h : LiftRel r s (inl a) y) : y.isLeft := by cases h; rfl +theorem isRight_left (h : LiftRel r s x (inr d)) : x.isRight := by cases h; rfl +theorem isRight_right (h : LiftRel r s (inr b) y) : y.isRight := by cases h; rfl + +theorem exists_of_isLeft_left (h₁ : LiftRel r s x y) (h₂ : x.isLeft) : + ∃ a c, r a c ∧ x = inl a ∧ y = inl c := by + rcases isLeft_iff.mp h₂ with ⟨_, rfl⟩ + simp only [liftRel_iff, false_and, and_false, exists_false, or_false] at h₁ + exact h₁ + +theorem exists_of_isLeft_right (h₁ : LiftRel r s x y) (h₂ : y.isLeft) : + ∃ a c, r a c ∧ x = inl a ∧ y = inl c := exists_of_isLeft_left h₁ ((isLeft_congr h₁).mpr h₂) + +theorem exists_of_isRight_left (h₁ : LiftRel r s x y) (h₂ : x.isRight) : + ∃ b d, s b d ∧ x = inr b ∧ y = inr d := by + rcases isRight_iff.mp h₂ with ⟨_, rfl⟩ + simp only [liftRel_iff, false_and, and_false, exists_false, false_or] at h₁ + exact h₁ + +theorem exists_of_isRight_right (h₁ : LiftRel r s x y) (h₂ : y.isRight) : + ∃ b d, s b d ∧ x = inr b ∧ y = inr d := + exists_of_isRight_left h₁ ((isRight_congr h₁).mpr h₂) + end LiftRel section Lex From bced26357ab23de86a957a79fd3d6760494d550f Mon Sep 17 00:00:00 2001 From: Lukas Miaskiwskyi Date: Sun, 17 Dec 2023 16:54:46 +0000 Subject: [PATCH 026/353] feat(RingTheory/Polynomial/Basic): add thms on degree of span and non-finiteness of polynomial ring as module (#9029) This shows with minimal requirements on `R`, that the `R`-module `R[X]` is not finite, or if `R` is a field, that equivalently `R[X]` is infinite-dimensional. On the way, some theorems are proven on how the `R`-span of a set of polynomials in `R[X]` interacts with the degree of the elements, and that the span of finitely many polynomials is always contained in some `Polynomial.degreeLE n` and some `Polynomial.degreeLT n`. --- Mathlib/RingTheory/Polynomial/Basic.lean | 66 ++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Mathlib/RingTheory/Polynomial/Basic.lean b/Mathlib/RingTheory/Polynomial/Basic.lean index 873224e280a7c..cc630abf36974 100644 --- a/Mathlib/RingTheory/Polynomial/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Basic.lean @@ -180,6 +180,72 @@ theorem eval_eq_sum_degreeLTEquiv {n : ℕ} {p : R[X]} (hp : p ∈ degreeLT R n) exact (sum_fin _ (by simp_rw [zero_mul, forall_const]) (mem_degreeLT.mp hp)).symm #align polynomial.eval_eq_sum_degree_lt_equiv Polynomial.eval_eq_sum_degreeLTEquiv +theorem degreeLT_succ_eq_degreeLE {n : ℕ} : degreeLT R (n + 1) = degreeLE R n := by + ext x + by_cases x_zero : x = 0 + · simp_rw [x_zero, Submodule.zero_mem] + · rw [mem_degreeLT, mem_degreeLE, ← natDegree_lt_iff_degree_lt (by rwa [ne_eq]), + ← natDegree_le_iff_degree_le, Nat.lt_succ] + +/-- For every polynomial `p` in the span of a set `s : Set R[X]`, there exists a polynomial of + `p' ∈ s` with higher degree. See also `Polynomial.exists_degree_le_of_mem_span_of_finite`. -/ +theorem exists_degree_le_of_mem_span {s : Set R[X]} {p : R[X]} + (hs : s.Nonempty) (hp : p ∈ Submodule.span R s) : + ∃ p' ∈ s, degree p ≤ degree p' := by + by_contra! h + by_cases hp_zero : p = 0 + · rw [hp_zero, degree_zero] at h + rcases hs with ⟨x,hx⟩ + exact not_lt_bot (h x hx) + · have : p ∈ degreeLT R (natDegree p) := by + refine (Submodule.span_le.mpr fun p' p'_mem => ?_) hp + rw [SetLike.mem_coe, mem_degreeLT, Nat.cast_withBot] + exact lt_of_lt_of_le (h p' p'_mem) degree_le_natDegree + rwa [mem_degreeLT, Nat.cast_withBot, degree_eq_natDegree hp_zero, + Nat.cast_withBot, lt_self_iff_false] at this + +/-- A stronger version of `Polynomial.exists_degree_le_of_mem_span` under the assumption that the + set `s : R[X]` is finite. There exists a polynomial `p' ∈ s` whose degree dominates the degree of + every element of `p ∈ span R s`-/ +theorem exists_degree_le_of_mem_span_of_finite {s : Set R[X]} (s_fin : s.Finite) (hs : s.Nonempty) : + ∃ p' ∈ s, ∀ (p : R[X]), p ∈ Submodule.span R s → degree p ≤ degree p' := by + rcases Set.Finite.exists_maximal_wrt degree s s_fin hs with ⟨a, has, hmax⟩ + refine ⟨a, has, fun p hp => ?_⟩ + rcases exists_degree_le_of_mem_span hs hp with ⟨p', hp'⟩ + have p'max := hmax p' hp'.left + by_cases h : degree a ≤ degree p' + · rw [← p'max h] at hp'; exact hp'.right + · exact le_trans hp'.right (not_le.mp h).le + +/-- The span of every finite set of polynomials is contained in a `degreeLE n` for some `n`. -/ +theorem span_le_degreeLE_of_finite {s : Set R[X]} (s_fin : s.Finite) : + ∃ n : ℕ, Submodule.span R s ≤ degreeLE R n := by + by_cases s_emp : s.Nonempty + · rcases exists_degree_le_of_mem_span_of_finite s_fin s_emp with ⟨p', _, hp'max⟩ + exact ⟨natDegree p', fun p hp => mem_degreeLE.mpr ((hp'max _ hp).trans degree_le_natDegree)⟩ + · rw [Set.not_nonempty_iff_eq_empty] at s_emp + rw [s_emp, Submodule.span_empty] + exact ⟨0, bot_le⟩ + +/-- The span of every finite set of polynomials is contained in a `degreeLT n` for some `n`. -/ +theorem span_of_finite_le_degreeLT {s : Set R[X]} (s_fin : s.Finite) : + ∃ n : ℕ, Submodule.span R s ≤ degreeLT R n := by + rcases span_le_degreeLE_of_finite s_fin with ⟨n, _⟩ + exact ⟨n + 1, by rwa [degreeLT_succ_eq_degreeLE]⟩ + +/-- If `R` is a nontrivial ring, the polynomials `R[X]` are not finite as an `R`-module. When `R` is +a field, this is equivalent to `R[X]` being an infinite-dimensional vector space over `R`. -/ +theorem not_finite [Nontrivial R] : ¬ Module.Finite R R[X] := by + rw [Module.finite_def, Submodule.fg_def] + push_neg + intro s hs contra + rcases span_le_degreeLE_of_finite hs with ⟨n,hn⟩ + have : ((X : R[X]) ^ (n + 1)) ∈ Polynomial.degreeLE R ↑n := by + rw [contra] at hn + exact hn Submodule.mem_top + rw [mem_degreeLE, degree_X_pow, Nat.cast_le, add_le_iff_nonpos_right, nonpos_iff_eq_zero] at this + exact one_ne_zero this + /-- The finset of nonzero coefficients of a polynomial. -/ def frange (p : R[X]) : Finset R := letI := Classical.decEq R From 9764993a84fe7bddfb4d7076ee6f2aaf07c121e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sun, 17 Dec 2023 17:55:01 +0000 Subject: [PATCH 027/353] feat: Checking `ae` on a countable type (#8945) and other simple measure lemmas From PFR and LeanCamCombi Co-authored-by: Yury G. Kudryashov --- .../MeasureTheory/Decomposition/Lebesgue.lean | 21 +++---- .../MeasureTheory/Measure/AEMeasurable.lean | 5 -- Mathlib/MeasureTheory/Measure/Dirac.lean | 12 ++-- .../MeasureTheory/Measure/MeasureSpace.lean | 61 ++++++++++++++++--- .../Measure/MeasureSpaceDef.lean | 9 ++- 5 files changed, 75 insertions(+), 33 deletions(-) diff --git a/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean b/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean index f9e1855e9d3ad..2da64473aadd6 100644 --- a/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean @@ -132,8 +132,7 @@ instance haveLebesgueDecomposition_smul_right (μ ν : Measure α) [HaveLebesgue refine ⟨⟨μ.singularPart ν, r⁻¹ • μ.rnDeriv ν⟩, ?_, ?_, ?_⟩ · change Measurable (r⁻¹ • μ.rnDeriv ν) exact hmeas.const_smul _ - · refine MutuallySingular.mono_ac hsing AbsolutelyContinuous.rfl ?_ - exact absolutelyContinuous_of_le_smul le_rfl + · exact hsing.mono_ac AbsolutelyContinuous.rfl smul_absolutelyContinuous · have : r⁻¹ • rnDeriv μ ν = ((r⁻¹ : ℝ≥0) : ℝ≥0∞) • rnDeriv μ ν := by simp [ENNReal.smul_def] rw [this, withDensity_smul _ hmeas, ENNReal.smul_def r, withDensity_smul_measure, ← smul_assoc, smul_eq_mul, ENNReal.coe_inv hr, ENNReal.inv_mul_cancel, one_smul] @@ -388,8 +387,8 @@ theorem singularPart_smul_right (μ ν : Measure α) (r : ℝ≥0) (hr : r ≠ 0 μ.singularPart (r • ν) = μ.singularPart ν := by by_cases hl : HaveLebesgueDecomposition μ ν · refine (eq_singularPart ((measurable_rnDeriv μ ν).const_smul r⁻¹) ?_ ?_).symm - · refine (mutuallySingular_singularPart μ ν).mono_ac AbsolutelyContinuous.rfl ?_ - exact absolutelyContinuous_of_le_smul le_rfl + · exact (mutuallySingular_singularPart μ ν).mono_ac AbsolutelyContinuous.rfl + smul_absolutelyContinuous · rw [ENNReal.smul_def r, withDensity_smul_measure, ← withDensity_smul] swap; · exact (measurable_rnDeriv _ _).const_smul _ convert haveLebesgueDecomposition_add μ ν @@ -546,11 +545,8 @@ See also `rnDeriv_smul_right'`, which requires sigma-finite `ν` and `μ`. -/ theorem rnDeriv_smul_right (ν μ : Measure α) [IsFiniteMeasure ν] [ν.HaveLebesgueDecomposition μ] {r : ℝ≥0} (hr : r ≠ 0) : ν.rnDeriv (r • μ) =ᵐ[μ] r⁻¹ • ν.rnDeriv μ := by - suffices ν.rnDeriv (r • μ) =ᵐ[r • μ] r⁻¹ • ν.rnDeriv μ by - suffices hμ : μ ≪ r • μ by exact hμ.ae_le this - refine absolutelyContinuous_of_le_smul (c := r⁻¹) ?_ - rw [← ENNReal.coe_inv hr, ← ENNReal.smul_def, ← smul_assoc, smul_eq_mul, - inv_mul_cancel hr, one_smul] + refine (absolutelyContinuous_smul $ ENNReal.coe_ne_zero.2 hr).ae_le + (?_ : ν.rnDeriv (r • μ) =ᵐ[r • μ] r⁻¹ • ν.rnDeriv μ) rw [← withDensity_eq_iff] rotate_left · exact (measurable_rnDeriv _ _).aemeasurable @@ -1019,11 +1015,8 @@ See also `rnDeriv_smul_right`, which has no hypothesis on `μ` but requires fini theorem rnDeriv_smul_right' (ν μ : Measure α) [SigmaFinite ν] [SigmaFinite μ] {r : ℝ≥0} (hr : r ≠ 0) : ν.rnDeriv (r • μ) =ᵐ[μ] r⁻¹ • ν.rnDeriv μ := by - suffices ν.rnDeriv (r • μ) =ᵐ[r • μ] r⁻¹ • ν.rnDeriv μ by - suffices hμ : μ ≪ r • μ by exact hμ.ae_le this - refine absolutelyContinuous_of_le_smul (c := r⁻¹) ?_ - rw [← ENNReal.coe_inv hr, ← ENNReal.smul_def, ← smul_assoc, smul_eq_mul, - inv_mul_cancel hr, one_smul] + refine (absolutelyContinuous_smul $ ENNReal.coe_ne_zero.2 hr).ae_le + (?_ : ν.rnDeriv (r • μ) =ᵐ[r • μ] r⁻¹ • ν.rnDeriv μ) rw [← withDensity_eq_iff_of_sigmaFinite] · simp_rw [ENNReal.smul_def] rw [withDensity_smul _ (measurable_rnDeriv _ _)] diff --git a/Mathlib/MeasureTheory/Measure/AEMeasurable.lean b/Mathlib/MeasureTheory/Measure/AEMeasurable.lean index 8058435dc2ced..0cebd49896375 100644 --- a/Mathlib/MeasureTheory/Measure/AEMeasurable.lean +++ b/Mathlib/MeasureTheory/Measure/AEMeasurable.lean @@ -51,11 +51,6 @@ lemma aemeasurable_of_map_neZero {mβ : MeasurableSpace β} {μ : Measure α} namespace AEMeasurable -protected theorem nullMeasurable (h : AEMeasurable f μ) : NullMeasurable f μ := - let ⟨_g, hgm, hg⟩ := h - hgm.nullMeasurable.congr hg.symm -#align ae_measurable.null_measurable AEMeasurable.nullMeasurable - lemma mono_ac (hf : AEMeasurable f ν) (hμν : μ ≪ ν) : AEMeasurable f μ := ⟨hf.mk f, hf.measurable_mk, hμν.ae_le hf.ae_eq_mk⟩ diff --git a/Mathlib/MeasureTheory/Measure/Dirac.lean b/Mathlib/MeasureTheory/Measure/Dirac.lean index cecc9e24da629..ffead1aa256a9 100644 --- a/Mathlib/MeasureTheory/Measure/Dirac.lean +++ b/Mathlib/MeasureTheory/Measure/Dirac.lean @@ -13,14 +13,12 @@ In this file we define the Dirac measure `MeasureTheory.Measure.dirac a` and prove some basic facts about it. -/ -set_option autoImplicit true - open Function Set open scoped ENNReal Classical noncomputable section -variable [MeasurableSpace α] [MeasurableSpace β] {s : Set α} +variable {α β δ : Type*} [MeasurableSpace α] [MeasurableSpace β] {s : Set α} {a : α} namespace MeasureTheory @@ -140,11 +138,15 @@ theorem ae_eq_dirac [MeasurableSingletonClass α] {a : α} (f : α → δ) : f =ᵐ[dirac a] const α (f a) := by simp [Filter.EventuallyEq] #align measure_theory.ae_eq_dirac MeasureTheory.ae_eq_dirac -instance Measure.dirac.isProbabilityMeasure [MeasurableSpace α] {x : α} : - IsProbabilityMeasure (dirac x) := +instance Measure.dirac.isProbabilityMeasure {x : α} : IsProbabilityMeasure (dirac x) := ⟨dirac_apply_of_mem <| mem_univ x⟩ #align measure_theory.measure.dirac.is_probability_measure MeasureTheory.Measure.dirac.isProbabilityMeasure +/-! Extra instances to short-circuit type class resolution -/ + +instance Measure.dirac.instIsFiniteMeasure {a : α} : IsFiniteMeasure (dirac a) := inferInstance +instance Measure.dirac.instSigmaFinite {a : α} : SigmaFinite (dirac a) := inferInstance + theorem restrict_dirac' (hs : MeasurableSet s) [Decidable (a ∈ s)] : (Measure.dirac a).restrict s = if a ∈ s then Measure.dirac a else 0 := by split_ifs with has diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index c7f1103d074b8..44c3e38c25fa5 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -211,6 +211,10 @@ theorem tsum_measure_preimage_singleton {s : Set β} (hs : s.Countable) {f : α rw [← Set.biUnion_preimage_singleton, measure_biUnion hs (pairwiseDisjoint_fiber f s) hf] #align measure_theory.tsum_measure_preimage_singleton MeasureTheory.tsum_measure_preimage_singleton +lemma measure_preimage_eq_zero_iff_of_countable {s : Set β} {f : α → β} (hs : s.Countable) : + μ (f ⁻¹' s) = 0 ↔ ∀ x ∈ s, μ (f ⁻¹' {x}) = 0 := by + rw [← biUnion_preimage_singleton, measure_biUnion_null_iff hs] + /-- If `s` is a `Finset`, then the measure of its preimage can be found as the sum of measures of the fibers `f ⁻¹' {y}`. -/ theorem sum_measure_preimage_singleton (s : Finset β) {f : α → β} @@ -287,11 +291,20 @@ theorem measure_eq_measure_larger_of_between_null_diff {s₁ s₂ s₃ : Set α} (measure_eq_measure_of_between_null_diff h12 h23 h_nulldiff).2 #align measure_theory.measure_eq_measure_larger_of_between_null_diff MeasureTheory.measure_eq_measure_larger_of_between_null_diff -theorem measure_compl (h₁ : MeasurableSet s) (h_fin : μ s ≠ ∞) : μ sᶜ = μ univ - μ s := by - rw [compl_eq_univ_diff] - exact measure_diff (subset_univ s) h₁ h_fin +lemma measure_compl₀ (h : NullMeasurableSet s μ) (hs : μ s ≠ ∞) : + μ sᶜ = μ Set.univ - μ s := by + rw [← measure_add_measure_compl₀ h, ENNReal.add_sub_cancel_left hs] + +theorem measure_compl (h₁ : MeasurableSet s) (h_fin : μ s ≠ ∞) : μ sᶜ = μ univ - μ s := + measure_compl₀ h₁.nullMeasurableSet h_fin #align measure_theory.measure_compl MeasureTheory.measure_compl +lemma measure_inter_conull' (ht : μ (s \ t) = 0) : μ (s ∩ t) = μ s := by + rw [← diff_compl, measure_diff_null']; rwa [← diff_eq] + +lemma measure_inter_conull (ht : μ tᶜ = 0) : μ (s ∩ t) = μ s := by + rw [← diff_compl, measure_diff_null ht] + @[simp] theorem union_ae_eq_left_iff_ae_subset : (s ∪ t : Set α) =ᵐ[μ] s ↔ t ≤ᵐ[μ] s := by rw [ae_le_set] @@ -852,6 +865,10 @@ instance instIsCentralScalar [SMul Rᵐᵒᵖ ℝ≥0∞] [IsCentralScalar R ℝ end SMul +instance instNoZeroSMulDivisors [Zero R] [SMulWithZero R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] + [NoZeroSMulDivisors R ℝ≥0∞] : NoZeroSMulDivisors R (Measure α) where + eq_zero_or_eq_zero_of_smul_eq_zero h := by simpa [Ne.def, @ext_iff', forall_or_left] using h + instance instMulAction [Monoid R] [MulAction R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] [MeasurableSpace α] : MulAction R (Measure α) := Injective.mulAction _ toOuterMeasure_injective smul_toOuterMeasure @@ -1219,6 +1236,8 @@ protected theorem map_smul_nnreal (c : ℝ≥0) (μ : Measure α) (f : α → β μ.map_smul (c : ℝ≥0∞) f #align measure_theory.measure.map_smul_nnreal MeasureTheory.Measure.map_smul_nnreal +variable {f : α → β} + lemma map_apply₀ {f : α → β} (hf : AEMeasurable f μ) {s : Set β} (hs : NullMeasurableSet s (map f μ)) : μ.map f s = μ (f ⁻¹' s) := by rw [map, dif_pos hf, mapₗ, dif_pos hf.measurable_mk] at hs ⊢ @@ -1228,24 +1247,33 @@ lemma map_apply₀ {f : α → β} (hf : AEMeasurable f μ) {s : Set β} /-- We can evaluate the pushforward on measurable sets. For non-measurable sets, see `MeasureTheory.Measure.le_map_apply` and `MeasurableEquiv.map_apply`. -/ @[simp] -theorem map_apply_of_aemeasurable {f : α → β} (hf : AEMeasurable f μ) {s : Set β} - (hs : MeasurableSet s) : μ.map f s = μ (f ⁻¹' s) := - map_apply₀ hf hs.nullMeasurableSet +theorem map_apply_of_aemeasurable (hf : AEMeasurable f μ) {s : Set β} (hs : MeasurableSet s) : + μ.map f s = μ (f ⁻¹' s) := map_apply₀ hf hs.nullMeasurableSet #align measure_theory.measure.map_apply_of_ae_measurable MeasureTheory.Measure.map_apply_of_aemeasurable @[simp] -theorem map_apply {f : α → β} (hf : Measurable f) {s : Set β} (hs : MeasurableSet s) : +theorem map_apply (hf : Measurable f) {s : Set β} (hs : MeasurableSet s) : μ.map f s = μ (f ⁻¹' s) := map_apply_of_aemeasurable hf.aemeasurable hs #align measure_theory.measure.map_apply MeasureTheory.Measure.map_apply -theorem map_toOuterMeasure {f : α → β} (hf : AEMeasurable f μ) : +theorem map_toOuterMeasure (hf : AEMeasurable f μ) : (μ.map f).toOuterMeasure = (OuterMeasure.map f μ.toOuterMeasure).trim := by rw [← trimmed, OuterMeasure.trim_eq_trim_iff] intro s hs rw [map_apply_of_aemeasurable hf hs, OuterMeasure.map_apply] #align measure_theory.measure.map_to_outer_measure MeasureTheory.Measure.map_toOuterMeasure +@[simp] lemma map_eq_zero_iff (hf : AEMeasurable f μ) : μ.map f = 0 ↔ μ = 0 := by + simp_rw [← measure_univ_eq_zero, map_apply_of_aemeasurable hf .univ, preimage_univ] + +@[simp] lemma mapₗ_eq_zero_iff (hf : Measurable f) : Measure.mapₗ f μ = 0 ↔ μ = 0 := by + rw [mapₗ_apply_of_measurable hf, map_eq_zero_iff hf.aemeasurable] + +lemma map_ne_zero_iff (hf : AEMeasurable f μ) : μ.map f ≠ 0 ↔ μ ≠ 0 := (map_eq_zero_iff hf).not +lemma mapₗ_ne_zero_iff (hf : Measurable f) : Measure.mapₗ f μ ≠ 0 ↔ μ ≠ 0 := + (mapₗ_eq_zero_iff hf).not + @[simp] theorem map_id : map id μ = μ := ext fun _ => map_apply measurable_id @@ -1615,11 +1643,19 @@ lemma add_right (h1 : μ ≪ ν) (ν' : Measure α) : μ ≪ ν + ν' := by end AbsolutelyContinuous +alias absolutelyContinuous_refl := AbsolutelyContinuous.refl +alias absolutelyContinuous_rfl := AbsolutelyContinuous.rfl + theorem absolutelyContinuous_of_le_smul {μ' : Measure α} {c : ℝ≥0∞} (hμ'_le : μ' ≤ c • μ) : μ' ≪ μ := (Measure.absolutelyContinuous_of_le hμ'_le).trans (Measure.AbsolutelyContinuous.rfl.smul c) #align measure_theory.measure.absolutely_continuous_of_le_smul MeasureTheory.Measure.absolutelyContinuous_of_le_smul +lemma smul_absolutelyContinuous {c : ℝ≥0∞} : c • μ ≪ μ := absolutelyContinuous_of_le_smul le_rfl + +lemma absolutelyContinuous_smul {c : ℝ≥0∞} (hc : c ≠ 0) : μ ≪ c • μ := by + simp [AbsolutelyContinuous, hc] + theorem ae_le_iff_absolutelyContinuous : μ.ae ≤ ν.ae ↔ μ ≪ ν := ⟨fun h s => by rw [measure_zero_iff_ae_nmem, measure_zero_iff_ae_nmem] @@ -1870,6 +1906,15 @@ open Measure open MeasureTheory +protected theorem _root_.AEMeasurable.nullMeasurable {f : α → β} (h : AEMeasurable f μ) : + NullMeasurable f μ := + let ⟨_g, hgm, hg⟩ := h; hgm.nullMeasurable.congr hg.symm +#align ae_measurable.null_measurable AEMeasurable.nullMeasurable + +lemma _root_.AEMeasurable.nullMeasurableSet_preimage {f : α → β} {s : Set β} + (hf : AEMeasurable f μ) (hs : MeasurableSet s) : NullMeasurableSet (f ⁻¹' s) μ := + hf.nullMeasurable hs + /-- The preimage of a null measurable set under a (quasi) measure preserving map is a null measurable set. -/ theorem NullMeasurableSet.preimage {ν : Measure β} {f : α → β} {t : Set β} diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean index 35e842e781051..a68d762f3c371 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean @@ -295,6 +295,9 @@ theorem measure_sUnion_null_iff {S : Set (Set α)} (hS : S.Countable) : μ.toOuterMeasure.sUnion_null_iff hS #align measure_theory.measure_sUnion_null_iff MeasureTheory.measure_sUnion_null_iff +lemma measure_null_iff_singleton {s : Set α} (hs : s.Countable) : μ s = 0 ↔ ∀ x ∈ s, μ {x} = 0 := by + rw [← measure_biUnion_null_iff hs, biUnion_of_singleton] + theorem measure_union_le (s₁ s₂ : Set α) : μ (s₁ ∪ s₂) ≤ μ s₁ + μ s₂ := μ.toOuterMeasure.union _ _ #align measure_theory.measure_union_le MeasureTheory.measure_union_le @@ -428,7 +431,11 @@ theorem all_ae_of {ι : Sort _} {p : α → ι → Prop} (hp : ∀ᵐ a ∂μ, ∀ᵐ a ∂μ, p a i := by filter_upwards [hp] with a ha using ha i -theorem ae_ball_iff {S : Set ι} (hS : S.Countable) {p : ∀ (_x : α), ∀ i ∈ S, Prop} : +lemma ae_iff_of_countable [Countable α] {p : α → Prop} : (∀ᵐ x ∂μ, p x) ↔ ∀ x, μ {x} ≠ 0 → p x := by + rw [ae_iff, measure_null_iff_singleton] + exacts [forall_congr' fun _ ↦ not_imp_comm, Set.to_countable _] + +theorem ae_ball_iff {S : Set ι} (hS : S.Countable) {p : α → ∀ i ∈ S, Prop} : (∀ᵐ x ∂μ, ∀ i (hi : i ∈ S), p x i hi) ↔ ∀ i (hi : i ∈ S), ∀ᵐ x ∂μ, p x i hi := eventually_countable_ball hS #align measure_theory.ae_ball_iff MeasureTheory.ae_ball_iff From b3a1d74f6f1bdd94c7e0f45d23c77abd2c5ec719 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Sun, 17 Dec 2023 17:55:02 +0000 Subject: [PATCH 028/353] chore: bump Std dependency to leanprover/std4#432 (#9094) This covers these changes in Std: https://github.com/leanprover/std4/compare/6b4cf96c89e53cfcd73350bbcd90333a051ff4f0...9dd24a3493cceefa2bede383f21e4ef548990b68 * `Int.ofNat_natAbs_eq_of_nonneg` has become `Int.natAbs_of_nonneg` (and one argument has become implicit) * `List.map_id''` and `List.map_id'` have exchanged names. (Yay naming things using primes!) * Some meta functions have moved to Std and can be deleted here. Co-authored-by: Scott Morrison --- Mathlib/Control/Random.lean | 2 +- Mathlib/Data/Fintype/Card.lean | 2 +- Mathlib/Data/Int/ModEq.lean | 2 +- Mathlib/Data/List/Basic.lean | 9 ++---- Mathlib/Data/List/BigOperators/Basic.lean | 2 +- Mathlib/Data/List/Sublists.lean | 4 +-- Mathlib/Data/Nat/Squarefree.lean | 2 +- Mathlib/Init/Data/Int/CompLemmas.lean | 2 +- Mathlib/Lean/Expr/Basic.lean | 38 ----------------------- Mathlib/Lean/Meta.lean | 11 ------- lake-manifest.json | 2 +- 11 files changed, 12 insertions(+), 64 deletions(-) diff --git a/Mathlib/Control/Random.lean b/Mathlib/Control/Random.lean index 1ebd61c4d1d9e..e904a25a471b4 100644 --- a/Mathlib/Control/Random.lean +++ b/Mathlib/Control/Random.lean @@ -132,7 +132,7 @@ instance : BoundedRandom m Int where Int.le_add_of_nonneg_left (Int.ofNat_zero_le z), Int.add_le_of_le_sub_right $ Int.le_trans (Int.ofNat_le.mpr h2) - (le_of_eq $ Int.ofNat_natAbs_eq_of_nonneg _ $ Int.sub_nonneg_of_le h)⟩ + (le_of_eq $ Int.natAbs_of_nonneg $ Int.sub_nonneg_of_le h)⟩ instance {n : Nat} : BoundedRandom m (Fin n) where randomR lo hi h _ := do diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index 312325eea6653..648642ea6cb76 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -1227,7 +1227,7 @@ theorem List.exists_pw_disjoint_with_card {α : Type*} [Fintype α] intro a ha conv_rhs => rw [← List.map_id a] rw [List.map_pmap] - simp only [Fin.valEmbedding_apply, Fin.val_mk, List.pmap_eq_map, List.map_id'', List.map_id] + simp only [Fin.valEmbedding_apply, Fin.val_mk, List.pmap_eq_map, List.map_id', List.map_id] use l.map (List.map (Fintype.equivFin α).symm) constructor · -- length diff --git a/Mathlib/Data/Int/ModEq.lean b/Mathlib/Data/Int/ModEq.lean index 870b4111ef194..fcdf45a50b175 100644 --- a/Mathlib/Data/Int/ModEq.lean +++ b/Mathlib/Data/Int/ModEq.lean @@ -315,7 +315,7 @@ theorem exists_unique_equiv (a : ℤ) {b : ℤ} (hb : 0 < b) : theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ, ↑z < b ∧ ↑z ≡ a [ZMOD b] := let ⟨z, hz1, hz2, hz3⟩ := exists_unique_equiv a hb ⟨z.natAbs, by - constructor <;> rw [ofNat_natAbs_eq_of_nonneg z hz1] <;> assumption⟩ + constructor <;> rw [natAbs_of_nonneg hz1] <;> assumption⟩ #align int.exists_unique_equiv_nat Int.exists_unique_equiv_nat theorem mod_mul_right_mod (a b c : ℤ) : a % (b * c) % b = a % b := diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index c2161c8f7cbf8..df16f00de16cd 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -1726,14 +1726,11 @@ theorem map_concat (f : α → β) (a : α) (l : List α) : induction l <;> [rfl; simp only [*, concat_eq_append, cons_append, map, map_append]] #align list.map_concat List.map_concat -@[simp] -theorem map_id'' (l : List α) : map (fun x => x) l = l := - map_id _ -#align list.map_id'' List.map_id'' +#align list.map_id'' List.map_id' -theorem map_id' {f : α → α} (h : ∀ x, f x = x) (l : List α) : map f l = l := by +theorem map_id'' {f : α → α} (h : ∀ x, f x = x) (l : List α) : map f l = l := by simp [show f = id from funext h] -#align list.map_id' List.map_id' +#align list.map_id' List.map_id'' theorem eq_nil_of_map_eq_nil {f : α → β} {l : List α} (h : map f l = nil) : l = nil := eq_nil_of_length_eq_zero <| by rw [← length_map l f, h]; rfl diff --git a/Mathlib/Data/List/BigOperators/Basic.lean b/Mathlib/Data/List/BigOperators/Basic.lean index 3f9dd02a8f11d..b9e9540de0234 100644 --- a/Mathlib/Data/List/BigOperators/Basic.lean +++ b/Mathlib/Data/List/BigOperators/Basic.lean @@ -348,7 +348,7 @@ theorem prod_lt_prod_of_ne_nil [Preorder M] [CovariantClass M M (· * ·) (· < theorem prod_le_pow_card [Preorder M] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] [CovariantClass M M (· * ·) (· ≤ ·)] (l : List M) (n : M) (h : ∀ x ∈ l, x ≤ n) : l.prod ≤ n ^ l.length := by - simpa only [map_id'', map_const', prod_replicate] using prod_le_prod' h + simpa only [map_id', map_const', prod_replicate] using prod_le_prod' h #align list.prod_le_pow_card List.prod_le_pow_card #align list.sum_le_card_nsmul List.sum_le_card_nsmul diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index e54d2e02fbe24..adca68d553f26 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -175,7 +175,7 @@ theorem sublists_cons (a : α) (l : List α) : theorem sublists_concat (l : List α) (a : α) : sublists (l ++ [a]) = sublists l ++ map (fun x => x ++ [a]) (sublists l) := by rw [sublists_append, sublists_singleton, bind_eq_bind, cons_bind, cons_bind, nil_bind, - map_id' append_nil, append_nil] + map_id'' append_nil, append_nil] #align list.sublists_concat List.sublists_concat theorem sublists_reverse (l : List α) : sublists (reverse l) = map reverse (sublists' l) := by @@ -189,7 +189,7 @@ theorem sublists_eq_sublists' (l : List α) : sublists l = map reverse (sublists #align list.sublists_eq_sublists' List.sublists_eq_sublists' theorem sublists'_reverse (l : List α) : sublists' (reverse l) = map reverse (sublists l) := by - simp only [sublists_eq_sublists', map_map, map_id' reverse_reverse, Function.comp] + simp only [sublists_eq_sublists', map_map, map_id'' reverse_reverse, Function.comp] #align list.sublists'_reverse List.sublists'_reverse theorem sublists'_eq_sublists (l : List α) : sublists' l = map reverse (sublists (reverse l)) := by diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index 24f6b53a0e8a3..20e7bd2170f90 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -432,7 +432,7 @@ lemma prod_primeFactors_invOn_squarefree : theorem prod_factors_toFinset_of_squarefree {n : ℕ} (hn : Squarefree n) : ∏ p in n.factors.toFinset, p = n := by - rw [List.prod_toFinset _ hn.nodup_factors, List.map_id'', Nat.prod_factors hn.ne_zero] + rw [List.prod_toFinset _ hn.nodup_factors, List.map_id', Nat.prod_factors hn.ne_zero] end Nat diff --git a/Mathlib/Init/Data/Int/CompLemmas.lean b/Mathlib/Init/Data/Int/CompLemmas.lean index ad16299e0b411..7fb5a1885379c 100644 --- a/Mathlib/Init/Data/Int/CompLemmas.lean +++ b/Mathlib/Init/Data/Int/CompLemmas.lean @@ -95,7 +95,7 @@ theorem zero_le_ofNat (n : ℕ) : 0 ≤ ofNat n := theorem ne_of_natAbs_ne_natAbs_of_nonneg {a b : ℤ} (ha : 0 ≤ a) (hb : 0 ≤ b) (h : natAbs a ≠ natAbs b) : a ≠ b := fun h => by have : (natAbs a : ℤ) = natAbs b := by - rwa [ofNat_natAbs_eq_of_nonneg _ ha, ofNat_natAbs_eq_of_nonneg _ hb] + rwa [natAbs_of_nonneg ha, natAbs_of_nonneg hb] injection this contradiction #align int.ne_of_nat_abs_ne_nat_abs_of_nonneg Int.ne_of_natAbs_ne_natAbs_of_nonneg diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean index 20350fd2aac08..3a14668d7fd41 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -200,44 +200,6 @@ def getAppApps (e : Expr) : Array Expr := let nargs := e.getAppNumArgs getAppAppsAux e (mkArray nargs dummy) (nargs-1) -/-- Turn an expression that is a natural number literal into a natural number. -/ -def natLit! : Expr → Nat - | lit (Literal.natVal v) => v - | _ => panic! "nat literal expected" - -/-- Turn an expression that is a constructor of `Int` applied to a natural number literal -into an integer. -/ -def intLit! (e : Expr) : Int := - if e.isAppOfArity ``Int.ofNat 1 then - e.appArg!.natLit! - else if e.isAppOfArity ``Int.negOfNat 1 then - .negOfNat e.appArg!.natLit! - else - panic! "not a raw integer literal" - -/-- -Check if an expression is a "natural number in normal form", -i.e. of the form `OfNat n`, where `n` matches `.lit (.natVal lit)` for some `lit`. -and if so returns `lit`. --/ --- Note that an `Expr.lit (.natVal n)` is not considered in normal form! -def nat? (e : Expr) : Option Nat := do - guard <| e.isAppOfArity ``OfNat.ofNat 3 - let lit (.natVal n) := e.appFn!.appArg! | none - n - - -/-- -Check if an expression is an "integer in normal form", -i.e. either a natural number in normal form, or the negation of one, -and if so returns the integer. --/ -def int? (e : Expr) : Option Int := - if e.isAppOfArity ``Neg.neg 3 then - (- ·) <$> e.appArg!.nat? - else - e.nat? - /-- Check if an expression is a "rational in normal form", i.e. either an integer number in normal form, diff --git a/Mathlib/Lean/Meta.lean b/Mathlib/Lean/Meta.lean index b08a6e9862aa5..606f13de63ee4 100644 --- a/Mathlib/Lean/Meta.lean +++ b/Mathlib/Lean/Meta.lean @@ -32,10 +32,6 @@ def «let» (g : MVarId) (h : Name) (v : Expr) (t : Option Expr := .none) : MetaM (FVarId × MVarId) := do (← g.define h (← t.getDM (inferType v)) v).intro1P -/-- Short-hand for applying a constant to the goal. -/ -def applyConst (mvar : MVarId) (c : Name) (cfg : ApplyConfig := {}) : MetaM (List MVarId) := do - mvar.apply (← mkConstWithFreshMVarLevels c) cfg - /-- Has the effect of `refine ⟨e₁,e₂,⋯, ?_⟩`. -/ def existsi (mvar : MVarId) (es : List Expr) : MetaM MVarId := do @@ -130,13 +126,6 @@ end Lean.MVarId namespace Lean.Meta -/-- Return local hypotheses which are not "implementation detail", as `Expr`s. -/ -def getLocalHyps [Monad m] [MonadLCtx m] : m (Array Expr) := do - let mut hs := #[] - for d in ← getLCtx do - if !d.isImplementationDetail then hs := hs.push d.toExpr - return hs - /-- Count how many local hypotheses appear in an expression. -/ def countLocalHypsUsed [Monad m] [MonadLCtx m] [MonadMCtx m] (e : Expr) : m Nat := do let e' ← instantiateMVars e diff --git a/lake-manifest.json b/lake-manifest.json index cd58ceb1d04d3..a90df0d688464 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "6b4cf96c89e53cfcd73350bbcd90333a051ff4f0", + "rev": "9dd24a3493cceefa2bede383f21e4ef548990b68", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", From 1515c7e8d1dbe9d0fca8d83af9e57ae48511a34f Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Sun, 17 Dec 2023 19:25:17 +0000 Subject: [PATCH 029/353] feat: Dual basis of power basis wrt trace form (#8835) Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 1 + Mathlib/Data/Polynomial/RingDivision.lean | 25 +++ Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean | 214 ++++++++++++++++++++ Mathlib/FieldTheory/Separable.lean | 13 ++ Mathlib/RingTheory/IntegralClosure.lean | 23 ++- Mathlib/RingTheory/Trace.lean | 31 +++ 6 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean diff --git a/Mathlib.lean b/Mathlib.lean index 9159a9eceaa8c..9979033ad8893 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2059,6 +2059,7 @@ import Mathlib.FieldTheory.Laurent import Mathlib.FieldTheory.Minpoly.Basic import Mathlib.FieldTheory.Minpoly.Field import Mathlib.FieldTheory.Minpoly.IsIntegrallyClosed +import Mathlib.FieldTheory.Minpoly.MinpolyDiv import Mathlib.FieldTheory.MvPolynomial import Mathlib.FieldTheory.Normal import Mathlib.FieldTheory.NormalClosure diff --git a/Mathlib/Data/Polynomial/RingDivision.lean b/Mathlib/Data/Polynomial/RingDivision.lean index e7abfdaa98f36..f5ba2515d7bb5 100644 --- a/Mathlib/Data/Polynomial/RingDivision.lean +++ b/Mathlib/Data/Polynomial/RingDivision.lean @@ -1263,6 +1263,31 @@ theorem eq_of_monic_of_dvd_of_natDegree_le {R} [CommRing R] {p q : R[X]} (hp : p rw [hq.leadingCoeff, C_1, one_mul] #align polynomial.eq_of_monic_of_dvd_of_nat_degree_le Polynomial.eq_of_monic_of_dvd_of_natDegree_le +lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero {R} [CommRing R] [IsDomain R] + (p : R[X]) {ι} [Fintype ι] {f : ι → R} (hf : Function.Injective f) + (heval : ∀ i, p.eval (f i) = 0) (hcard : natDegree p < Fintype.card ι) : p = 0 := by + classical + by_contra hp + apply not_lt_of_le (le_refl (Finset.card p.roots.toFinset)) + calc + Finset.card p.roots.toFinset ≤ Multiset.card p.roots := Multiset.toFinset_card_le _ + _ ≤ natDegree p := Polynomial.card_roots' p + _ < Fintype.card ι := hcard + _ = Fintype.card (Set.range f) := (Set.card_range_of_injective hf).symm + _ = Finset.card (Finset.univ.image f) := by rw [← Set.toFinset_card, Set.toFinset_range] + _ ≤ Finset.card p.roots.toFinset := Finset.card_mono ?_ + intro _ + simp only [Finset.mem_image, Finset.mem_univ, true_and, Multiset.mem_toFinset, mem_roots', ne_eq, + IsRoot.def, forall_exists_index, hp, not_false_eq_true] + rintro x rfl + exact heval _ + +lemma eq_zero_of_natDegree_lt_card_of_eval_eq_zero' {R} [CommRing R] [IsDomain R] + (p : R[X]) (s : Finset R) (heval : ∀ i ∈ s, p.eval i = 0) (hcard : natDegree p < s.card) : + p = 0 := + eq_zero_of_natDegree_lt_card_of_eval_eq_zero p Subtype.val_injective + (fun i : s ↦ heval i i.prop) (hcard.trans_eq (Fintype.card_coe s).symm) + theorem isCoprime_X_sub_C_of_isUnit_sub {R} [CommRing R] {a b : R} (h : IsUnit (a - b)) : IsCoprime (X - C a) (X - C b) := ⟨-C h.unit⁻¹.val, C h.unit⁻¹.val, by diff --git a/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean b/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean new file mode 100644 index 0000000000000..acdd23f680982 --- /dev/null +++ b/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean @@ -0,0 +1,214 @@ +/- +Copyright (c) 2023 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.FieldTheory.Minpoly.IsIntegrallyClosed +import Mathlib.FieldTheory.PrimitiveElement +import Mathlib.FieldTheory.IsAlgClosed.Basic + +/-! +# Results about `minpoly R x / (X - C x)` + +## Main definition +- `minpolyDiv`: The polynomial `minpoly R x / (X - C x)`. + +We used the contents of this file to describe the dual basis of a powerbasis under the trace form. +See `traceForm_dualBasis_powerBasis_eq`. + +## Main results +- `span_coeff_minpolyDiv`: The coefficients of `minpolyDiv` spans `R`. +-/ + +open Polynomial BigOperators FiniteDimensional + +variable (R K) {L S} [CommRing R] [Field K] [Field L] [CommRing S] [Algebra R S] [Algebra K L] +variable (x : S) + +/-- `minpolyDiv R x : S[X]` for `x : S` is the polynomial `minpoly R x / (X - C x)`. -/ +noncomputable def minpolyDiv : S[X] := (minpoly R x).map (algebraMap R S) /ₘ (X - C x) + +lemma minpolyDiv_spec : + minpolyDiv R x * (X - C x) = (minpoly R x).map (algebraMap R S) := by + delta minpolyDiv + rw [mul_comm, mul_divByMonic_eq_iff_isRoot, IsRoot, eval_map, ← aeval_def, minpoly.aeval] + +lemma coeff_minpolyDiv (i) : coeff (minpolyDiv R x) i = + algebraMap R S (coeff (minpoly R x) (i + 1)) + coeff (minpolyDiv R x) (i + 1) * x := by + rw [← coeff_map, ← minpolyDiv_spec R x]; simp [mul_sub] + +variable (hx : IsIntegral R x) {R x} + +lemma minpolyDiv_ne_zero [Nontrivial S] : minpolyDiv R x ≠ 0 := by + intro e + have := minpolyDiv_spec R x + rw [e, zero_mul] at this + exact ((minpoly.monic hx).map (algebraMap R S)).ne_zero this.symm + +lemma minpolyDiv_eq_zero (hx : ¬IsIntegral R x) : minpolyDiv R x = 0 := by + delta minpolyDiv minpoly + rw [dif_neg hx, Polynomial.map_zero, zero_divByMonic] + +lemma minpolyDiv_monic : Monic (minpolyDiv R x) := by + nontriviality S + have := congr_arg leadingCoeff (minpolyDiv_spec R x) + rw [leadingCoeff_mul', ((minpoly.monic hx).map (algebraMap R S)).leadingCoeff] at this + · simpa using this + · simpa using minpolyDiv_ne_zero hx + +lemma eval_minpolyDiv_self : (minpolyDiv R x).eval x = aeval x (derivative <| minpoly R x) := by + rw [aeval_def, ← eval_map, ← derivative_map, ← minpolyDiv_spec R x]; simp + +lemma minpolyDiv_eval_eq_zero_of_ne_of_aeval_eq_zero [IsDomain S] + {y} (hxy : y ≠ x) (hy : aeval y (minpoly R x) = 0) : (minpolyDiv R x).eval y = 0 := by + rw [aeval_def, ← eval_map, ← minpolyDiv_spec R x] at hy + simp only [eval_mul, eval_sub, eval_X, eval_C, mul_eq_zero] at hy + exact hy.resolve_right (by rwa [sub_eq_zero]) + +lemma eval₂_minpolyDiv_of_eval₂_eq_zero {T} [CommRing T] + [IsDomain T] [DecidableEq T] {x y} + (σ : S →+* T) (hy : eval₂ (σ.comp (algebraMap R S)) y (minpoly R x) = 0) : + eval₂ σ y (minpolyDiv R x) = + if σ x = y then σ (aeval x (derivative <| minpoly R x)) else 0 := by + split_ifs with h + · rw [← h, eval₂_hom, eval_minpolyDiv_self] + · rw [← eval₂_map, ← minpolyDiv_spec] at hy + simpa [sub_eq_zero, Ne.symm h] using hy + +lemma eval₂_minpolyDiv_self {T} [CommRing T] [Algebra R T] [IsDomain T] [DecidableEq T] (x : S) + (σ₁ σ₂ : S →ₐ[R] T) : + eval₂ σ₁ (σ₂ x) (minpolyDiv R x) = + if σ₁ x = σ₂ x then σ₁ (aeval x (derivative <| minpoly R x)) else 0 := by + apply eval₂_minpolyDiv_of_eval₂_eq_zero + rw [AlgHom.comp_algebraMap, ← σ₂.comp_algebraMap, ← eval₂_map, ← RingHom.coe_coe, eval₂_hom, + eval_map, ← aeval_def, minpoly.aeval, map_zero] + +lemma eval_minpolyDiv_of_aeval_eq_zero [IsDomain S] [DecidableEq S] + {y} (hy : aeval y (minpoly R x) = 0) : + (minpolyDiv R x).eval y = if x = y then aeval x (derivative <| minpoly R x) else 0 := by + rw [eval, eval₂_minpolyDiv_of_eval₂_eq_zero]; rfl + exact hy + +lemma natDegree_minpolyDiv_succ [Nontrivial S] : + natDegree (minpolyDiv R x) + 1 = natDegree (minpoly R x) := by + rw [← (minpoly.monic hx).natDegree_map (algebraMap R S), ← minpolyDiv_spec, natDegree_mul'] + · simp + · simpa using minpolyDiv_ne_zero hx + +lemma natDegree_minpolyDiv : + natDegree (minpolyDiv R x) = natDegree (minpoly R x) - 1 := by + nontriviality S + by_cases hx : IsIntegral R x + · rw [← natDegree_minpolyDiv_succ hx]; rfl + · rw [minpolyDiv_eq_zero hx, minpoly.eq_zero hx]; rfl + +lemma natDegree_minpolyDiv_lt [Nontrivial S] : + natDegree (minpolyDiv R x) < natDegree (minpoly R x) := by + rw [← natDegree_minpolyDiv_succ hx] + exact Nat.lt.base _ + +lemma coeff_minpolyDiv_mem_adjoin (x : S) (i) : + coeff (minpolyDiv R x) i ∈ Algebra.adjoin R {x} := by + by_contra H + have : ∀ j, coeff (minpolyDiv R x) (i + j) ∉ Algebra.adjoin R {x} + · intro j; induction j with + | zero => exact H + | succ j IH => + intro H; apply IH + rw [coeff_minpolyDiv] + refine add_mem ?_ (mul_mem H (Algebra.self_mem_adjoin_singleton R x)) + exact Subalgebra.algebraMap_mem _ _ + apply this (natDegree (minpolyDiv R x) + 1) + rw [coeff_eq_zero_of_natDegree_lt] + · exact zero_mem _ + · refine (Nat.le_add_left _ i).trans_lt ?_ + rw [← add_assoc] + exact Nat.lt.base _ + +lemma minpolyDiv_eq_of_isIntegrallyClosed [IsDomain R] [IsIntegrallyClosed R] [IsDomain S] + [Algebra R K] [Algebra K S] [IsScalarTower R K S] [IsFractionRing R K] : + minpolyDiv R x = minpolyDiv K x := by + delta minpolyDiv + rw [IsScalarTower.algebraMap_eq R K S, ← map_map, + ← minpoly.isIntegrallyClosed_eq_field_fractions' _ hx] + +lemma coeff_minpolyDiv_sub_pow_mem_span {i} (hi : i ≤ natDegree (minpolyDiv R x)) : + coeff (minpolyDiv R x) (natDegree (minpolyDiv R x) - i) - x ^ i ∈ + Submodule.span R ((x ^ ·) '' Set.Iio i) := by + induction i with + | zero => simp [(minpolyDiv_monic hx).leadingCoeff] + | succ i IH => + rw [coeff_minpolyDiv, add_sub_assoc, pow_succ', ← sub_mul, Algebra.algebraMap_eq_smul_one] + refine add_mem ?_ ?_ + · apply Submodule.smul_mem + apply Submodule.subset_span + exact ⟨0, Nat.zero_lt_succ _, pow_zero _⟩ + · rw [Nat.succ_eq_add_one, ← tsub_tsub, tsub_add_cancel_of_le + (le_tsub_of_add_le_left (b := 1) hi)] + apply SetLike.le_def.mp ?_ + (Submodule.mul_mem_mul (IH ((Nat.le_succ _).trans hi)) + (Submodule.mem_span_singleton_self x)) + rw [Submodule.span_mul_span, Set.mul_singleton, Set.image_image] + apply Submodule.span_mono + rintro _ ⟨j, hj : j < i, rfl⟩ + exact ⟨j + 1, Nat.add_lt_of_lt_sub hj, pow_succ' x j⟩ + +lemma span_coeff_minpolyDiv : + Submodule.span R (Set.range (coeff (minpolyDiv R x))) = + Subalgebra.toSubmodule (Algebra.adjoin R {x}) := by + nontriviality S + classical + apply le_antisymm + · rw [Submodule.span_le] + rintro _ ⟨i, rfl⟩ + apply coeff_minpolyDiv_mem_adjoin + · rw [← Submodule.span_range_natDegree_eq_adjoin (minpoly.monic hx) (minpoly.aeval _ _), + Submodule.span_le] + simp only [Finset.coe_image, Finset.coe_range, Set.image_subset_iff] + intro i + apply Nat.strongInductionOn i + intro i hi hi' + have : coeff (minpolyDiv R x) (natDegree (minpolyDiv R x) - i) ∈ + Submodule.span R (Set.range (coeff (minpolyDiv R x))) := + Submodule.subset_span (Set.mem_range_self _) + rw [Set.mem_preimage, SetLike.mem_coe, ← Submodule.sub_mem_iff_right _ this] + refine SetLike.le_def.mp ?_ (coeff_minpolyDiv_sub_pow_mem_span hx ?_) + · rw [Submodule.span_le, Set.image_subset_iff] + intro j (hj : j < i) + exact hi j hj (lt_trans hj hi') + · rwa [← natDegree_minpolyDiv_succ hx, Set.mem_Iio, Nat.lt_succ_iff] at hi' + +section PowerBasis + +variable {K} + +lemma sum_smul_minpolyDiv_eq_X_pow (E) [Field E] [Algebra K E] [IsAlgClosed E] + [FiniteDimensional K L] [IsSeparable K L] + {x : L} (hxL : Algebra.adjoin K {x} = ⊤) {r : ℕ} (hr : r < finrank K L) : + ∑ σ : L →ₐ[K] E, ((x ^ r / aeval x (derivative <| minpoly K x)) • + minpolyDiv K x).map σ = (X ^ r : E[X]) := by + classical + rw [← sub_eq_zero] + have : Function.Injective (fun σ : L →ₐ[K] E ↦ σ x) := fun _ _ h => + AlgHom.ext_of_adjoin_eq_top hxL (fun _ hx ↦ hx ▸ h) + apply Polynomial.eq_zero_of_natDegree_lt_card_of_eval_eq_zero _ this + · intro σ + simp only [Polynomial.map_smul, map_div₀, map_pow, RingHom.coe_coe, eval_sub, eval_finset_sum, + eval_smul, eval_map, eval₂_minpolyDiv_self, this.eq_iff, smul_eq_mul, mul_ite, mul_zero, + Finset.sum_ite_eq', Finset.mem_univ, ite_true, eval_pow, eval_X] + rw [sub_eq_zero, div_mul_cancel] + rw [ne_eq, map_eq_zero_iff σ σ.toRingHom.injective] + exact (IsSeparable.separable _ _).aeval_derivative_ne_zero (minpoly.aeval _ _) + · refine (Polynomial.natDegree_sub_le _ _).trans_lt + (max_lt ((Polynomial.natDegree_sum_le _ _).trans_lt ?_) ?_) + · simp only [AlgEquiv.toAlgHom_eq_coe, Polynomial.map_smul, + map_div₀, map_pow, RingHom.coe_coe, AlgHom.coe_coe, Function.comp_apply, + Finset.mem_univ, forall_true_left, true_and, Finset.fold_max_lt, AlgHom.card] + refine ⟨finrank_pos, ?_⟩ + intro σ + exact ((Polynomial.natDegree_smul_le _ _).trans (natDegree_map_le _ _)).trans_lt + ((natDegree_minpolyDiv_lt (Algebra.IsIntegral.of_finite _ _ x)).trans_le + (minpoly.natDegree_le _)) + · rwa [natDegree_pow, natDegree_X, mul_one, AlgHom.card] + +end PowerBasis diff --git a/Mathlib/FieldTheory/Separable.lean b/Mathlib/FieldTheory/Separable.lean index b90d92843b8ba..e634787807932 100644 --- a/Mathlib/FieldTheory/Separable.lean +++ b/Mathlib/FieldTheory/Separable.lean @@ -130,6 +130,19 @@ theorem Separable.map {p : R[X]} (h : p.Separable) {f : R →+* S} : (p.map f).S Polynomial.map_one]⟩ #align polynomial.separable.map Polynomial.Separable.map +theorem Separable.eval₂_derivative_ne_zero [Nontrivial S] (f : R →+* S) {p : R[X]} + (h : p.Separable) {x : S} (hx : p.eval₂ f x = 0) : + (derivative p).eval₂ f x ≠ 0 := by + intro hx' + obtain ⟨a, b, e⟩ := h + apply_fun Polynomial.eval₂ f x at e + simp only [eval₂_add, eval₂_mul, hx, mul_zero, hx', add_zero, eval₂_one, zero_ne_one] at e + +theorem Separable.aeval_derivative_ne_zero [Nontrivial S] [Algebra R S] {p : R[X]} + (h : p.Separable) {x : S} (hx : aeval x p = 0) : + aeval x (derivative p) ≠ 0 := + h.eval₂_derivative_ne_zero (algebraMap R S) hx + variable (p q : ℕ) theorem isUnit_of_self_mul_dvd_separable {p q : R[X]} (hp : p.Separable) (hq : q * q ∣ p) : diff --git a/Mathlib/RingTheory/IntegralClosure.lean b/Mathlib/RingTheory/IntegralClosure.lean index 86743a62a9475..249bd9e14d3ce 100644 --- a/Mathlib/RingTheory/IntegralClosure.lean +++ b/Mathlib/RingTheory/IntegralClosure.lean @@ -170,22 +170,29 @@ theorem isIntegral_iff_isIntegral_closure_finite {r : B} : exact hsr.of_subring _ #align is_integral_iff_is_integral_closure_finite isIntegral_iff_isIntegral_closure_finite -theorem IsIntegral.fg_adjoin_singleton {x : B} (hx : IsIntegral R x) : - (Algebra.adjoin R {x}).toSubmodule.FG := by - rcases hx with ⟨f, hfm, hfx⟩ - use (Finset.range <| f.natDegree + 1).image (x ^ ·) +theorem Submodule.span_range_natDegree_eq_adjoin {R A} [CommRing R] [Semiring A] [Algebra R A] + {x : A} {f : R[X]} (hf : f.Monic) (hfx : aeval x f = 0) : + span R (Finset.image (x ^ ·) (Finset.range (natDegree f))) = + Subalgebra.toSubmodule (Algebra.adjoin R {x}) := by + nontriviality A + have hf1 : f ≠ 1 := by rintro rfl; simp [one_ne_zero' A] at hfx refine (span_le.mpr fun s hs ↦ ?_).antisymm fun r hr ↦ ?_ · rcases Finset.mem_image.1 hs with ⟨k, -, rfl⟩ exact (Algebra.adjoin R {x}).pow_mem (Algebra.subset_adjoin rfl) k rw [Subalgebra.mem_toSubmodule, Algebra.adjoin_singleton_eq_range_aeval] at hr rcases (aeval x).mem_range.mp hr with ⟨p, rfl⟩ - rw [← modByMonic_add_div p hfm, map_add, map_mul, aeval_def x f, hfx, + rw [← modByMonic_add_div p hf, map_add, map_mul, hfx, zero_mul, add_zero, ← sum_C_mul_X_pow_eq (p %ₘ f), aeval_def, eval₂_sum, sum_def] refine sum_mem fun k hkq ↦ ?_ rw [C_mul_X_pow_eq_monomial, eval₂_monomial, ← Algebra.smul_def] - exact smul_mem _ _ (subset_span <| Finset.mem_image_of_mem _ <| Finset.mem_range_succ_iff.mpr <| - (le_natDegree_of_mem_supp _ hkq).trans <| natDegree_modByMonic_le p hfm) -#align fg_adjoin_singleton_of_integral IsIntegral.fg_adjoin_singleton + exact smul_mem _ _ (subset_span <| Finset.mem_image_of_mem _ <| Finset.mem_range.mpr <| + (le_natDegree_of_mem_supp _ hkq).trans_lt <| natDegree_modByMonic_lt p hf hf1) + +theorem IsIntegral.fg_adjoin_singleton {x : B} (hx : IsIntegral R x) : + (Algebra.adjoin R {x}).toSubmodule.FG := by + rcases hx with ⟨f, hfm, hfx⟩ + use (Finset.range <| f.natDegree).image (x ^ ·) + exact span_range_natDegree_eq_adjoin hfm (by rwa [aeval_def]) theorem fg_adjoin_of_finite {s : Set A} (hfs : s.Finite) (his : ∀ x ∈ s, IsIntegral R x) : (Algebra.adjoin R s).toSubmodule.FG := diff --git a/Mathlib/RingTheory/Trace.lean b/Mathlib/RingTheory/Trace.lean index e97e24b66b0da..183407924e4e7 100644 --- a/Mathlib/RingTheory/Trace.lean +++ b/Mathlib/RingTheory/Trace.lean @@ -13,6 +13,7 @@ import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure import Mathlib.FieldTheory.PrimitiveElement import Mathlib.FieldTheory.Galois import Mathlib.RingTheory.PowerBasis +import Mathlib.FieldTheory.Minpoly.MinpolyDiv #align_import ring_theory.trace from "leanprover-community/mathlib"@"3e068ece210655b7b9a9477c3aff38a492400aa1" @@ -43,6 +44,8 @@ the roots of the minimal polynomial of `s` over `R`. algebraically closed field * `traceForm_nondegenerate`: the trace form over a separable extension is a nondegenerate bilinear form +* `traceForm_dualBasis_powerBasis_eq`: The dual basis of a powerbasis `{1, x, x²...}` under the + trace form is `aᵢ / f'(x)`, with `f` being the minpoly of `x` and `f / (X - x) = ∑ aᵢxⁱ`. ## Implementation notes @@ -660,4 +663,32 @@ theorem Algebra.trace_surjective [FiniteDimensional K L] [IsSeparable K L] : rw [LinearMap.range_eq_bot] exact Algebra.trace_ne_zero K L +variable {K L} + +/-- +The dual basis of a powerbasis `{1, x, x²...}` under the trace form is `aᵢ / f'(x)`, +with `f` being the minimal polynomial of `x` and `f / (X - x) = ∑ aᵢxⁱ`. +-/ +lemma traceForm_dualBasis_powerBasis_eq [FiniteDimensional K L] [IsSeparable K L] + (pb : PowerBasis K L) (i) : + (Algebra.traceForm K L).dualBasis (traceForm_nondegenerate K L) pb.basis i = + (minpolyDiv K pb.gen).coeff i / aeval pb.gen (derivative <| minpoly K pb.gen) := by + classical + apply ((Algebra.traceForm K L).toDual (traceForm_nondegenerate K L)).injective + apply pb.basis.ext + intro j + simp only [BilinForm.toDual_def, BilinForm.apply_dualBasis_left] + apply (algebraMap K (AlgebraicClosure K)).injective + have := congr_arg (coeff · i) (sum_smul_minpolyDiv_eq_X_pow (AlgebraicClosure K) + pb.adjoin_gen_eq_top (r := j) (pb.finrank.symm ▸ j.prop)) + simp only [AlgEquiv.toAlgHom_eq_coe, Polynomial.map_smul, map_div₀, + map_pow, RingHom.coe_coe, AlgHom.coe_coe, finset_sum_coeff, coeff_smul, coeff_map, smul_eq_mul, + coeff_X_pow, ← Fin.ext_iff, @eq_comm _ i] at this + rw [PowerBasis.coe_basis, Algebra.traceForm_apply, RingHom.map_ite_one_zero, + ← this, trace_eq_sum_embeddings (E := AlgebraicClosure K)] + apply Finset.sum_congr rfl + intro σ _ + simp only [_root_.map_mul, map_div₀, map_pow] + ring + end DetNeZero From 07b02ce380d5b5a8d3c3fc7c229dbfd56dc4bd8a Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 17 Dec 2023 20:09:10 +0000 Subject: [PATCH 030/353] feat(Algebra/MonoidAlgebra): when `single` and `of` commute (#8975) Also removes an `autoImplicit` that tripped me up when working on this file. --- Mathlib/Algebra/MonoidAlgebra/Basic.lean | 39 +++++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/Mathlib/Algebra/MonoidAlgebra/Basic.lean b/Mathlib/Algebra/MonoidAlgebra/Basic.lean index e8f00eb595151..4d7bb6fdf2b7e 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Basic.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Basic.lean @@ -50,8 +50,6 @@ Similarly, I attempted to just define `Multiplicative G = G` leaks through everywhere, and seems impossible to use. -/ -set_option autoImplicit true - noncomputable section @@ -118,7 +116,8 @@ theorem single_add (a : G) (b₁ b₂ : k) : single a (b₁ + b₂) = single a b Finsupp.single_add a b₁ b₂ @[simp] -theorem sum_single_index [AddCommMonoid N] {a : G} {b : k} {h : G → k → N} (h_zero : h a 0 = 0) : +theorem sum_single_index {N} [AddCommMonoid N] {a : G} {b : k} {h : G → k → N} + (h_zero : h a 0 = 0) : (single a b).sum h = h a b := Finsupp.sum_single_index h_zero @[simp] @@ -452,6 +451,17 @@ theorem single_mul_single [Mul G] {a₁ a₂ : G} {b₁ b₂ : k} : (sum_single_index (by rw [mul_zero, single_zero])) #align monoid_algebra.single_mul_single MonoidAlgebra.single_mul_single +theorem single_commute_single [Mul G] {a₁ a₂ : G} {b₁ b₂ : k} + (ha : Commute a₁ a₂) (hb : Commute b₁ b₂) : + Commute (single a₁ b₁) (single a₂ b₂) := + single_mul_single.trans <| congr_arg₂ single ha hb |>.trans single_mul_single.symm + +theorem single_commute [Mul G] {a : G} {b : k} (ha : ∀ a', Commute a a') (hb : ∀ b', Commute b b') : + ∀ f : MonoidAlgebra k G, Commute (single a b) f := + suffices AddMonoidHom.mulLeft (single a b) = AddMonoidHom.mulRight (single a b) from + FunLike.congr_fun this + addHom_ext' fun a' => AddMonoidHom.ext fun b' => single_commute_single (ha a') (hb b') + @[simp] theorem single_pow [Monoid G] {a : G} {b : k} : ∀ n : ℕ, single a b ^ n = single (a ^ n) (b ^ n) | 0 => by @@ -516,6 +526,10 @@ theorem of_injective [MulOneClass G] [Nontrivial k] : simpa using (single_eq_single_iff _ _ _ _).mp h #align monoid_algebra.of_injective MonoidAlgebra.of_injective +theorem of_commute [MulOneClass G] {a : G} (h : ∀ a', Commute a a') (f : MonoidAlgebra k G) : + Commute (of k G a) f := + single_commute h Commute.one_left f + /-- `Finsupp.single` as a `MonoidHom` from the product type into the monoid algebra. Note the order of the elements of the product are reversed compared to the arguments of @@ -729,10 +743,8 @@ section Algebra -- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`. theorem single_one_comm [CommSemiring k] [MulOneClass G] (r : k) (f : MonoidAlgebra k G) : - single (1 : G) r * f = f * single (1 : G) r := by - -- Porting note: `ext` → `refine Finsupp.ext fun _ => ?_` - refine Finsupp.ext fun _ => ?_ - rw [single_one_mul_apply, mul_single_one_apply, mul_comm] + single (1 : G) r * f = f * single (1 : G) r := + single_commute Commute.one_left (Commute.all _) f #align monoid_algebra.single_one_comm MonoidAlgebra.single_one_comm /-- `Finsupp.single 1` as a `RingHom` -/ @@ -1235,7 +1247,8 @@ theorem single_add (a : G) (b₁ b₂ : k) : single a (b₁ + b₂) = single a b Finsupp.single_add a b₁ b₂ @[simp] -theorem sum_single_index [AddCommMonoid N] {a : G} {b : k} {h : G → k → N} (h_zero : h a 0 = 0) : +theorem sum_single_index {N} [AddCommMonoid N] {a : G} {b : k} {h : G → k → N} + (h_zero : h a 0 = 0) : (single a b).sum h = h a b := Finsupp.sum_single_index h_zero @[simp] @@ -1554,6 +1567,11 @@ theorem single_mul_single [Add G] {a₁ a₂ : G} {b₁ b₂ : k} : @MonoidAlgebra.single_mul_single k (Multiplicative G) _ _ _ _ _ _ #align add_monoid_algebra.single_mul_single AddMonoidAlgebra.single_mul_single +theorem single_commute_single [Add G] {a₁ a₂ : G} {b₁ b₂ : k} + (ha : AddCommute a₁ a₂) (hb : Commute b₁ b₂) : + Commute (single a₁ b₁) (single a₂ b₂) := + @MonoidAlgebra.single_commute_single k (Multiplicative G) _ _ _ _ _ _ ha hb + -- This should be a `@[simp]` lemma, but the simp_nf linter times out if we add this. -- Probably the correct fix is to make a `[Add]MonoidAlgebra.single` with the correct type, -- instead of relying on `Finsupp.single`. @@ -1632,6 +1650,11 @@ theorem of_injective [Nontrivial k] [AddZeroClass G] : Function.Injective (of k MonoidAlgebra.of_injective #align add_monoid_algebra.of_injective AddMonoidAlgebra.of_injective +theorem of'_commute [Semiring k] [AddZeroClass G] {a : G} (h : ∀ a', AddCommute a a') + (f : AddMonoidAlgebra k G) : + Commute (of' k G a) f := + MonoidAlgebra.of_commute (G := Multiplicative G) h f + /-- `Finsupp.single` as a `MonoidHom` from the product type into the additive monoid algebra. Note the order of the elements of the product are reversed compared to the arguments of From f1ba2113dea86fd9220acd5d181c5e04325eaacb Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 17 Dec 2023 20:09:12 +0000 Subject: [PATCH 031/353] chore(LinearAlgebra/CliffordAlgebra): move results about inversion to a new file (#9075) I plan to contribute a few more of these, and this provides a better place for them to live. No lemma statements or proofs have changed. These were originally contributed in leanprover-community/mathlib#16077. --- Mathlib.lean | 1 + .../LinearAlgebra/CliffordAlgebra/Basic.lean | 38 ------------- .../CliffordAlgebra/Inversion.lean | 57 +++++++++++++++++++ 3 files changed, 58 insertions(+), 38 deletions(-) create mode 100644 Mathlib/LinearAlgebra/CliffordAlgebra/Inversion.lean diff --git a/Mathlib.lean b/Mathlib.lean index 9979033ad8893..5f206e8dc6c81 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2356,6 +2356,7 @@ import Mathlib.LinearAlgebra.CliffordAlgebra.Even import Mathlib.LinearAlgebra.CliffordAlgebra.EvenEquiv import Mathlib.LinearAlgebra.CliffordAlgebra.Fold import Mathlib.LinearAlgebra.CliffordAlgebra.Grading +import Mathlib.LinearAlgebra.CliffordAlgebra.Inversion import Mathlib.LinearAlgebra.CliffordAlgebra.Star import Mathlib.LinearAlgebra.Coevaluation import Mathlib.LinearAlgebra.Contraction diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean index 4dd0d618b4196..79fd91e5fd90b 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean @@ -367,44 +367,6 @@ theorem equivOfIsometry_refl : end Map -variable (Q) - -/-- If the quadratic form of a vector is invertible, then so is that vector. -/ -def invertibleιOfInvertible (m : M) [Invertible (Q m)] : Invertible (ι Q m) where - invOf := ι Q (⅟ (Q m) • m) - invOf_mul_self := by - rw [map_smul, smul_mul_assoc, ι_sq_scalar, Algebra.smul_def, ← map_mul, invOf_mul_self, map_one] - mul_invOf_self := by - rw [map_smul, mul_smul_comm, ι_sq_scalar, Algebra.smul_def, ← map_mul, invOf_mul_self, map_one] -#align clifford_algebra.invertible_ι_of_invertible CliffordAlgebra.invertibleιOfInvertible - -/-- For a vector with invertible quadratic form, $v^{-1} = \frac{v}{Q(v)}$ -/ -theorem invOf_ι (m : M) [Invertible (Q m)] [Invertible (ι Q m)] : - ⅟ (ι Q m) = ι Q (⅟ (Q m) • m) := by - letI := invertibleιOfInvertible Q m - convert (rfl : ⅟ (ι Q m) = _) -#align clifford_algebra.inv_of_ι CliffordAlgebra.invOf_ι - -theorem isUnit_ι_of_isUnit {m : M} (h : IsUnit (Q m)) : IsUnit (ι Q m) := by - cases h.nonempty_invertible - letI := invertibleιOfInvertible Q m - exact isUnit_of_invertible (ι Q m) -#align clifford_algebra.is_unit_ι_of_is_unit CliffordAlgebra.isUnit_ι_of_isUnit - -/-- $aba^{-1}$ is a vector. -/ -theorem ι_mul_ι_mul_invOf_ι (a b : M) [Invertible (ι Q a)] [Invertible (Q a)] : - ι Q a * ι Q b * ⅟ (ι Q a) = ι Q ((⅟ (Q a) * QuadraticForm.polar Q a b) • a - b) := by - rw [invOf_ι, map_smul, mul_smul_comm, ι_mul_ι_mul_ι, ← map_smul, smul_sub, smul_smul, smul_smul, - invOf_mul_self, one_smul] -#align clifford_algebra.ι_mul_ι_mul_inv_of_ι CliffordAlgebra.ι_mul_ι_mul_invOf_ι - -/-- $a^{-1}ba$ is a vector. -/ -theorem invOf_ι_mul_ι_mul_ι (a b : M) [Invertible (ι Q a)] [Invertible (Q a)] : - ⅟ (ι Q a) * ι Q b * ι Q a = ι Q ((⅟ (Q a) * QuadraticForm.polar Q a b) • a - b) := by - rw [invOf_ι, map_smul, smul_mul_assoc, smul_mul_assoc, ι_mul_ι_mul_ι, ← map_smul, smul_sub, - smul_smul, smul_smul, invOf_mul_self, one_smul] -#align clifford_algebra.inv_of_ι_mul_ι_mul_ι CliffordAlgebra.invOf_ι_mul_ι_mul_ι - end CliffordAlgebra namespace TensorAlgebra diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Inversion.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Inversion.lean new file mode 100644 index 0000000000000..8e82f4defd9c4 --- /dev/null +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Inversion.lean @@ -0,0 +1,57 @@ +/- +Copyright (c) 2022 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.LinearAlgebra.CliffordAlgebra.Basic + +/-! # Results about inverses in Clifford algebras + +This contains some basic results about the inversion of vectors, related to the fact that +$ι(m)^{-1} = \frac{ι(m)}{Q(m)}$. +-/ + +variable {R M : Type*} +variable [CommRing R] [AddCommGroup M] [Module R M] {Q : QuadraticForm R M} + +namespace CliffordAlgebra + +variable (Q) + +/-- If the quadratic form of a vector is invertible, then so is that vector. -/ +def invertibleιOfInvertible (m : M) [Invertible (Q m)] : Invertible (ι Q m) where + invOf := ι Q (⅟ (Q m) • m) + invOf_mul_self := by + rw [map_smul, smul_mul_assoc, ι_sq_scalar, Algebra.smul_def, ← map_mul, invOf_mul_self, map_one] + mul_invOf_self := by + rw [map_smul, mul_smul_comm, ι_sq_scalar, Algebra.smul_def, ← map_mul, invOf_mul_self, map_one] +#align clifford_algebra.invertible_ι_of_invertible CliffordAlgebra.invertibleιOfInvertible + +/-- For a vector with invertible quadratic form, $v^{-1} = \frac{v}{Q(v)}$ -/ +theorem invOf_ι (m : M) [Invertible (Q m)] [Invertible (ι Q m)] : + ⅟ (ι Q m) = ι Q (⅟ (Q m) • m) := by + letI := invertibleιOfInvertible Q m + convert (rfl : ⅟ (ι Q m) = _) +#align clifford_algebra.inv_of_ι CliffordAlgebra.invOf_ι + +theorem isUnit_ι_of_isUnit {m : M} (h : IsUnit (Q m)) : IsUnit (ι Q m) := by + cases h.nonempty_invertible + letI := invertibleιOfInvertible Q m + exact isUnit_of_invertible (ι Q m) +#align clifford_algebra.is_unit_ι_of_is_unit CliffordAlgebra.isUnit_ι_of_isUnit + +/-- $aba^{-1}$ is a vector. -/ +theorem ι_mul_ι_mul_invOf_ι (a b : M) [Invertible (ι Q a)] [Invertible (Q a)] : + ι Q a * ι Q b * ⅟ (ι Q a) = ι Q ((⅟ (Q a) * QuadraticForm.polar Q a b) • a - b) := by + rw [invOf_ι, map_smul, mul_smul_comm, ι_mul_ι_mul_ι, ← map_smul, smul_sub, smul_smul, smul_smul, + invOf_mul_self, one_smul] +#align clifford_algebra.ι_mul_ι_mul_inv_of_ι CliffordAlgebra.ι_mul_ι_mul_invOf_ι + +/-- $a^{-1}ba$ is a vector. -/ +theorem invOf_ι_mul_ι_mul_ι (a b : M) [Invertible (ι Q a)] [Invertible (Q a)] : + ⅟ (ι Q a) * ι Q b * ι Q a = ι Q ((⅟ (Q a) * QuadraticForm.polar Q a b) • a - b) := by + rw [invOf_ι, map_smul, smul_mul_assoc, smul_mul_assoc, ι_mul_ι_mul_ι, ← map_smul, smul_sub, + smul_smul, smul_smul, invOf_mul_self, one_smul] +#align clifford_algebra.inv_of_ι_mul_ι_mul_ι CliffordAlgebra.invOf_ι_mul_ι_mul_ι + +end CliffordAlgebra From 1fb36f85fc99ac7291e8b2dd18c5291be53f1727 Mon Sep 17 00:00:00 2001 From: damiano Date: Sun, 17 Dec 2023 20:55:40 +0000 Subject: [PATCH 032/353] feat({ Tactic + test }/ComputeDegree): Add support for `hsmul` (#8666) This PR adds support for `smul` in `compute_degree`. [Zulip discussion](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/compute_total_degree/near/404468840) --- Mathlib/Tactic/ComputeDegree.lean | 12 ++++++++++++ test/ComputeDegree.lean | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/Mathlib/Tactic/ComputeDegree.lean b/Mathlib/Tactic/ComputeDegree.lean index 5ab9de971c149..92932a560ee1d 100644 --- a/Mathlib/Tactic/ComputeDegree.lean +++ b/Mathlib/Tactic/ComputeDegree.lean @@ -116,6 +116,16 @@ theorem coeff_pow_of_natDegree_le_of_eq_ite' [Semiring R] {m n o : ℕ} {a : R} · exact natDegree_pow_le_of_le m ‹_› · exact Iff.mp ne_comm h +theorem natDegree_smul_le_of_le {n : ℕ} {a : R} {f : R[X]} (hf : natDegree f ≤ n) : + natDegree (a • f) ≤ n := + (natDegree_smul_le a f).trans hf + +theorem degree_smul_le_of_le {n : ℕ} {a : R} {f : R[X]} (hf : degree f ≤ n) : + degree (a • f) ≤ n := + (degree_smul_le a f).trans hf + +theorem coeff_smul {n : ℕ} {a : R} {f : R[X]} : (a • f).coeff n = a * f.coeff n := rfl + section congr_lemmas /-- The following two lemmas should be viewed as a hand-made "congr"-lemmas. @@ -320,6 +330,8 @@ def dispatchLemma π ``natDegree_monomial_le ``degree_monomial_le ``coeff_monomial | .inr ``Polynomial.C => π ``natDegree_C_le ``degree_C_le ``coeff_C + | .inr ``HSMul.hSMul => + π ``natDegree_smul_le_of_le ``degree_smul_le_of_le ``coeff_smul | _ => π ``le_rfl ``le_rfl ``rfl /-- `try_rfl mvs` takes as input a list of `MVarId`s, scans them partitioning them into two diff --git a/test/ComputeDegree.lean b/test/ComputeDegree.lean index 3cf30c9a91e55..6c5e10d5d1d27 100644 --- a/test/ComputeDegree.lean +++ b/test/ComputeDegree.lean @@ -219,4 +219,13 @@ example {F} [Ring F] {a : F} : natDegree (X ^ 3 + C a * X ^ 10 : F[X]) ≤ 10 := example [Semiring R] : natDegree (7 * X : R[X]) ≤ 1 := by compute_degree +example [Semiring R] {a : R} : natDegree (a • X ^ 5 : R[X]) ≤ 5 := by + compute_degree + +example [Semiring R] {a : R} (a0 : a ≠ 0) : natDegree (a • X ^ 5 + X : R[X]) = 5 := by + compute_degree! + +example [Semiring R] {a : R} (a0 : a ≠ 0) : degree (a • X ^ 5 + X ^ 2 : R[X]) = 5 := by + compute_degree! + end tests_from_mathlib3 From d0dee32e9002017677346ad05fc6bd16e5d1c494 Mon Sep 17 00:00:00 2001 From: damiano Date: Sun, 17 Dec 2023 20:55:41 +0000 Subject: [PATCH 033/353] feat({ Tactic + test }/ComputeDegree): Add `monicity(!)?` (#8668) This PR adds a macro `monicity` for showing that a polynomial is `Monic` and the analogous `monicity!` macro that tries harder. [Zulip discussion](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/compute_total_degree/near/404491025) --- Mathlib/Tactic/ComputeDegree.lean | 13 +++++++++++++ test/ComputeDegree.lean | 3 +++ 2 files changed, 16 insertions(+) diff --git a/Mathlib/Tactic/ComputeDegree.lean b/Mathlib/Tactic/ComputeDegree.lean index 92932a560ee1d..1044c6b9db4df 100644 --- a/Mathlib/Tactic/ComputeDegree.lean +++ b/Mathlib/Tactic/ComputeDegree.lean @@ -478,6 +478,19 @@ elab_rules : tactic | `(tactic| compute_degree $[!%$bang]?) => focus <| withMain throwError Lean.MessageData.joinSep (m!"The given degree is '{deg}'. However,\n" :: errors) "\n" +/-- `monicity` tries to solve a goal of the form `Monic f`. +It converts the goal into a goal of the form `natDegree f ≤ n` and one of the form `f.coeff n = 1` +and calls `compute_degree` on those two goals. + +The variant `monicity!` starts like `monicity`, but calls `compute_degree!` on the two side-goals. +-/ +macro (name := monicityMacro) "monicity" : tactic => + `(tactic| (apply monic_of_natDegree_le_of_coeff_eq_one <;> compute_degree)) + +@[inherit_doc monicityMacro] +macro "monicity!" : tactic => + `(tactic| (apply monic_of_natDegree_le_of_coeff_eq_one <;> compute_degree!)) + end Tactic end Mathlib.Tactic.ComputeDegree diff --git a/test/ComputeDegree.lean b/test/ComputeDegree.lean index 6c5e10d5d1d27..3f4d209c9650f 100644 --- a/test/ComputeDegree.lean +++ b/test/ComputeDegree.lean @@ -154,6 +154,9 @@ example (h : n ≤ 5) : natDegree (monomial n (5 + n : R)) ≤ 5 := by compute_d -- Expr.fvar example {f : R[X]} : natDegree f ≤ natDegree f := by compute_degree +example {R} [Semiring R] [Nontrivial R] : Monic (1 * X ^ 5 + X ^ 6 * monomial 10 1 : R[X]) := by + monicity! + end native_mathlib4_tests section tests_from_mathlib3 From b067a6ffc212de78a0aa10f72a82e63788ee2f1b Mon Sep 17 00:00:00 2001 From: grunweg Date: Sun, 17 Dec 2023 20:55:42 +0000 Subject: [PATCH 034/353] feat: add Homeomorph.empty (#9092) This came up in #8160 and (independently) sphere-eversion. Co-authored-by: grunweg --- Mathlib/Topology/Homeomorph.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mathlib/Topology/Homeomorph.lean b/Mathlib/Topology/Homeomorph.lean index 54a38c1c0cbfa..7d7c46b4aa2ef 100644 --- a/Mathlib/Topology/Homeomorph.lean +++ b/Mathlib/Topology/Homeomorph.lean @@ -69,6 +69,10 @@ instance : CoeFun (X ≃ₜ Y) fun _ ↦ X → Y := ⟨FunLike.coe⟩ rfl #align homeomorph.homeomorph_mk_coe Homeomorph.homeomorph_mk_coe +/-- The unique homeomorphism between two empty types. -/ +protected def empty [IsEmpty X] [IsEmpty Y] : X ≃ₜ Y where + __ := Equiv.equivOfIsEmpty X Y + /-- Inverse of a homeomorphism. -/ protected def symm (h : X ≃ₜ Y) : Y ≃ₜ X where continuous_toFun := h.continuous_invFun From 4310b5835ccd3419abce829560f9e5b096a36935 Mon Sep 17 00:00:00 2001 From: Alex J Best Date: Sun, 17 Dec 2023 20:55:43 +0000 Subject: [PATCH 035/353] chore: fix linarith docs and test (#9127) --- Mathlib/Tactic/Linarith/Frontend.lean | 2 +- test/linarith.lean | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Tactic/Linarith/Frontend.lean b/Mathlib/Tactic/Linarith/Frontend.lean index 04b01eadfbbe6..79a270de231f7 100644 --- a/Mathlib/Tactic/Linarith/Frontend.lean +++ b/Mathlib/Tactic/Linarith/Frontend.lean @@ -351,7 +351,7 @@ optional arguments: problems. * `transparency` controls how hard `linarith` will try to match atoms to each other. By default it will only unfold `reducible` definitions. -* If `split_hypotheses` is true, `linarith` will split conjunctions in the context into separate +* If `splitHypotheses` is true, `linarith` will split conjunctions in the context into separate hypotheses. * If `splitNe` is `true`, `linarith` will case split on disequality hypotheses. For a given `x ≠ y` hypothesis, `linarith` is run with both `x < y` and `x > y`, diff --git a/test/linarith.lean b/test/linarith.lean index cb89b23fcd5f0..4a67985cb6734 100644 --- a/test/linarith.lean +++ b/test/linarith.lean @@ -192,7 +192,7 @@ by linarith (config := {exfalso := false}) example (x y : Rat) (h : 6 + ((x + 4) * x + (6 + 3 * y) * y) = 3 ∧ (x + 4) * x ≥ 0 ∧ (6 + 3 * y) * y ≥ 0) : False := by fail_if_success - linarith (config := {split_hypotheses := false}) + linarith (config := {splitHypotheses := false}) linarith example (h : 1 < 0) (g : ¬ 37 < 42) (k : True) (l : (-7 : ℤ) < 5) : 3 < 7 := by From 2362ccdf99c7488f470f9eff7e6533ef747348fc Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 17 Dec 2023 21:55:01 +0000 Subject: [PATCH 036/353] feat: make `mod_cases` work on Nat, in addition to Int (#3922) The current `mod_cases`, as implemented in #593, only works on integers. This pull request extends it to also work on natural numbers. --- Mathlib/Tactic/ModCases.lean | 136 +++++++++++++++++++++++++++++------ test/mod_cases.lean | 6 ++ 2 files changed, 119 insertions(+), 23 deletions(-) diff --git a/Mathlib/Tactic/ModCases.lean b/Mathlib/Tactic/ModCases.lean index 678b0feada813..97e2c05360ae9 100644 --- a/Mathlib/Tactic/ModCases.lean +++ b/Mathlib/Tactic/ModCases.lean @@ -7,14 +7,17 @@ import Mathlib.Data.Int.ModEq /-! # `mod_cases` tactic -The `mod_cases` tactic does case disjunction on `e % n`, where `e : ℤ`, to yield a number of -subgoals in which `e ≡ 0 [ZMOD n]`, ..., `e ≡ n-1 [ZMOD n]` are assumed. +The `mod_cases` tactic does case disjunction on `e % n`, where `e : ℤ` or `e : ℕ`, +to yield `n` new subgoals corresponding to the possible values of `e` modulo `n`. -/ set_option autoImplicit true namespace Mathlib.Tactic.ModCases -open Lean Meta Elab Tactic Term Qq Int +open Lean Meta Elab Tactic Term Qq + +namespace IntMod +open Int /-- `OnModCases n a lb p` represents a partial proof by cases that @@ -73,32 +76,119 @@ partial def proveOnModCases (n : Q(ℕ)) (a : Q(ℤ)) (b : Q(ℕ)) (p : Q(Sort u pure (q(onModCases_succ $b $g $pr), g.mvarId! :: acc) /-- -* The tactic `mod_cases h : e % 3` will perform a case disjunction on `e : ℤ` and yield subgoals - containing the assumptions `h : e ≡ 0 [ZMOD 3]`, `h : e ≡ 1 [ZMOD 3]`, `h : e ≡ 2 [ZMOD 3]` - respectively. +Int case of `mod_cases h : e % n`. +-/ +def modCases (h : TSyntax `Lean.binderIdent) (e : Q(ℤ)) (n : ℕ) : TacticM Unit := do + let ⟨u, p, g⟩ ← inferTypeQ (.mvar (← getMainGoal)) + have lit : Q(ℕ) := mkRawNatLit n + let p₁ : Nat.ble 1 $lit =Q true := ⟨⟩ + let (p₂, gs) ← proveOnModCases lit e (mkRawNatLit 0) p + let gs ← gs.mapM fun g => do + let (fvar, g) ← match h with + | `(binderIdent| $n:ident) => g.intro n.getId + | _ => g.intro `H + g.withContext <| (Expr.fvar fvar).addLocalVarInfoForBinderIdent h + pure g + g.mvarId!.assign q(onModCases_start $p $e $lit $p₁ $p₂) + replaceMainGoal gs + +end IntMod + +namespace NatMod + +/-- +`OnModCases n a lb p` represents a partial proof by cases that +there exists `0 ≤ m < n` such that `a ≡ m (mod n)`. +It asserts that if `∃ m, lb ≤ m < n ∧ a ≡ m (mod n)` holds, then `p` +(where `p` is the current goal). +-/ +def OnModCases (n : ℕ) (a : ℕ) (lb : ℕ) (p : Sort _) := +∀ m, lb ≤ m ∧ m < n ∧ a ≡ m [MOD n] → p + +/-- +The first theorem we apply says that `∃ m, 0 ≤ m < n ∧ a ≡ m (mod n)`. +The actual mathematical content of the proof is here. +-/ +@[inline] def onModCases_start (p : Sort _) (a : ℕ) (n : ℕ) (hn : Nat.ble 1 n = true) + (H : OnModCases n a (nat_lit 0) p) : p := + H (a % n) <| by + refine ⟨Nat.zero_le _, ?_, ?_⟩ + · exact Nat.mod_lt _ (Nat.le_of_ble_eq_true hn) + · rw [Nat.ModEq, Nat.mod_mod] + + +/-- +The end point is that once we have reduced to `∃ m, n ≤ m < n ∧ a ≡ m (mod n)` +there are no more cases to consider. +-/ +@[inline] def onModCases_stop (p : Sort _) (n : ℕ) (a : ℕ) : OnModCases n a n p := + fun _ h => (Nat.not_lt.2 h.1 h.2.1).elim + +/-- +The successor case decomposes `∃ m, b ≤ m < n ∧ a ≡ m (mod n)` into +`a ≡ b (mod n) ∨ ∃ m, b+1 ≤ m < n ∧ a ≡ m (mod n)`, +and the `a ≡ b (mod n) → p` case becomes a subgoal. +-/ +@[inline] def onModCases_succ {p : Sort _} {n : ℕ} {a : ℕ} (b : ℕ) + (h : a ≡ b [MOD n] → p) (H : OnModCases n a (Nat.add b 1) p) : + OnModCases n a b p := + fun z ⟨h₁, h₂⟩ => if e : b = z then h (e ▸ h₂.2) else H _ ⟨Nat.lt_of_le_of_ne h₁ e, h₂⟩ + +/-- +Proves an expression of the form `OnModCases n a b p` where `n` and `b` are raw nat literals +and `b ≤ n`. Returns the list of subgoals `?gi : a ≡ i [MOD n] → p`. +-/ +partial def proveOnModCases (n : Q(ℕ)) (a : Q(ℕ)) (b : Q(ℕ)) (p : Q(Sort u)) : + MetaM (Q(OnModCases $n $a $b $p) × List MVarId) := do + if n.natLit! ≤ b.natLit! then + pure ((q(onModCases_stop $p $n $a) : Expr), []) + else + let ty := q($a ≡ $b [MOD $n] → $p) + let g ← mkFreshExprMVarQ ty + let ((pr : Q(OnModCases $n $a (Nat.add $b 1) $p)), acc) ← + proveOnModCases n a (mkRawNatLit (b.natLit! + 1)) p + pure ((q(onModCases_succ $b $g $pr) : Expr), g.mvarId! :: acc) + +/-- +Nat case of `mod_cases h : e % n`. +-/ +def modCases (h : TSyntax `Lean.binderIdent) (e : Q(ℕ)) (n : ℕ) : TacticM Unit := do + let ⟨u, p, g⟩ ← inferTypeQ (.mvar (← getMainGoal)) + have lit : Q(ℕ) := mkRawNatLit n + let p₁ : Q(Nat.ble 1 $lit = true) := (q(Eq.refl true) : Expr) + let (p₂, gs) ← proveOnModCases lit e (mkRawNatLit 0) p + let gs ← gs.mapM fun g => do + let (fvar, g) ← match h with + | `(binderIdent| $n:ident) => g.intro n.getId + | _ => g.intro `H + g.withContext <| (Expr.fvar fvar).addLocalVarInfoForBinderIdent h + pure g + g.mvarId!.assign q(onModCases_start $p $e $lit $p₁ $p₂) + replaceMainGoal gs + +end NatMod + +/-- +* The tactic `mod_cases h : e % 3` will perform a case disjunction on `e`. + If `e : ℤ`, then it will yield subgoals containing the assumptions + `h : e ≡ 0 [ZMOD 3]`, `h : e ≡ 1 [ZMOD 3]`, `h : e ≡ 2 [ZMOD 3]` + respectively. If `e : ℕ` instead, then it works similarly, except with + `[MOD 3]` instead of `[ZMOD 3]`. * In general, `mod_cases h : e % n` works - when `n` is a positive numeral and `e` is an expression of type `ℤ`. + when `n` is a positive numeral and `e` is an expression of type `ℕ` or `ℤ`. * If `h` is omitted as in `mod_cases e % n`, it will be default-named `H`. -/ -syntax "mod_cases " (atomic(binderIdent " : "))? term:71 " % " num : tactic +syntax "mod_cases " (atomic(binderIdent ":"))? term:71 " % " num : tactic elab_rules : tactic | `(tactic| mod_cases $[$h :]? $e % $n) => do let n := n.getNat if n == 0 then Elab.throwUnsupportedSyntax - let g ← getMainGoal - g.withContext do - let ⟨u, p, g⟩ ← inferTypeQ (.mvar g) - let e : Q(ℤ) ← Tactic.elabTermEnsuringType e q(ℤ) let h := h.getD (← `(binderIdent| _)) - have lit : Q(ℕ) := mkRawNatLit n - let p₁ : Nat.ble 1 $lit =Q true := ⟨⟩ - let (p₂, gs) ← proveOnModCases lit e (mkRawNatLit 0) p - let gs ← gs.mapM fun g => do - let (fvar, g) ← match h with - | `(binderIdent| $n:ident) => g.intro n.getId - | _ => g.intro `H - g.withContext <| (Expr.fvar fvar).addLocalVarInfoForBinderIdent h - pure g - g.mvarId!.assign q(onModCases_start $p $e $lit $p₁ $p₂) - replaceMainGoal gs + withMainContext do + let e ← Tactic.elabTerm e none + let α : Q(Type) ← inferType e + match α with + | ~q(ℤ) => IntMod.modCases h e n + | ~q(ℕ) => NatMod.modCases h e n + | _ => throwError "mod_cases only works with Int and Nat" diff --git a/test/mod_cases.lean b/test/mod_cases.lean index f7393fc8e86db..d7d8292197519 100644 --- a/test/mod_cases.lean +++ b/test/mod_cases.lean @@ -7,6 +7,12 @@ example (n : ℤ) : 3 ∣ n ^ 3 - n := by · guard_hyp H :ₛ n ≡ 1 [ZMOD 3]; guard_target = 3 ∣ n ^ 3 - n; exact test_sorry · guard_hyp H :ₛ n ≡ 2 [ZMOD 3]; guard_target = 3 ∣ n ^ 3 - n; exact test_sorry +example (n : ℕ) : 3 ∣ n ^ 3 + n := by + mod_cases n % 3 + · guard_hyp H :~ n ≡ 0 [MOD 3]; guard_target = 3 ∣ n ^ 3 + n; exact test_sorry + · guard_hyp H :~ n ≡ 1 [MOD 3]; guard_target = 3 ∣ n ^ 3 + n; exact test_sorry + · guard_hyp H :~ n ≡ 2 [MOD 3]; guard_target = 3 ∣ n ^ 3 + n; exact test_sorry + -- test case for https://github.com/leanprover-community/mathlib4/issues/1851 example (n : ℕ) (z : ℤ) : n = n := by induction n with From 7b1f933b5de3846a1559b3061b166fe19b9163cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Dupuis?= Date: Sun, 17 Dec 2023 21:55:03 +0000 Subject: [PATCH 037/353] feat: positivity extension for zpow (#8003) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a positivity extension for integer powers, i.e. `a ^ (r : ℤ)`. It's basically copy-pasted from the natural power extension. Note that this makes the imports of `Mathlib.Tactic.Positivity.Basic` slightly heavier since the required lemmas were not there (and the relevant file doesn't import positivity so I couldn't put it there either). It's probably not too bad, but I can put it in a new file if people think this would be better. Co-authored-by: David Renshaw --- .../Analysis/SpecialFunctions/Bernstein.lean | 1 - .../Covering/Differentiation.lean | 1 - Mathlib/Tactic/Positivity/Basic.lean | 54 ++++++++++++++++++- test/positivity.lean | 7 +-- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean index 11b25b4bee846..29acf116dd222 100644 --- a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean +++ b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean @@ -236,7 +236,6 @@ theorem bernsteinApproximation_uniform (f : C(I, ℝ)) : filter_upwards [nhds_zero.eventually (gt_mem_nhds (half_pos h)), eventually_gt_atTop 0] with n nh npos' have npos : 0 < (n : ℝ) := by positivity - have w₂ : 0 ≤ δ ^ (-2:ℤ) := zpow_neg_two_nonneg _ -- TODO: need a positivity extension for `zpow` -- As `[0,1]` is compact, it suffices to check the inequality pointwise. rw [ContinuousMap.norm_lt_iff _ h] intro x diff --git a/Mathlib/MeasureTheory/Covering/Differentiation.lean b/Mathlib/MeasureTheory/Covering/Differentiation.lean index 7358f734bdfbb..392596f7e5807 100644 --- a/Mathlib/MeasureTheory/Covering/Differentiation.lean +++ b/Mathlib/MeasureTheory/Covering/Differentiation.lean @@ -587,7 +587,6 @@ theorem withDensity_le_mul {s : Set α} (hs : MeasurableSet s) {t : ℝ≥0} (ht zpow_add₀ t_ne_zero'] conv_rhs => rw [← mul_one (t ^ n)] gcongr - · apply NNReal.zpow_pos t_ne_zero' -- TODO: positivity extension for `zpow` rw [zpow_neg_one] exact inv_lt_one ht calc diff --git a/Mathlib/Tactic/Positivity/Basic.lean b/Mathlib/Tactic/Positivity/Basic.lean index 6840ce0ca5e46..3a5d3b0b9c8cc 100644 --- a/Mathlib/Tactic/Positivity/Basic.lean +++ b/Mathlib/Tactic/Positivity/Basic.lean @@ -13,7 +13,7 @@ import Mathlib.Data.Rat.Cast.Order import Mathlib.Tactic.Positivity.Core import Mathlib.Tactic.HaveI import Mathlib.Algebra.GroupPower.Order -import Mathlib.Algebra.Order.Field.Basic +import Mathlib.Algebra.Order.Field.Power import Qq /-! @@ -376,6 +376,58 @@ def evalPow : PositivityExt where eval {u α} zα pα e := do | .nonzero pa => ofNonzero pa (← synthInstanceQ (_ : Q(Type u))) | .none => pure .none +/-- The `positivity` extension which identifies expressions of the form `a ^ (b : ℤ)`, +such that `positivity` successfully recognises both `a` and `b`. -/ +@[positivity (_ : α) ^ (_ : ℤ), Pow.pow _ (_ : ℤ)] +def evalZpow : PositivityExt where eval {u α} zα pα e := do + let .app (.app _ (a : Q($α))) (b : Q(ℤ)) ← withReducible (whnf e) | throwError "not ^" + let result ← catchNone do + let _a ← synthInstanceQ q(LinearOrderedField $α) + assumeInstancesCommute + match ← whnfR b with + | .app (.app (.app (.const `OfNat.ofNat _) _) (.lit (Literal.natVal n))) _ => + guard (n % 2 = 0) + have m : Q(ℕ) := mkRawNatLit (n / 2) + haveI' : $b =Q $m + $m := ⟨⟩ -- b = bit0 m + haveI' : $e =Q $a ^ $b := ⟨⟩ + pure (by exact .nonnegative q(zpow_bit0_nonneg $a $m)) + | .app (.app (.app (.const `Neg.neg _) _) _) b' => + let b' ← whnfR b' + let .true := b'.isAppOfArity ``OfNat.ofNat 3 | throwError "not a ^ -n where n is a literal" + let some n := (b'.getRevArg! 1).natLit? | throwError "not a ^ -n where n is a literal" + guard (n % 2 = 0) + have m : Q(ℕ) := mkRawNatLit (n / 2) + haveI' : $b =Q (-$m) + (-$m) := ⟨⟩ -- b = bit0 (-m) + haveI' : $e =Q $a ^ $b := ⟨⟩ + pure (by exact .nonnegative q(zpow_bit0_nonneg $a (-$m))) + | _ => throwError "not a ^ n where n is a literal or a negated literal" + orElse result do + let ra ← core zα pα a + let ofNonneg (pa : Q(0 ≤ $a)) (_oα : Q(LinearOrderedSemifield $α)) : + MetaM (Strictness zα pα e) := do + haveI' : $e =Q $a ^ $b := ⟨⟩ + assumeInstancesCommute + pure (by exact .nonnegative (q(zpow_nonneg $pa $b))) + let ofNonzero (pa : Q($a ≠ 0)) (_oα : Q(GroupWithZero $α)) : MetaM (Strictness zα pα e) := do + haveI' : $e =Q $a ^ $b := ⟨⟩ + let _a ← synthInstanceQ q(GroupWithZero $α) + assumeInstancesCommute + pure (.nonzero (by exact q(zpow_ne_zero $b $pa))) + match ra with + | .positive pa => + try + let _a ← synthInstanceQ (q(LinearOrderedSemifield $α) : Q(Type u)) + haveI' : $e =Q $a ^ $b := ⟨⟩ + assumeInstancesCommute + pure (by exact .positive (q(zpow_pos_of_pos $pa $b))) + catch e : Exception => + trace[Tactic.positivity.failure] "{e.toMessageData}" + let oα ← synthInstanceQ q(LinearOrderedSemifield $α) + orElse (← catchNone (ofNonneg q(le_of_lt $pa) oα)) (ofNonzero q(ne_of_gt $pa) oα) + | .nonnegative pa => ofNonneg pa (← synthInstanceQ (_ : Q(Type u))) + | .nonzero pa => ofNonzero pa (← synthInstanceQ (_ : Q(Type u))) + | .none => pure .none + private theorem abs_pos_of_ne_zero {α : Type*} [AddGroup α] [LinearOrder α] [CovariantClass α α (·+·) (·≤·)] {a : α} : a ≠ 0 → 0 < |a| := abs_pos.mpr diff --git a/test/positivity.lean b/test/positivity.lean index 028cdba4cb6eb..bd5451621f0dd 100644 --- a/test/positivity.lean +++ b/test/positivity.lean @@ -179,9 +179,10 @@ example [OrderedSemiring α] {a : α} {n : ℕ} (ha : 0 ≤ a) : 0 ≤ a ^ n := example [StrictOrderedSemiring α] {a : α} {n : ℕ} (ha : 0 < a) : 0 < a ^ n := by positivity example [LinearOrderedSemifield α] (a : α) : 0 < a ^ (0 : ℤ) := by positivity --- example [LinearOrderedField α] (a : α) (n : ℤ) : 0 ≤ a ^ bit0 n := by positivity --- example [LinearOrderedSemifield α] {a : α} {n : ℤ} (ha : 0 ≤ a) : 0 ≤ a ^ n := by positivity --- example [LinearOrderedSemifield α] {a : α} {n : ℤ} (ha : 0 < a) : 0 < a ^ n := by positivity +example [LinearOrderedField α] (a : α) : 0 ≤ a ^ (18 : ℤ) := by positivity +example [LinearOrderedField α] (a : α) : 0 ≤ a ^ (-34 : ℤ) := by positivity +example [LinearOrderedSemifield α] {a : α} {n : ℤ} (ha : 0 ≤ a) : 0 ≤ a ^ n := by positivity +example [LinearOrderedSemifield α] {a : α} {n : ℤ} (ha : 0 < a) : 0 < a ^ n := by positivity -- example {a b : Cardinal.{u}} (ha : 0 < a) : 0 < a ^ b := by positivity -- example {a b : Ordinal.{u}} (ha : 0 < a) : 0 < a ^ b := by positivity From c9df7640930f132aa92ed6bc5dbe0a3eb11b0516 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 17 Dec 2023 21:55:04 +0000 Subject: [PATCH 038/353] chore: various style improvements in positivity extensions (#8098) - match with ~q() - put type ascriptions inline --- Mathlib/Tactic/Positivity/Basic.lean | 50 +++++++++++----------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/Mathlib/Tactic/Positivity/Basic.lean b/Mathlib/Tactic/Positivity/Basic.lean index 3a5d3b0b9c8cc..7ef1b4b58a3f0 100644 --- a/Mathlib/Tactic/Positivity/Basic.lean +++ b/Mathlib/Tactic/Positivity/Basic.lean @@ -238,25 +238,17 @@ where `a` and `b` are integers. -/ let ra ← core zα pα a; let rb ← core zα pα b guard <|← withDefault <| withNewMCtxDepth <| isDefEq f q(HDiv.hDiv (α := ℤ) (β := ℤ)) match ra, rb with - | .positive pa, .positive pb => - have pa' : Q(0 < $a) := pa - have pb' : Q(0 < $b) := pb + | .positive (pa : Q(0 < $a)), .positive (pb : Q(0 < $b)) => if pa == pb then -- Only attempts to prove `0 < a / a`, otherwise falls back to `0 ≤ a / b` - pure (.positive (q(int_div_self_pos $pa') : Expr)) + pure (.positive (q(int_div_self_pos $pa) : Expr)) else - pure (.nonnegative (q(int_div_nonneg_of_pos_of_pos $pa' $pb') : Expr)) - | .positive pa, .nonnegative pb => - have pa' : Q(0 < $a) := pa - have pb' : Q(0 ≤ $b) := pb - pure (.nonnegative (q(int_div_nonneg_of_pos_of_nonneg $pa' $pb') : Expr)) - | .nonnegative pa, .positive pb => - have pa' : Q(0 ≤ $a) := pa - have pb' : Q(0 < $b) := pb - pure (.nonnegative (q(int_div_nonneg_of_nonneg_of_pos $pa' $pb') : Expr)) - | .nonnegative pa, .nonnegative pb => - have pa' : Q(0 ≤ $a) := pa - have pb' : Q(0 ≤ $b) := pb - pure (.nonnegative (q(Int.ediv_nonneg $pa' $pb') : Expr)) + pure (.nonnegative (q(int_div_nonneg_of_pos_of_pos $pa $pb) : Expr)) + | .positive (pa : Q(0 < $a)), .nonnegative (pb : Q(0 ≤ $b)) => + pure (.nonnegative (q(int_div_nonneg_of_pos_of_nonneg $pa $pb) : Expr)) + | .nonnegative (pa : Q(0 ≤ $a)), .positive (pb : Q(0 < $b)) => + pure (.nonnegative (q(int_div_nonneg_of_nonneg_of_pos $pa $pb) : Expr)) + | .nonnegative (pa : Q(0 ≤ $a)), .nonnegative (pb : Q(0 ≤ $b)) => + pure (.nonnegative (q(Int.ediv_nonneg $pa $pb) : Expr)) | _, _ => pure .none section LinearOrderedSemifield @@ -433,8 +425,8 @@ private theorem abs_pos_of_ne_zero {α : Type*} [AddGroup α] [LinearOrder α] /-- The `positivity` extension which identifies expressions of the form `|a|`. -/ @[positivity |(_ : α)|] -def evalAbs : PositivityExt where eval {_ _α} zα pα e := do - let (.app _ (a : Q($_α))) ← withReducible (whnf e) | throwError "not |·|" +def evalAbs : PositivityExt where eval {u} (α : Q(Type u)) zα pα (e : Q($α)) := do + let ~q(@Abs.abs _ (_) $a) := e | throwError "not |·|" try match ← core zα pα a with | .positive pa => @@ -456,8 +448,8 @@ Since the output type of `Int.natAbs` is `ℕ`, the nonnegative case is handled `positivity` tactic. -/ @[positivity Int.natAbs _] -def evalNatAbs : PositivityExt where eval {_u _α} _zα _pα e := do - let (.app _ (a : Q(Int))) ← withReducible (whnf e) | throwError "not Int.natAbs" +def evalNatAbs : PositivityExt where eval {_u _α} _zα _pα (e : Q(ℕ)) := do + let ~q(Int.natAbs $a) := e | throwError "not Int.natAbs" let zα' : Q(Zero Int) := q(inferInstance) let pα' : Q(PartialOrder Int) := q(inferInstance) let ra ← core zα' pα' a @@ -473,14 +465,13 @@ def evalNatAbs : PositivityExt where eval {_u _α} _zα _pα e := do @[positivity Nat.cast _] def evalNatCast : PositivityExt where eval {u α} _zα _pα e := do - let (.app _ (a : Q(Nat))) ← withReducible (whnf e) | throwError "not Nat.cast" + let ~q(@Nat.cast _ (_) ($a : ℕ)) := e | throwError "not Nat.cast" let zα' : Q(Zero Nat) := q(inferInstance) let pα' : Q(PartialOrder Nat) := q(inferInstance) - let ra ← core zα' pα' a - let _oα ← synthInstanceQ q(OrderedSemiring $α) + let (_oα : Q(OrderedSemiring $α)) ← synthInstanceQ q(OrderedSemiring $α) haveI' : $e =Q Nat.cast $a := ⟨⟩ assumeInstancesCommute - match ra with + match ← core zα' pα' a with | .positive pa => let _nt ← synthInstanceQ q(Nontrivial $α) pure (.positive q(Nat.cast_pos.mpr $pa)) @@ -489,7 +480,7 @@ def evalNatCast : PositivityExt where eval {u α} _zα _pα e := do @[positivity Int.cast _] def evalIntCast : PositivityExt where eval {u α} _zα _pα e := do - let (.app _ (a : Q(Int))) ← withReducible (whnf e) | throwError "not Int.cast" + let ~q(@Int.cast _ (_) ($a : ℤ)) := e | throwError "not Int.cast" let zα' : Q(Zero Int) := q(inferInstance) let pα' : Q(PartialOrder Int) := q(inferInstance) let ra ← core zα' pα' a @@ -518,8 +509,7 @@ def evalIntCast : PositivityExt where eval {u α} _zα _pα e := do /-- Extension for Rat.cast. -/ @[positivity Rat.cast _] def evalRatCast : PositivityExt where eval {u α} _zα _pα e := do - let _rα : Q(RatCast $α) ← synthInstanceQ (q(RatCast $α)) - let ~q(Rat.cast ($a : ℚ)) := e | throwError "not Rat.cast" + let ~q(@Rat.cast _ (_) ($a : ℚ)) := e | throwError "not Rat.cast" let zα' : Q(Zero ℚ) := q(inferInstance) let pα' : Q(PartialOrder ℚ) := q(inferInstance) match ← core zα' pα' a with @@ -537,8 +527,8 @@ def evalRatCast : PositivityExt where eval {u α} _zα _pα e := do /-- Extension for Nat.succ. -/ @[positivity Nat.succ _] -def evalNatSucc : PositivityExt where eval {_u _α} _zα _pα e := do - let (.app _ (a : Q(Nat))) ← withReducible (whnf e) | throwError "not Nat.succ" +def evalNatSucc : PositivityExt where eval {_u _α} _zα _pα (e : Q(ℕ)) := do + let ~q(Nat.succ $a) := e | throwError "not Nat.succ" pure (.positive (q(Nat.succ_pos $a) : Expr)) /-- Extension for Nat.factorial. -/ From 4bb736fa10db3a87645dee2d41670e474c0624fd Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 17 Dec 2023 21:55:04 +0000 Subject: [PATCH 039/353] refactor(Testing/SlimCheck/Sampleable): Qq-ify (#8857) This makes things a little less fragile to refactors, as the types are checked up front. It also means we get better error messages. --- Mathlib/Testing/SlimCheck/Sampleable.lean | 32 +++++++++++++---------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/Mathlib/Testing/SlimCheck/Sampleable.lean b/Mathlib/Testing/SlimCheck/Sampleable.lean index b580a2d1f7525..97b2fb3892a85 100644 --- a/Mathlib/Testing/SlimCheck/Sampleable.lean +++ b/Mathlib/Testing/SlimCheck/Sampleable.lean @@ -288,18 +288,20 @@ def printSamples {t : Type} [Repr t] (g : Gen t) : IO PUnit := do open Lean Meta Qq /-- Create a `Gen α` expression from the argument of `#sample` -/ -def mkGenerator (e : Expr) : MetaM (Expr × Expr) := do - let t ← inferType e - match t.getAppFnArgs with - | (`Gen, #[t]) => do - let repr_inst ← synthInstance (← mkAppM ``Repr #[t]) - pure (repr_inst, e) - | _ => do - let sampleableExt_inst ← synthInstance (mkApp (← mkConstWithFreshMVarLevels ``SampleableExt) e) - let repr_inst ← mkAppOptM ``SampleableExt.proxyRepr #[e, sampleableExt_inst] - let gen ← mkAppOptM ``SampleableExt.sample #[none, sampleableExt_inst] - pure (repr_inst, gen) - +def mkGenerator (e : Expr) : MetaM (Σ (u : Level) (α : Q(Type $u)), Q(Repr $α) × Q(Gen $α)) := do + match ← inferTypeQ e with + | ⟨.succ u, ~q(Gen $α), gen⟩ => + let repr_inst ← synthInstanceQ (q(Repr $α) : Q(Type $u)) + pure ⟨u, α, repr_inst, gen⟩ + | ⟨.succ u, ~q(Sort u), α⟩ => do + let v ← mkFreshLevelMVar + let _sampleableExt_inst ← synthInstanceQ (q(SampleableExt.{u,v} $α) : Q(Sort (max u (v + 2)))) + let v ← instantiateLevelMVars v + let repr_inst := q(SampleableExt.proxyRepr (α := $α)) + let gen := q(SampleableExt.sample (α := $α)) + pure ⟨v, q(SampleableExt.proxy $α), repr_inst, gen⟩ + | ⟨_u, t, _e⟩ => + throwError "Must be a Sort u` or a `Gen α`, got value of type{indentExpr t}" open Elab /-- @@ -339,8 +341,10 @@ values of type `type` using an increasing size parameter. elab "#sample " e:term : command => Command.runTermElabM fun _ => do let e ← Elab.Term.elabTermAndSynthesize e none - let (repr_inst, gen) ← mkGenerator e - let printSamples ← mkAppOptM ``printSamples #[none, repr_inst, gen] + let g ← mkGenerator e + -- `printSamples` only works in `Type 0` (see the porting note) + let ⟨0, α, _, gen⟩ := g | throwError "Cannot sample from {g.1} due to its universe" + let printSamples := q(printSamples (t := $α) $gen) let code ← unsafe evalExpr (IO PUnit) q(IO PUnit) printSamples _ ← code From 27b7e3e706fdb739a59f4b18652bfbbf4110320f Mon Sep 17 00:00:00 2001 From: Markus Himmel Date: Sun, 17 Dec 2023 21:55:06 +0000 Subject: [PATCH 040/353] feat: add `CharP.natCast_eq_natCast_mod` and relax typeclass assumptions (#9050) --- Mathlib/Algebra/CharP/Basic.lean | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/Mathlib/Algebra/CharP/Basic.lean b/Mathlib/Algebra/CharP/Basic.lean index 442eacdc5f895..5df7a76e492ee 100644 --- a/Mathlib/Algebra/CharP/Basic.lean +++ b/Mathlib/Algebra/CharP/Basic.lean @@ -145,12 +145,30 @@ theorem CharP.intCast_eq_intCast [AddGroupWithOne R] (p : ℕ) [CharP R p] {a b rw [eq_comm, ← sub_eq_zero, ← Int.cast_sub, CharP.int_cast_eq_zero_iff R p, Int.modEq_iff_dvd] #align char_p.int_cast_eq_int_cast CharP.intCast_eq_intCast -theorem CharP.natCast_eq_natCast [AddGroupWithOne R] (p : ℕ) [CharP R p] {a b : ℕ} : - (a : R) = b ↔ a ≡ b [MOD p] := by - rw [← Int.cast_ofNat, ← Int.cast_ofNat b] - exact (CharP.intCast_eq_intCast _ _).trans Int.coe_nat_modEq_iff +theorem CharP.natCast_eq_natCast' [AddMonoidWithOne R] (p : ℕ) [CharP R p] {a b : ℕ} + (h : a ≡ b [MOD p]) : (a : R) = b := by + wlog hle : a ≤ b + · exact (this R p h.symm (le_of_not_le hle)).symm + rw [Nat.modEq_iff_dvd' hle] at h + rw [← Nat.sub_add_cancel hle, Nat.cast_add, (CharP.cast_eq_zero_iff R p _).mpr h, zero_add] + +theorem CharP.natCast_eq_natCast [AddMonoidWithOne R] [IsRightCancelAdd R] (p : ℕ) [CharP R p] + {a b : ℕ} : (a : R) = b ↔ a ≡ b [MOD p] := by + wlog hle : a ≤ b + · rw [eq_comm, this R p (le_of_not_le hle), Nat.ModEq.comm] + rw [Nat.modEq_iff_dvd' hle, ← CharP.cast_eq_zero_iff R p (b - a), + ← add_right_cancel_iff (G := R) (a := a) (b := b - a), zero_add, ← Nat.cast_add, + Nat.sub_add_cancel hle, eq_comm] #align char_p.nat_cast_eq_nat_cast CharP.natCast_eq_natCast +theorem CharP.intCast_eq_intCast_mod [AddGroupWithOne R] (p : ℕ) [CharP R p] {a : ℤ} : + (a : R) = a % (p : ℤ) := + (CharP.intCast_eq_intCast R p).mpr (Int.mod_modEq a p).symm + +theorem CharP.natCast_eq_natCast_mod [AddMonoidWithOne R] (p : ℕ) [CharP R p] {a : ℕ} : + (a : R) = a % p := + CharP.natCast_eq_natCast' R p (Nat.mod_modEq a p).symm + theorem CharP.eq [AddMonoidWithOne R] {p q : ℕ} (_c1 : CharP R p) (_c2 : CharP R q) : p = q := Nat.dvd_antisymm ((CharP.cast_eq_zero_iff R p q).1 (CharP.cast_eq_zero _ _)) ((CharP.cast_eq_zero_iff R q p).1 (CharP.cast_eq_zero _ _)) From 079c7b46c4841995e4060325cf4fb335d3f63c2b Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sun, 17 Dec 2023 21:55:07 +0000 Subject: [PATCH 041/353] chore(Set/NAry): fix docstring, golf (#9059) - Fix the module docstring of `Data.Set.NAry`. It looks like it was copied from `Data.Finset.NAry` while synchronizing the files. - Golf some proofs. --- Mathlib/Data/Set/NAry.lean | 40 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/Mathlib/Data/Set/NAry.lean b/Mathlib/Data/Set/NAry.lean index c60dd9b7deaee..e162a2aa89e33 100644 --- a/Mathlib/Data/Set/NAry.lean +++ b/Mathlib/Data/Set/NAry.lean @@ -10,19 +10,19 @@ import Mathlib.Data.Set.Prod /-! # N-ary images of sets -This file defines `Set.image2`, the binary image of finsets. This is the finset version of -`Set.image2`. This is mostly useful to define pointwise operations. +This file defines `Set.image2`, the binary image of sets. +This is mostly useful to define pointwise operations and `Set.seq`. ## Notes -This file is very similar to the n-ary section of `Data.Set.Basic`, to `Order.Filter.NAry` and to +This file is very similar to `Data.Finset.NAry`, to `Order.Filter.NAry`, and to `Data.Option.NAry`. Please keep them in sync. -We do not define `Set.image3` as its only purpose would be to prove properties of `Set.image2` -and `Set.image2` already fulfills this task. +We also define `Set.image3`. +Its only purpose is to prove properties of `Set.image2`, +and it should be rarely used outside of this file. -/ - open Function namespace Set @@ -122,11 +122,7 @@ theorem image2_swap (s : Set α) (t : Set β) : image2 f s t = image2 (fun a b = variable {f} theorem image2_union_left : image2 f (s ∪ s') t = image2 f s t ∪ image2 f s' t := by - ext c - constructor - · rintro ⟨a, b, ha | ha, hb, rfl⟩ <;> [left; right] <;> exact ⟨_, _, ‹_›, ‹_›, rfl⟩ - · rintro (⟨_, _, _, _, rfl⟩ | ⟨_, _, _, _, rfl⟩) <;> refine' ⟨_, _, _, ‹_›, rfl⟩ <;> - simp [mem_union, *] + simp_rw [← image_prod, union_prod, image_union] #align set.image2_union_left Set.image2_union_left theorem image2_union_right : image2 f s (t ∪ t') = image2 f s t ∪ image2 f s t' := by @@ -181,14 +177,12 @@ theorem Subsingleton.image2 (hs : s.Subsingleton) (ht : t.Subsingleton) (f : α rw [← image_prod] apply (hs.prod ht).image -theorem image2_inter_subset_left : image2 f (s ∩ s') t ⊆ image2 f s t ∩ image2 f s' t := by - rintro _ ⟨a, b, ⟨h1a, h2a⟩, hb, rfl⟩ - constructor <;> exact ⟨_, _, ‹_›, ‹_›, rfl⟩ +theorem image2_inter_subset_left : image2 f (s ∩ s') t ⊆ image2 f s t ∩ image2 f s' t := + Monotone.map_inf_le (fun _ _ ↦ image2_subset_right) s s' #align set.image2_inter_subset_left Set.image2_inter_subset_left -theorem image2_inter_subset_right : image2 f s (t ∩ t') ⊆ image2 f s t ∩ image2 f s t' := by - rintro _ ⟨a, b, ha, ⟨h1b, h2b⟩, rfl⟩ - constructor <;> exact ⟨_, _, ‹_›, ‹_›, rfl⟩ +theorem image2_inter_subset_right : image2 f s (t ∩ t') ⊆ image2 f s t ∩ image2 f s t' := + Monotone.map_inf_le (fun _ _ ↦ image2_subset_left) t t' #align set.image2_inter_subset_right Set.image2_inter_subset_right @[simp] @@ -285,20 +279,12 @@ theorem image_image2 (f : α → β → γ) (g : γ → δ) : theorem image2_image_left (f : γ → β → δ) (g : α → γ) : image2 f (g '' s) t = image2 (fun a b => f (g a) b) s t := by - ext; constructor - · rintro ⟨_, b, ⟨a, ha, rfl⟩, hb, rfl⟩ - refine' ⟨a, b, ha, hb, rfl⟩ - · rintro ⟨a, b, ha, hb, rfl⟩ - refine' ⟨_, b, ⟨a, ha, rfl⟩, hb, rfl⟩ + ext; simp #align set.image2_image_left Set.image2_image_left theorem image2_image_right (f : α → γ → δ) (g : β → γ) : image2 f s (g '' t) = image2 (fun a b => f a (g b)) s t := by - ext; constructor - · rintro ⟨a, _, ha, ⟨b, hb, rfl⟩, rfl⟩ - refine' ⟨a, b, ha, hb, rfl⟩ - · rintro ⟨a, b, ha, hb, rfl⟩ - refine' ⟨a, _, ha, ⟨b, hb, rfl⟩, rfl⟩ + ext; simp #align set.image2_image_right Set.image2_image_right @[simp] From fad7cd8739e81f40f02832afafbcebffa8c9c0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sun, 17 Dec 2023 21:55:08 +0000 Subject: [PATCH 042/353] =?UTF-8?q?feat:=20`exp=20(t=20*=20x)=20=E2=89=A4?= =?UTF-8?q?=20cosh=20x=20+=20t=20*=20sinh=20x`=20(#9097)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From LeanAPAP --- .../Analysis/Convex/SpecificFunctions/Basic.lean | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean index a3b4003a04041..662229221fc00 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean @@ -216,3 +216,16 @@ theorem strictConcaveOn_log_Iio : StrictConcaveOn ℝ (Iio 0) log := by _ = _ := by rw [log_neg_eq_log] #align strict_concave_on_log_Iio strictConcaveOn_log_Iio + +namespace Real + +lemma exp_mul_le_cosh_add_mul_sinh {t : ℝ} (ht : |t| ≤ 1) (x : ℝ) : + exp (t * x) ≤ cosh x + t * sinh x := by + rw [abs_le] at ht + calc + _ = exp ((1 + t) / 2 * x + (1 - t) / 2 * (-x)) := by ring_nf + _ ≤ (1 + t) / 2 * exp x + (1 - t) / 2 * exp (-x) := + convexOn_exp.2 (Set.mem_univ _) (Set.mem_univ _) (by linarith) (by linarith) $ by ring + _ = _ := by rw [cosh_eq, sinh_eq]; ring + +end Real From 91ef688973668efe254feafcee68735cd956acb9 Mon Sep 17 00:00:00 2001 From: Thomas Browning Date: Sun, 17 Dec 2023 23:08:30 +0000 Subject: [PATCH 043/353] feat(Data/Polynomial/RingDivision): Negation lemmas for `roots`, `aroots`, and `rootSet` (#9133) This PR adds negation lemmas for `roots`, `aroots`, and `rootSet`. --- Mathlib/Data/Polynomial/RingDivision.lean | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Mathlib/Data/Polynomial/RingDivision.lean b/Mathlib/Data/Polynomial/RingDivision.lean index f5ba2515d7bb5..f6aec117ed4ed 100644 --- a/Mathlib/Data/Polynomial/RingDivision.lean +++ b/Mathlib/Data/Polynomial/RingDivision.lean @@ -784,6 +784,10 @@ theorem roots_smul_nonzero (p : R[X]) (ha : a ≠ 0) : (a • p).roots = p.roots rw [smul_eq_C_mul, roots_C_mul _ ha] #align polynomial.roots_smul_nonzero Polynomial.roots_smul_nonzero +@[simp] +lemma roots_neg (p : R[X]) : (-p).roots = p.roots := by + rw [← neg_one_smul R p, roots_smul_nonzero p (neg_ne_zero.mpr one_ne_zero)] + theorem roots_list_prod (L : List R[X]) : (0 : R[X]) ∉ L → L.prod.roots = (L : Multiset R[X]).bind roots := List.recOn L (fun _ => roots_one) fun hd tl ih H => by @@ -1062,6 +1066,11 @@ theorem aroots_one [CommRing S] [IsDomain S] [Algebra T S] : (1 : T[X]).aroots S = 0 := aroots_C 1 +@[simp] +theorem aroots_neg [CommRing S] [IsDomain S] [Algebra T S] (p : T[X]) : + (-p).aroots S = p.aroots S := + by rw [aroots, Polynomial.map_neg, roots_neg] + @[simp] theorem aroots_C_mul [CommRing S] [IsDomain S] [Algebra T S] [NoZeroSMulDivisors T S] {a : T} (p : T[X]) (ha : a ≠ 0) : @@ -1123,6 +1132,15 @@ theorem rootSet_zero (S) [CommRing S] [IsDomain S] [Algebra T S] : (0 : T[X]).ro rw [← C_0, rootSet_C] #align polynomial.root_set_zero Polynomial.rootSet_zero +@[simp] +theorem rootSet_one (S) [CommRing S] [IsDomain S] [Algebra T S] : (1 : T[X]).rootSet S = ∅ := by + rw [← C_1, rootSet_C] + +@[simp] +theorem rootSet_neg (p : T[X]) (S) [CommRing S] [IsDomain S] [Algebra T S] : + (-p).rootSet S = p.rootSet S := by + rw [rootSet, aroots_neg, rootSet] + instance rootSetFintype (p : T[X]) (S : Type*) [CommRing S] [IsDomain S] [Algebra T S] : Fintype (p.rootSet S) := FinsetCoe.fintype _ From eda0f8d332cf9d189519ad097a6fe7f1a6b01d19 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Sun, 17 Dec 2023 23:56:58 +0000 Subject: [PATCH 044/353] fix: use colGt in `#help` parser (#9128) Fixes #9126. The parsers had to be split into a separate `syntax` declaration to allow for the `withPosition` combinator to set the position so that `colGt` works as intended. Co-authored-by: Mario Carneiro --- Mathlib/Tactic/HelpCmd.lean | 64 +++++++++++++++++++++++++++---------- test/help_cmd.lean | 6 ++++ 2 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 test/help_cmd.lean diff --git a/Mathlib/Tactic/HelpCmd.lean b/Mathlib/Tactic/HelpCmd.lean index f706e7282f595..11a979baf8953 100644 --- a/Mathlib/Tactic/HelpCmd.lean +++ b/Mathlib/Tactic/HelpCmd.lean @@ -41,7 +41,9 @@ it will appear as a `(currently: true)` note next to the option. The form `#help option id` will show only options that begin with `id`. -/ -elab "#help " &"option" id:(ppSpace Parser.rawIdent)? : command => do +syntax withPosition("#help " colGt &"option" (colGt ppSpace Parser.rawIdent)?) : command + +private def elabHelpOption (id : Option Ident) : CommandElabM Unit := do let id := id.map (·.raw.getId.toString false) let mut decls : Lean.RBMap _ _ compare := {} for (name, decl) in show Lean.RBMap .. from ← getOptionDecls do @@ -69,6 +71,8 @@ elab "#help " &"option" id:(ppSpace Parser.rawIdent)? : command => do msg := msg ++ .nest 2 (f!"option {name} : {msg1}" ++ .line ++ decl.descr) ++ .line ++ .line logInfo msg +elab_rules : command | `(#help option $(id)?) => elabHelpOption id + /-- The command `#help attribute` (or the short form `#help attr`) shows all attributes that have been defined in the current environment. @@ -83,7 +87,10 @@ as the docstring will be displayed here. The form `#help attr id` will show only attributes that begin with `id`. -/ -elab "#help " (&"attr" <|> &"attribute") id:(ppSpace Parser.rawIdent)? : command => do +syntax withPosition("#help " colGt (&"attr" <|> &"attribute") + (colGt ppSpace Parser.rawIdent)?) : command + +private def elabHelpAttr (id : Option Ident) : CommandElabM Unit := do let id := id.map (·.raw.getId.toString false) let mut decls : Lean.RBMap _ _ compare := {} for (name, decl) in ← attributeMapRef.get do @@ -105,6 +112,10 @@ elab "#help " (&"attr" <|> &"attribute") id:(ppSpace Parser.rawIdent)? : command msg := msg ++ .nest 2 msg1 ++ .line ++ .line logInfo msg +elab_rules : command + | `(#help attr $(id)?) => elabHelpAttr id + | `(#help attribute $(id)?) => elabHelpAttr id + /-- Gets the initial string token in a parser description. For example, for a declaration like `syntax "bla" "baz" term : tactic`, it returns `some "bla"`. Returns `none` for syntax declarations that don't start with a string constant. -/ @@ -136,7 +147,9 @@ but you can click to go to the definition.) It also shows the doc string if avai The form `#help cats id` will show only syntax categories that begin with `id`. -/ -elab "#help " &"cats" id:(ppSpace Parser.rawIdent)? : command => do +syntax withPosition("#help " colGt &"cats" (colGt ppSpace Parser.rawIdent)?) : command + +private def elabHelpCats (id : Option Ident) : CommandElabM Unit := do let id := id.map (·.raw.getId.toString false) let mut decls : Lean.RBMap _ _ compare := {} for (name, cat) in (Parser.parserExtension.getState (← getEnv)).categories do @@ -158,6 +171,8 @@ elab "#help " &"cats" id:(ppSpace Parser.rawIdent)? : command => do msg := msg ++ .nest 2 msg1 ++ (.line ++ .line : Format) logInfo msg +elab_rules : command | `(#help cats $(id)?) => elabHelpCats id + /-- The command `#help cat C` shows all syntaxes that have been defined in syntax category `C` in the current environment. @@ -173,11 +188,11 @@ name of the syntax (which you can also click to go to the definition), and the d * The form `#help cat+ C` will also show information about any `macro`s and `elab`s associated to the listed syntaxes. -/ -elab "#help " &"cat" more:"+"? ppSpace catStx:ident - id:(ppSpace (Parser.rawIdent <|> str))? : command => do - let id := id.map fun id ↦ match id.raw with - | .ident _ _ v _ => v.toString false - | id => id.isStrLit?.get! +syntax withPosition("#help " colGt &"cat" "+"? colGt ident + (colGt ppSpace (Parser.rawIdent <|> str))?) : command + +private def elabHelpCat (more : Option Syntax) (catStx : Ident) (id : Option String) : + CommandElabM Unit := do let mut decls : Lean.RBMap _ _ compare := {} let mut rest : Lean.RBMap _ _ compare := {} let catName := catStx.getId.eraseMacroScopes @@ -231,30 +246,47 @@ elab "#help " &"cat" more:"+"? ppSpace catStx:ident msg ← addMsg k msg m!"syntax ... [{mkConst k}]" logInfo msg +elab_rules : command + | `(#help cat $[+%$more]? $cat) => elabHelpCat more cat none + | `(#help cat $[+%$more]? $cat $id:ident) => elabHelpCat more cat (id.getId.toString false) + | `(#help cat $[+%$more]? $cat $id:str) => elabHelpCat more cat id.getString + /-- The command `#help term` shows all term syntaxes that have been defined in the current environment. See `#help cat` for more information. -/ -macro "#help " tk:&"term" more:"+"? id:(ppSpace (Parser.rawIdent <|> str))? : command => - `(#help cat$[+%$more]? $(mkIdentFrom tk `term) $(id.map (⟨·.raw⟩))?) +syntax withPosition("#help " colGt &"term" "+"? + (colGt ppSpace (Parser.rawIdent <|> str))?) : command +macro_rules + | `(#help term%$tk $[+%$more]? $(id)?) => + `(#help cat$[+%$more]? $(mkIdentFrom tk `term) $(id)?) /-- The command `#help tactic` shows all tactics that have been defined in the current environment. See `#help cat` for more information. -/ -macro "#help " tk:&"tactic" more:"+"? id:(ppSpace (Parser.rawIdent <|> str))? : command => do - `(#help cat$[+%$more]? $(mkIdentFrom tk `tactic) $(id.map (⟨·.raw⟩))?) +syntax withPosition("#help " colGt &"tactic" "+"? + (colGt ppSpace (Parser.rawIdent <|> str))?) : command +macro_rules + | `(#help tactic%$tk $[+%$more]? $(id)?) => + `(#help cat$[+%$more]? $(mkIdentFrom tk `tactic) $(id)?) /-- The command `#help conv` shows all tactics that have been defined in the current environment. See `#help cat` for more information. -/ -macro "#help " tk:&"conv" more:"+"? id:(ppSpace (Parser.rawIdent <|> str))? : command => - `(#help cat$[+%$more]? $(mkIdentFrom tk `conv) $(id.map (⟨·.raw⟩))?) +syntax withPosition("#help " colGt &"conv" "+"? + (colGt ppSpace (Parser.rawIdent <|> str))?) : command +macro_rules + | `(#help conv%$tk $[+%$more]? $(id)?) => + `(#help cat$[+%$more]? $(mkIdentFrom tk `conv) $(id)?) /-- The command `#help command` shows all commands that have been defined in the current environment. See `#help cat` for more information. -/ -macro "#help " tk:&"command" more:"+"? id:(ppSpace (Parser.rawIdent <|> str))? : command => - `(#help cat$[+%$more]? $(mkIdentFrom tk `command) $(id.map (⟨·.raw⟩))?) +syntax withPosition("#help " colGt &"command" "+"? + (colGt ppSpace (Parser.rawIdent <|> str))?) : command +macro_rules + | `(#help command%$tk $[+%$more]? $(id)?) => + `(#help cat$[+%$more]? $(mkIdentFrom tk `command) $(id)?) diff --git a/test/help_cmd.lean b/test/help_cmd.lean new file mode 100644 index 0000000000000..710dd1ac512b5 --- /dev/null +++ b/test/help_cmd.lean @@ -0,0 +1,6 @@ +import Mathlib.Tactic.HelpCmd +import Std.Tactic.GuardMsgs + +#guard_msgs(error, drop info) in +#help tactic +def foo := 1 From bca1c69de4d55d65bdb4ed4cde23b5d68b2f2fd2 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Mon, 18 Dec 2023 01:08:32 +0000 Subject: [PATCH 045/353] feat: define `NonUnital(Semi)NormedCommRing` (#8664) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds commutative versions of the existing `NonUnital(Semi)NormedRing` classes. This is essential for talking about, for example, non-unital commutative C⋆-algebras. --- Mathlib/Analysis/Normed/Field/Basic.lean | 99 ++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/Mathlib/Analysis/Normed/Field/Basic.lean b/Mathlib/Analysis/Normed/Field/Basic.lean index 426ecac3abf1a..7dc7ac0acaa57 100644 --- a/Mathlib/Analysis/Normed/Field/Basic.lean +++ b/Mathlib/Analysis/Normed/Field/Basic.lean @@ -101,6 +101,24 @@ instance (priority := 100) NormedRing.toNonUnitalNormedRing [β : NormedRing α] { β with } #align normed_ring.to_non_unital_normed_ring NormedRing.toNonUnitalNormedRing +/-- A non-unital seminormed commutative ring is a non-unital commutative ring endowed with a +seminorm which satisfies the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/ +class NonUnitalSeminormedCommRing (α : Type*) extends NonUnitalSeminormedRing α where + /-- Multiplication is commutative. -/ + mul_comm : ∀ x y : α, x * y = y * x + +/-- A non-unital normed commutative ring is a non-unital commutative ring endowed with a +norm which satisfies the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/ +class NonUnitalNormedCommRing (α : Type*) extends NonUnitalNormedRing α where + /-- Multiplication is commutative. -/ + mul_comm : ∀ x y : α, x * y = y * x + +-- see Note [lower instance priority] +/-- A non-unital normed commutative ring is a non-unital seminormed commutative ring. -/ +instance (priority := 100) NonUnitalNormedCommRing.toNonUnitalSeminormedCommRing + [β : NonUnitalNormedCommRing α] : NonUnitalSeminormedCommRing α := + { β with } + /-- A seminormed commutative ring is a commutative ring endowed with a seminorm which satisfies the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/ class SeminormedCommRing (α : Type*) extends SeminormedRing α where @@ -115,6 +133,18 @@ class NormedCommRing (α : Type*) extends NormedRing α where mul_comm : ∀ x y : α, x * y = y * x #align normed_comm_ring NormedCommRing +-- see Note [lower instance priority] +/-- A seminormed commutative ring is a non-unital seminormed commutative ring. -/ +instance (priority := 100) SeminormedCommRing.toNonUnitalSeminormedCommRing + [β : SeminormedCommRing α] : NonUnitalSeminormedCommRing α := + { β with } + +-- see Note [lower instance priority] +/-- A normed commutative ring is a non-unital normed commutative ring. -/ +instance (priority := 100) NormedCommRing.toNonUnitalNormedCommRing + [β : NormedCommRing α] : NonUnitalNormedCommRing α := + { β with } + -- see Note [lower instance priority] /-- A normed commutative ring is a seminormed commutative ring. -/ instance (priority := 100) NormedCommRing.toSeminormedCommRing [β : NormedCommRing α] : @@ -147,6 +177,11 @@ theorem NormOneClass.nontrivial (α : Type*) [SeminormedAddCommGroup α] [One α nontrivial_of_ne 0 1 <| ne_of_apply_ne norm <| by simp #align norm_one_class.nontrivial NormOneClass.nontrivial +-- see Note [lower instance priority] +instance (priority := 100) NonUnitalSeminormedCommRing.toNonUnitalCommRing + [β : NonUnitalSeminormedCommRing α] : NonUnitalCommRing α := + { β with } + -- see Note [lower instance priority] instance (priority := 100) SeminormedCommRing.toCommRing [β : SeminormedCommRing α] : CommRing α := { β with } @@ -463,6 +498,53 @@ instance MulOpposite.normedRing : NormedRing αᵐᵒᵖ := end NormedRing +section NonUnitalSeminormedCommRing + +variable [NonUnitalSeminormedCommRing α] + +instance ULift.nonUnitalSeminormedCommRing : NonUnitalSeminormedCommRing (ULift α) := + { ULift.nonUnitalSeminormedRing, ULift.nonUnitalCommRing with } + +/-- Non-unital seminormed commutative ring structure on the product of two non-unital seminormed +commutative rings, using the sup norm. -/ +instance Prod.nonUnitalSeminormedCommRing [NonUnitalSeminormedCommRing β] : + NonUnitalSeminormedCommRing (α × β) := + { nonUnitalSeminormedRing, instNonUnitalCommRing with } + +/-- Non-unital seminormed commutative ring structure on the product of finitely many non-unital +seminormed commutative rings, using the sup norm. -/ +instance Pi.nonUnitalSeminormedCommRing {π : ι → Type*} [Fintype ι] + [∀ i, NonUnitalSeminormedCommRing (π i)] : NonUnitalSeminormedCommRing (∀ i, π i) := + { Pi.nonUnitalSeminormedRing, Pi.nonUnitalCommRing with } + +instance MulOpposite.nonUnitalSeminormedCommRing : NonUnitalSeminormedCommRing αᵐᵒᵖ := + { MulOpposite.nonUnitalSeminormedRing, MulOpposite.nonUnitalCommRing α with } + +end NonUnitalSeminormedCommRing +section NonUnitalNormedCommRing + +variable [NonUnitalNormedCommRing α] + +instance ULift.nonUnitalNormedCommRing : NonUnitalNormedCommRing (ULift α) := + { ULift.nonUnitalSeminormedCommRing, ULift.normedAddCommGroup with } + +/-- Non-unital normed commutative ring structure on the product of two non-unital normed +commutative rings, using the sup norm. -/ +instance Prod.nonUnitalNormedCommRing [NonUnitalNormedCommRing β] : + NonUnitalNormedCommRing (α × β) := + { Prod.nonUnitalSeminormedCommRing, Prod.normedAddCommGroup with } + +/-- Normed commutative ring structure on the product of finitely many non-unital normed +commutative rings, using the sup norm. -/ +instance Pi.nonUnitalNormedCommRing {π : ι → Type*} [Fintype ι] + [∀ i, NonUnitalNormedCommRing (π i)] : NonUnitalNormedCommRing (∀ i, π i) := + { Pi.nonUnitalSeminormedCommRing, Pi.normedAddCommGroup with } + +instance MulOpposite.nonUnitalNormedCommRing : NonUnitalNormedCommRing αᵐᵒᵖ := + { MulOpposite.nonUnitalSeminormedCommRing, MulOpposite.normedAddCommGroup with } + +end NonUnitalNormedCommRing + -- see Note [lower instance priority] instance (priority := 100) semi_normed_ring_top_monoid [NonUnitalSeminormedRing α] : ContinuousMul α := @@ -1021,6 +1103,23 @@ def NormedRing.induced [Ring R] [NormedRing S] [NonUnitalRingHomClass F R S] (f { NonUnitalSeminormedRing.induced R S f, NormedAddCommGroup.induced R S f hf, ‹Ring R› with } #align normed_ring.induced NormedRing.induced +/-- A non-unital ring homomorphism from a `NonUnitalCommRing` to a `NonUnitalSeminormedCommRing` +induces a `NonUnitalSeminormedCommRing` structure on the domain. + +See note [reducible non-instances] -/ +@[reducible] +def NonUnitalSeminormedCommRing.induced [NonUnitalCommRing R] [NonUnitalSeminormedCommRing S] + [NonUnitalRingHomClass F R S] (f : F) : NonUnitalSeminormedCommRing R := + { NonUnitalSeminormedRing.induced R S f, ‹NonUnitalCommRing R› with } + +/-- An injective non-unital ring homomorphism from a `NonUnitalCommRing` to a +`NonUnitalNormedCommRing` induces a `NonUnitalNormedCommRing` structure on the domain. + +See note [reducible non-instances] -/ +@[reducible] +def NonUnitalNormedCommRing.induced [NonUnitalCommRing R] [NonUnitalNormedCommRing S] + [NonUnitalRingHomClass F R S] (f : F) (hf : Function.Injective f) : NonUnitalNormedCommRing R := + { NonUnitalNormedRing.induced R S f hf, ‹NonUnitalCommRing R› with } /-- A non-unital ring homomorphism from a `CommRing` to a `SeminormedRing` induces a `SeminormedCommRing` structure on the domain. From 6a04469e1985e23b35ede9b6e228bdb8b61b293e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Degenne?= Date: Mon, 18 Dec 2023 01:51:44 +0000 Subject: [PATCH 046/353] =?UTF-8?q?feat:=20properties=20of=20`x=20?= =?UTF-8?q?=E2=86=A6=20-=20x=20*=20log=20x`=20(#8922)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Continuity, concavity, first two derivatives of `x ↦ - x * log x`. From the PFR project. Co-authored-by: Eric Wieser Co-authored-by: Rémy Degenne --- Mathlib.lean | 1 + .../SpecialFunctions/Log/NegMulLog.lean | 133 ++++++++++++++++++ .../SpecialFunctions/Pow/Asymptotics.lean | 14 ++ 3 files changed, 148 insertions(+) create mode 100644 Mathlib/Analysis/SpecialFunctions/Log/NegMulLog.lean diff --git a/Mathlib.lean b/Mathlib.lean index 5f206e8dc6c81..e999eb305e2e5 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -870,6 +870,7 @@ import Mathlib.Analysis.SpecialFunctions.Log.Base import Mathlib.Analysis.SpecialFunctions.Log.Basic import Mathlib.Analysis.SpecialFunctions.Log.Deriv import Mathlib.Analysis.SpecialFunctions.Log.Monotone +import Mathlib.Analysis.SpecialFunctions.Log.NegMulLog import Mathlib.Analysis.SpecialFunctions.NonIntegrable import Mathlib.Analysis.SpecialFunctions.PolarCoord import Mathlib.Analysis.SpecialFunctions.PolynomialExp diff --git a/Mathlib/Analysis/SpecialFunctions/Log/NegMulLog.lean b/Mathlib/Analysis/SpecialFunctions/Log/NegMulLog.lean new file mode 100644 index 0000000000000..066f81e187631 --- /dev/null +++ b/Mathlib/Analysis/SpecialFunctions/Log/NegMulLog.lean @@ -0,0 +1,133 @@ +/- +Copyright (c) 2023 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +import Mathlib.Analysis.SpecialFunctions.Log.Deriv +import Mathlib.Analysis.SpecialFunctions.Pow.Asymptotics + +/-! +# The function `x ↦ - x * log x` + +The purpose of this file is to record basic analytic properties of the function `x ↦ - x * log x`, +which is notably used in the theory of Shannon entropy. + +## Main definitions + +* `negMulLog`: the function `x ↦ - x * log x` from `ℝ` to `ℝ`. + +-/ + +open scoped Topology + +namespace Real + +lemma continuous_mul_log : Continuous fun x ↦ x * log x := by + rw [continuous_iff_continuousAt] + intro x + obtain hx | rfl := ne_or_eq x 0 + · exact (continuous_id'.continuousAt).mul (continuousAt_log hx) + rw [ContinuousAt, zero_mul] + simp_rw [mul_comm _ (log _)] + nth_rewrite 1 [← nhdsWithin_univ] + have : (Set.univ : Set ℝ) = Set.Iio 0 ∪ Set.Ioi 0 ∪ {0} := by ext; simp [em] + rw [this, nhdsWithin_union, nhdsWithin_union] + simp only [nhdsWithin_singleton, sup_le_iff, Filter.nonpos_iff, Filter.tendsto_sup] + refine ⟨⟨tendsto_log_mul_self_nhds_zero_left, ?_⟩, ?_⟩ + · simpa only [rpow_one] using tendsto_log_mul_rpow_nhds_zero zero_lt_one + · convert tendsto_pure_nhds (fun x ↦ log x * x) 0 + simp + +lemma differentiableOn_mul_log : DifferentiableOn ℝ (fun x ↦ x * log x) {0}ᶜ := + differentiable_id'.differentiableOn.mul differentiableOn_log + +lemma deriv_mul_log {x : ℝ} (hx : x ≠ 0) : deriv (fun x ↦ x * log x) x = log x + 1 := by + rw [deriv_mul differentiableAt_id' (differentiableAt_log hx)] + simp only [deriv_id'', one_mul, deriv_log', ne_eq, add_right_inj] + exact mul_inv_cancel hx + +lemma hasDerivAt_mul_log {x : ℝ} (hx : x ≠ 0) : HasDerivAt (fun x ↦ x * log x) (log x + 1) x := by + rw [← deriv_mul_log hx, hasDerivAt_deriv_iff] + refine DifferentiableOn.differentiableAt differentiableOn_mul_log ?_ + simp [hx] + +lemma deriv2_mul_log {x : ℝ} (hx : x ≠ 0) : deriv^[2] (fun x ↦ x * log x) x = x⁻¹ := by + simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id, + Function.comp_apply] + suffices ∀ᶠ y in (𝓝 x), deriv (fun x ↦ x * log x) y = log y + 1 by + refine (Filter.EventuallyEq.deriv_eq this).trans ?_ + rw [deriv_add_const, deriv_log x] + filter_upwards [eventually_ne_nhds hx] with y hy using deriv_mul_log hy + +lemma strictConvexOn_mul_log : StrictConvexOn ℝ (Set.Ici (0 : ℝ)) (fun x ↦ x * log x) := by + refine strictConvexOn_of_deriv2_pos (convex_Ici 0) (continuous_mul_log.continuousOn) ?_ + intro x hx + simp only [Set.nonempty_Iio, interior_Ici', Set.mem_Ioi] at hx + rw [deriv2_mul_log hx.ne'] + positivity + +lemma convexOn_mul_log : ConvexOn ℝ (Set.Ici (0 : ℝ)) (fun x ↦ x * log x) := + strictConvexOn_mul_log.convexOn + +lemma mul_log_nonneg {x : ℝ} (hx : 1 ≤ x) : 0 ≤ x * log x := + mul_nonneg (zero_le_one.trans hx) (log_nonneg hx) + +lemma mul_log_nonpos {x : ℝ} (hx₀ : 0 ≤ x) (hx₁ : x ≤ 1) : x * log x ≤ 0 := + mul_nonpos_of_nonneg_of_nonpos hx₀ (log_nonpos hx₀ hx₁) + +section negMulLog + +/-- The function `x ↦ - x * log x` from `ℝ` to `ℝ`. -/ +noncomputable def negMulLog (x : ℝ) : ℝ := - x * log x + +lemma negMulLog_def : negMulLog = fun x ↦ - x * log x := rfl + +lemma negMulLog_eq_neg : negMulLog = fun x ↦ - (x * log x) := by simp [negMulLog_def] + +@[simp] lemma negMulLog_zero : negMulLog (0 : ℝ) = 0 := by simp [negMulLog] + +@[simp] lemma negMulLog_one : negMulLog (1 : ℝ) = 0 := by simp [negMulLog] + +lemma negMulLog_nonneg {x : ℝ} (h1 : 0 ≤ x) (h2 : x ≤ 1) : 0 ≤ negMulLog x := by + simpa only [negMulLog_eq_neg, neg_nonneg] using mul_log_nonpos h1 h2 + +lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negMulLog y := by + simp only [negMulLog, neg_mul, neg_add_rev] + by_cases hx : x = 0 + · simp [hx] + by_cases hy : y = 0 + · simp [hy] + rw [log_mul hx hy] + ring + +lemma continuous_negMulLog : Continuous negMulLog := by + simpa only [negMulLog_eq_neg] using continuous_mul_log.neg + +lemma differentiableOn_negMulLog : DifferentiableOn ℝ negMulLog {0}ᶜ := by + simpa only [negMulLog_eq_neg] using differentiableOn_mul_log.neg + +lemma deriv_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv negMulLog x = - log x - 1 := by + rw [negMulLog_eq_neg, deriv.neg, deriv_mul_log hx] + ring + +lemma hasDerivAt_negMulLog {x : ℝ} (hx : x ≠ 0) : HasDerivAt negMulLog (- log x - 1) x := by + rw [← deriv_negMulLog hx, hasDerivAt_deriv_iff] + refine DifferentiableOn.differentiableAt differentiableOn_negMulLog ?_ + simp [hx] + +lemma deriv2_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv^[2] negMulLog x = - x⁻¹ := by + rw [negMulLog_eq_neg] + have h := deriv2_mul_log hx + simp only [Function.iterate_succ, Function.iterate_zero, Function.comp.left_id, + Function.comp_apply, deriv.neg', differentiableAt_id', differentiableAt_log_iff, ne_eq] at h ⊢ + rw [h] + +lemma strictConcaveOn_negMulLog : StrictConcaveOn ℝ (Set.Ici (0 : ℝ)) negMulLog := by + simpa only [negMulLog_eq_neg] using strictConvexOn_mul_log.neg + +lemma concaveOn_negMulLog : ConcaveOn ℝ (Set.Ici (0 : ℝ)) negMulLog := + strictConcaveOn_negMulLog.concaveOn + +end negMulLog + +end Real diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean index 39f42c5b2e481..515844e618e49 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean @@ -380,3 +380,17 @@ theorem tendsto_log_mul_rpow_nhds_zero {r : ℝ} (hr : 0 < r) : (tendsto_log_div_rpow_nhds_zero <| neg_lt_zero.2 hr).congr' <| eventually_mem_nhdsWithin.mono fun x hx => by rw [rpow_neg hx.out.le, div_inv_eq_mul] #align tendsto_log_mul_rpow_nhds_zero tendsto_log_mul_rpow_nhds_zero + +lemma tendsto_log_mul_self_nhds_zero_left : Filter.Tendsto (fun x ↦ log x * x) (𝓝[<] 0) (𝓝 0) := by + have h := tendsto_log_mul_rpow_nhds_zero zero_lt_one + simp only [Real.rpow_one] at h + have h_eq : ∀ x ∈ Set.Iio 0, (- (fun x ↦ log x * x) ∘ (fun x ↦ |x|)) x = log x * x := by + simp only [Set.mem_Iio, Pi.neg_apply, Function.comp_apply, log_abs] + intro x hx + simp only [abs_of_nonpos hx.le, mul_neg, neg_neg] + refine tendsto_nhdsWithin_congr h_eq ?_ + nth_rewrite 3 [← neg_zero] + refine (h.comp (tendsto_abs_nhdsWithin_zero.mono_left ?_)).neg + refine nhdsWithin_mono 0 (fun x hx ↦ ?_) + simp only [Set.mem_Iio] at hx + simp only [Set.mem_compl_iff, Set.mem_singleton_iff, hx.ne, not_false_eq_true] From 3f7c7ee0f7842bd559b25a389fafd0f4f481fc6b Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 18 Dec 2023 04:13:57 +0000 Subject: [PATCH 047/353] feat: the graded tensor product (#7394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the graded tensor product $A \hat\otimes_R B$, imbued with a multiplication defined on homogeneous tensors by: $$(a \hat\otimes b) \cdot (a' \hat\otimes b') = (-1)^{\deg a' \deg b} (a \cdot a') \hat\otimes (b \cdot b')$$ where $A$ and $B$ are algebras graded by `ℕ`, `ℤ`, or `ZMod 2` (or more generally, any index that satisfies `Module ι (Additive ℤˣ)`). We do this in two phases: * Define bundled morphisms that perform the multiplication and braiding maps on regular tensor products of `DirectSum`s * Define a new `GradedTensorProduct` type synonym that attaches the multiplication operator to `*` notation, and restricts itself to internally-graded algebras. --- Mathlib.lean | 2 + .../TensorProduct/Graded/External.lean | 263 ++++++++++++ .../TensorProduct/Graded/Internal.lean | 380 ++++++++++++++++++ Mathlib/RingTheory/TensorProduct.lean | 5 +- 4 files changed, 649 insertions(+), 1 deletion(-) create mode 100644 Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean create mode 100644 Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean diff --git a/Mathlib.lean b/Mathlib.lean index e999eb305e2e5..35cad24521ea9 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2478,6 +2478,8 @@ import Mathlib.LinearAlgebra.TensorAlgebra.Grading import Mathlib.LinearAlgebra.TensorAlgebra.ToTensorPower import Mathlib.LinearAlgebra.TensorPower import Mathlib.LinearAlgebra.TensorProduct +import Mathlib.LinearAlgebra.TensorProduct.Graded.External +import Mathlib.LinearAlgebra.TensorProduct.Graded.Internal import Mathlib.LinearAlgebra.TensorProduct.Matrix import Mathlib.LinearAlgebra.TensorProduct.Opposite import Mathlib.LinearAlgebra.TensorProduct.Prod diff --git a/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean b/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean new file mode 100644 index 0000000000000..0d2eefaed5243 --- /dev/null +++ b/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean @@ -0,0 +1,263 @@ +/- +Copyright (c) 2023 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.Data.Int.Order.Units +import Mathlib.Data.ZMod.IntUnitsPower +import Mathlib.RingTheory.TensorProduct +import Mathlib.LinearAlgebra.DirectSum.TensorProduct +import Mathlib.Algebra.DirectSum.Algebra + +/-! +# Graded tensor products over graded algebras + +The graded tensor product $A \hat\otimes_R B$ is imbued with a multiplication defined on homogeneous +tensors by: + +$$(a \otimes b) \cdot (a' \otimes b') = (-1)^{\deg a' \deg b} (a \cdot a') \otimes (b \cdot b')$$ + +where $A$ and $B$ are algebras graded by `ℕ`, `ℤ`, or `ZMod 2` (or more generally, any index +that satisfies `Module ι (Additive ℤˣ)`). + +The results for internally-graded algebras (via `GradedAlgebra`) are elsewhere, as is the type +`GradedTensorProduct`. + +## Main results + +* `TensorProduct.gradedComm`: the symmetric braiding operator on the tensor product of + externally-graded rings. +* `TensorProduct.gradedMul`: the previously-described multiplication on externally-graded rings, as + a bilinear map. + +## Implementation notes + +Rather than implementing the multiplication directly as above, we first implement the canonical +non-trivial braiding sending $a \otimes b$ to $(-1)^{\deg a' \deg b} (b \otimes a)$, as the +multiplication follows trivially from this after some point-free nonsense. + +## References + +* https://math.stackexchange.com/q/202718/1896 +* [*Algebra I*, Bourbaki : Chapter III, §4.7, example (2)][bourbaki1989] + +-/ + +suppress_compilation + +open scoped TensorProduct DirectSum + +variable {R ι A B : Type*} + +namespace TensorProduct + +variable [CommSemiring ι] [Module ι (Additive ℤˣ)] [DecidableEq ι] +variable (𝒜 : ι → Type*) (ℬ : ι → Type*) +variable [CommRing R] +variable [∀ i, AddCommGroup (𝒜 i)] [∀ i, AddCommGroup (ℬ i)] +variable [∀ i, Module R (𝒜 i)] [∀ i, Module R (ℬ i)] +variable [DirectSum.GRing 𝒜] [DirectSum.GRing ℬ] +variable [DirectSum.GAlgebra R 𝒜] [DirectSum.GAlgebra R ℬ] + +-- this helps with performance +instance (i : ι × ι) : Module R (𝒜 (Prod.fst i) ⊗[R] ℬ (Prod.snd i)) := + TensorProduct.leftModule + +open DirectSum (lof) + +variable (R) + +section gradedComm + +local notation "𝒜ℬ" => (fun i : ι × ι => 𝒜 (Prod.fst i) ⊗[R] ℬ (Prod.snd i)) +local notation "ℬ𝒜" => (fun i : ι × ι => ℬ (Prod.fst i) ⊗[R] 𝒜 (Prod.snd i)) + +/-- Auxliary construction used to build `TensorProduct.gradedComm`. + +This operates on direct sums of tensors instead of tensors of direct sums. -/ +def gradedCommAux : DirectSum _ 𝒜ℬ →ₗ[R] DirectSum _ ℬ𝒜 := by + refine DirectSum.toModule R _ _ fun i => ?_ + have o := DirectSum.lof R _ ℬ𝒜 i.swap + have s : ℤˣ := ((-1 : ℤˣ)^(i.1* i.2 : ι) : ℤˣ) + exact (s • o) ∘ₗ (TensorProduct.comm R _ _).toLinearMap + +@[simp] +theorem gradedCommAux_lof_tmul (i j : ι) (a : 𝒜 i) (b : ℬ j) : + gradedCommAux R 𝒜 ℬ (lof R _ 𝒜ℬ (i, j) (a ⊗ₜ b)) = + (-1 : ℤˣ)^(j * i) • lof R _ ℬ𝒜 (j, i) (b ⊗ₜ a) := by + rw [gradedCommAux] + dsimp + simp [mul_comm i j] + +@[simp] +theorem gradedCommAux_comp_gradedCommAux : + gradedCommAux R 𝒜 ℬ ∘ₗ gradedCommAux R ℬ 𝒜 = LinearMap.id := by + ext i a b + dsimp + rw [gradedCommAux_lof_tmul, LinearMap.map_smul_of_tower, gradedCommAux_lof_tmul, smul_smul, + mul_comm i.2 i.1, Int.units_mul_self, one_smul] + +/-- The braiding operation for tensor products of externally `ι`-graded algebras. + +This sends $a ⊗ b$ to $(-1)^{\deg a' \deg b} (b ⊗ a)$. -/ +def gradedComm : + (⨁ i, 𝒜 i) ⊗[R] (⨁ i, ℬ i) ≃ₗ[R] (⨁ i, ℬ i) ⊗[R] (⨁ i, 𝒜 i) := by + refine TensorProduct.directSum R 𝒜 ℬ ≪≫ₗ ?_ ≪≫ₗ (TensorProduct.directSum R ℬ 𝒜).symm + exact LinearEquiv.ofLinear (gradedCommAux _ _ _) (gradedCommAux _ _ _) + (gradedCommAux_comp_gradedCommAux _ _ _) (gradedCommAux_comp_gradedCommAux _ _ _) + +/-- The braiding is symmetric. -/ +@[simp] +theorem gradedComm_symm : (gradedComm R 𝒜 ℬ).symm = gradedComm R ℬ 𝒜 := by + rw [gradedComm, gradedComm, LinearEquiv.trans_symm, LinearEquiv.symm_symm] + ext + rfl + +theorem gradedComm_of_tmul_of (i j : ι) (a : 𝒜 i) (b : ℬ j) : + gradedComm R 𝒜 ℬ (lof R _ 𝒜 i a ⊗ₜ lof R _ ℬ j b) = + (-1 : ℤˣ)^(j * i) • (lof R _ ℬ _ b ⊗ₜ lof R _ 𝒜 _ a) := by + rw [gradedComm] + dsimp only [LinearEquiv.trans_apply, LinearEquiv.ofLinear_apply] + rw [TensorProduct.directSum_lof_tmul_lof, gradedCommAux_lof_tmul, Units.smul_def, + zsmul_eq_smul_cast R, map_smul, TensorProduct.directSum_symm_lof_tmul, + ← zsmul_eq_smul_cast, ← Units.smul_def] + +theorem gradedComm_tmul_of_zero (a : ⨁ i, 𝒜 i) (b : ℬ 0) : + gradedComm R 𝒜 ℬ (a ⊗ₜ lof R _ ℬ 0 b) = lof R _ ℬ _ b ⊗ₜ a := by + suffices + (gradedComm R 𝒜 ℬ).toLinearMap ∘ₗ + (TensorProduct.mk R (⨁ i, 𝒜 i) (⨁ i, ℬ i)).flip (lof R _ ℬ 0 b) = + TensorProduct.mk R _ _ (lof R _ ℬ 0 b) from + FunLike.congr_fun this a + ext i a + dsimp + rw [gradedComm_of_tmul_of, zero_mul, uzpow_zero, one_smul] + +theorem gradedComm_of_zero_tmul (a : 𝒜 0) (b : ⨁ i, ℬ i) : + gradedComm R 𝒜 ℬ (lof R _ 𝒜 0 a ⊗ₜ b) = b ⊗ₜ lof R _ 𝒜 _ a := by + suffices + (gradedComm R 𝒜 ℬ).toLinearMap ∘ₗ (TensorProduct.mk R (⨁ i, 𝒜 i) (⨁ i, ℬ i)) (lof R _ 𝒜 0 a) = + (TensorProduct.mk R _ _).flip (lof R _ 𝒜 0 a) from + FunLike.congr_fun this b + ext i b + dsimp + rw [gradedComm_of_tmul_of, mul_zero, uzpow_zero, one_smul] + +theorem gradedComm_tmul_one (a : ⨁ i, 𝒜 i) : gradedComm R 𝒜 ℬ (a ⊗ₜ 1) = 1 ⊗ₜ a := + gradedComm_tmul_of_zero _ _ _ _ _ + +theorem gradedComm_one_tmul (b : ⨁ i, ℬ i) : gradedComm R 𝒜 ℬ (1 ⊗ₜ b) = b ⊗ₜ 1 := + gradedComm_of_zero_tmul _ _ _ _ _ + +@[simp, nolint simpNF] -- linter times out +theorem gradedComm_one : gradedComm R 𝒜 ℬ 1 = 1 := + gradedComm_one_tmul _ _ _ _ + +theorem gradedComm_tmul_algebraMap (a : ⨁ i, 𝒜 i) (r : R) : + gradedComm R 𝒜 ℬ (a ⊗ₜ algebraMap R _ r) = algebraMap R _ r ⊗ₜ a := + gradedComm_tmul_of_zero _ _ _ _ _ + +theorem gradedComm_algebraMap_tmul (r : R) (b : ⨁ i, ℬ i) : + gradedComm R 𝒜 ℬ (algebraMap R _ r ⊗ₜ b) = b ⊗ₜ algebraMap R _ r := + gradedComm_of_zero_tmul _ _ _ _ _ + +theorem gradedComm_algebraMap (r : R) : + gradedComm R 𝒜 ℬ (algebraMap R _ r) = algebraMap R _ r := + (gradedComm_algebraMap_tmul R 𝒜 ℬ r 1).trans (Algebra.TensorProduct.algebraMap_apply' r).symm + +end gradedComm + +open TensorProduct (assoc map) in +/-- The multiplication operation for tensor products of externally `ι`-graded algebras. -/ +noncomputable irreducible_def gradedMul : + letI AB := DirectSum _ 𝒜 ⊗[R] DirectSum _ ℬ + letI : Module R AB := TensorProduct.leftModule + AB →ₗ[R] AB →ₗ[R] AB := by + refine TensorProduct.curry ?_ + refine map (LinearMap.mul' R (⨁ i, 𝒜 i)) (LinearMap.mul' R (⨁ i, ℬ i)) ∘ₗ ?_ + refine (assoc R _ _ _).symm.toLinearMap ∘ₗ .lTensor _ ?_ ∘ₗ (assoc R _ _ _).toLinearMap + refine (assoc R _ _ _).toLinearMap ∘ₗ .rTensor _ ?_ ∘ₗ (assoc R _ _ _).symm.toLinearMap + exact (gradedComm _ _ _).toLinearMap + +theorem tmul_of_gradedMul_of_tmul (j₁ i₂ : ι) + (a₁ : ⨁ i, 𝒜 i) (b₁ : ℬ j₁) (a₂ : 𝒜 i₂) (b₂ : ⨁ i, ℬ i) : + gradedMul R 𝒜 ℬ (a₁ ⊗ₜ lof R _ ℬ j₁ b₁) (lof R _ 𝒜 i₂ a₂ ⊗ₜ b₂) = + (-1 : ℤˣ)^(j₁ * i₂) • ((a₁ * lof R _ 𝒜 _ a₂) ⊗ₜ (lof R _ ℬ _ b₁ * b₂)) := by + rw [gradedMul] + dsimp only [curry_apply, LinearMap.coe_comp, LinearEquiv.coe_coe, Function.comp_apply, assoc_tmul, + map_tmul, LinearMap.id_coe, id_eq, assoc_symm_tmul, LinearMap.rTensor_tmul, + LinearMap.lTensor_tmul] + rw [mul_comm j₁ i₂, gradedComm_of_tmul_of] + -- the tower smul lemmas elaborate too slowly + rw [Units.smul_def, Units.smul_def, zsmul_eq_smul_cast R, zsmul_eq_smul_cast R] + rw [← smul_tmul', map_smul, tmul_smul, map_smul, map_smul] + dsimp + +variable {R} + +theorem algebraMap_gradedMul (r : R) (x : (⨁ i, 𝒜 i) ⊗[R] (⨁ i, ℬ i)) : + gradedMul R 𝒜 ℬ (algebraMap R _ r ⊗ₜ 1) x = r • x := by + suffices gradedMul R 𝒜 ℬ (algebraMap R _ r ⊗ₜ 1) = DistribMulAction.toLinearMap R _ r by + exact FunLike.congr_fun this x + ext ia a ib b + dsimp + erw [tmul_of_gradedMul_of_tmul] + rw [zero_mul, uzpow_zero, one_smul, smul_tmul'] + erw [one_mul, _root_.Algebra.smul_def] + +theorem one_gradedMul (x : (⨁ i, 𝒜 i) ⊗[R] (⨁ i, ℬ i)) : + gradedMul R 𝒜 ℬ 1 x = x := by + simpa only [_root_.map_one, one_smul] using algebraMap_gradedMul 𝒜 ℬ 1 x + +theorem gradedMul_algebraMap (x : (⨁ i, 𝒜 i) ⊗[R] (⨁ i, ℬ i)) (r : R) : + gradedMul R 𝒜 ℬ x (algebraMap R _ r ⊗ₜ 1) = r • x := by + suffices (gradedMul R 𝒜 ℬ).flip (algebraMap R _ r ⊗ₜ 1) = DistribMulAction.toLinearMap R _ r by + exact FunLike.congr_fun this x + ext + dsimp + erw [tmul_of_gradedMul_of_tmul] + rw [mul_zero, uzpow_zero, one_smul, smul_tmul'] + erw [mul_one, _root_.Algebra.smul_def, Algebra.commutes] + rfl + +theorem gradedMul_one (x : (⨁ i, 𝒜 i) ⊗[R] (⨁ i, ℬ i)) : + gradedMul R 𝒜 ℬ x 1 = x := by + simpa only [_root_.map_one, one_smul] using gradedMul_algebraMap 𝒜 ℬ x 1 + +theorem gradedMul_assoc (x y z : DirectSum _ 𝒜 ⊗[R] DirectSum _ ℬ) : + gradedMul R 𝒜 ℬ (gradedMul R 𝒜 ℬ x y) z = gradedMul R 𝒜 ℬ x (gradedMul R 𝒜 ℬ y z) := by + let mA := gradedMul R 𝒜 ℬ + -- restate as an equality of morphisms so that we can use `ext` + suffices LinearMap.llcomp R _ _ _ mA ∘ₗ mA = + (LinearMap.llcomp R _ _ _ LinearMap.lflip <| LinearMap.llcomp R _ _ _ mA.flip ∘ₗ mA).flip by + exact FunLike.congr_fun (FunLike.congr_fun (FunLike.congr_fun this x) y) z + ext ixa xa ixb xb iya ya iyb yb iza za izb zb + dsimp + simp_rw [tmul_of_gradedMul_of_tmul, Units.smul_def, zsmul_eq_smul_cast R, + LinearMap.map_smul₂, LinearMap.map_smul, DirectSum.lof_eq_of, DirectSum.of_mul_of, + ← DirectSum.lof_eq_of R, tmul_of_gradedMul_of_tmul, DirectSum.lof_eq_of, ← DirectSum.of_mul_of, + ← DirectSum.lof_eq_of R, mul_assoc] + simp_rw [← zsmul_eq_smul_cast R, ← Units.smul_def, smul_smul, ← uzpow_add, add_mul, mul_add] + congr 2 + abel + +theorem gradedComm_gradedMul (x y : DirectSum _ 𝒜 ⊗[R] DirectSum _ ℬ) : + gradedComm R 𝒜 ℬ (gradedMul R 𝒜 ℬ x y) + = gradedMul R ℬ 𝒜 (gradedComm R 𝒜 ℬ x) (gradedComm R 𝒜 ℬ y) := by + suffices (gradedMul R 𝒜 ℬ).compr₂ (gradedComm R 𝒜 ℬ).toLinearMap + = (gradedMul R ℬ 𝒜 ∘ₗ (gradedComm R 𝒜 ℬ).toLinearMap).compl₂ + (gradedComm R 𝒜 ℬ).toLinearMap from + LinearMap.congr_fun₂ this x y + ext i₁ a₁ j₁ b₁ i₂ a₂ j₂ b₂ + dsimp + rw [gradedComm_of_tmul_of, gradedComm_of_tmul_of, tmul_of_gradedMul_of_tmul] + simp_rw [Units.smul_def, zsmul_eq_smul_cast R, map_smul, LinearMap.smul_apply] + simp_rw [← zsmul_eq_smul_cast R, ← Units.smul_def, DirectSum.lof_eq_of, DirectSum.of_mul_of, + ← DirectSum.lof_eq_of R, gradedComm_of_tmul_of, tmul_of_gradedMul_of_tmul, smul_smul, + DirectSum.lof_eq_of, ← DirectSum.of_mul_of, ← DirectSum.lof_eq_of R] + simp_rw [← uzpow_add, mul_add, add_mul, mul_comm i₁ j₂] + congr 1 + abel_nf + rw [two_nsmul, uzpow_add, uzpow_add, Int.units_mul_self, one_mul] + +end TensorProduct diff --git a/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean b/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean new file mode 100644 index 0000000000000..8988e8863e9f3 --- /dev/null +++ b/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean @@ -0,0 +1,380 @@ +/- +Copyright (c) 2023 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.LinearAlgebra.TensorProduct.Graded.External +import Mathlib.RingTheory.GradedAlgebra.Basic + +/-! +# Graded tensor products over graded algebras + +The graded tensor product $A \hat\otimes_R B$ is imbued with a multiplication defined on homogeneous +tensors by: + +$$(a \otimes b) \cdot (a' \otimes b') = (-1)^{\deg a' \deg b} (a \cdot a') \otimes (b \cdot b')$$ + +where $A$ and $B$ are algebras graded by `ℕ`, `ℤ`, or `ι` (or more generally, any index +that satisfies `Module ι (Additive ℤˣ)`). + +## Main results + +* `GradedTensorProduct R 𝒜 ℬ`: for families of submodules of `A` and `B` that form a graded algebra, + this is a type alias for `A ⊗[R] B` with the appropriate multiplication. +* `GradedTensorProduct.instAlgebra`: the ring structure induced by this multiplication. +* `GradedTensorProduct.liftEquiv`: a universal property for graded tensor products + +## Notation + +* `𝒜 ᵍ⊗[R] ℬ` is notation for `GradedTensorProduct R 𝒜 ℬ`. +* `a ᵍ⊗ₜ b` is notation for `GradedTensorProduct.tmul _ a b`. + +## References + +* https://math.stackexchange.com/q/202718/1896 +* [*Algebra I*, Bourbaki : Chapter III, §4.7, example (2)][bourbaki1989] + +## Implementation notes + +We cannot put the multiplication on `A ⊗[R] B` directly as it would conflict with the existing +multiplication defined without the $(-1)^{\deg a' \deg b}$ term. Furthermore, the ring `A` may not +have a unique graduation, and so we need the chosen graduation `𝒜` to appear explicitly in the +type. + +## TODO + +* Show that the tensor product of graded algebras is itself a graded algebra. +* Determine if replacing the synonym with a single-field structure improves performance. +-/ + +suppress_compilation + +open scoped TensorProduct + +variable {R ι A B : Type*} + +variable [CommSemiring ι] [Module ι (Additive ℤˣ)] [DecidableEq ι] +variable [CommRing R] [Ring A] [Ring B] [Algebra R A] [Algebra R B] +variable (𝒜 : ι → Submodule R A) (ℬ : ι → Submodule R B) +variable [GradedAlgebra 𝒜] [GradedAlgebra ℬ] + +open DirectSum + + +variable (R) in +/-- A Type synonym for `A ⊗[R] B`, but with multiplication as `TensorProduct.gradedMul`. + +This has notation `𝒜 ᵍ⊗[R] ℬ`. -/ +@[nolint unusedArguments] +def GradedTensorProduct + (𝒜 : ι → Submodule R A) (ℬ : ι → Submodule R B) + [GradedAlgebra 𝒜] [GradedAlgebra ℬ] : + Type _ := + A ⊗[R] B + +namespace GradedTensorProduct + +open TensorProduct + +@[inherit_doc GradedTensorProduct] +scoped[TensorProduct] notation:100 𝒜 " ᵍ⊗[" R "] " ℬ:100 => GradedTensorProduct R 𝒜 ℬ + +instance instAddCommGroupWithOne : AddCommGroupWithOne (𝒜 ᵍ⊗[R] ℬ) := + Algebra.TensorProduct.instAddCommGroupWithOne +instance : Module R (𝒜 ᵍ⊗[R] ℬ) := TensorProduct.leftModule + +variable (R) in +/-- The casting equivalence to move between regular and graded tensor products. -/ +def of : A ⊗[R] B ≃ₗ[R] 𝒜 ᵍ⊗[R] ℬ := LinearEquiv.refl _ _ + +@[simp] +theorem of_one : of R 𝒜 ℬ 1 = 1 := rfl + +@[simp] +theorem of_symm_one : (of R 𝒜 ℬ).symm 1 = 1 := rfl + +-- for dsimp +@[simp, nolint simpNF] +theorem of_symm_of (x : A ⊗[R] B) : (of R 𝒜 ℬ).symm (of R 𝒜 ℬ x) = x := rfl + +-- for dsimp +@[simp, nolint simpNF] +theorem symm_of_of (x : 𝒜 ᵍ⊗[R] ℬ) : of R 𝒜 ℬ ((of R 𝒜 ℬ).symm x) = x := rfl + +/-- Two linear maps from the graded tensor product agree if they agree on the underlying tensor +product. -/ +@[ext] +theorem hom_ext {M} [AddCommMonoid M] [Module R M] ⦃f g : 𝒜 ᵍ⊗[R] ℬ →ₗ[R] M⦄ + (h : f ∘ₗ of R 𝒜 ℬ = (g ∘ₗ of R 𝒜 ℬ : A ⊗[R] B →ₗ[R] M)) : + f = g := + h + +variable (R) {𝒜 ℬ} in +/-- The graded tensor product of two elements of graded rings. -/ +abbrev tmul (a : A) (b : B) : 𝒜 ᵍ⊗[R] ℬ := of R 𝒜 ℬ (a ⊗ₜ b) + +@[inherit_doc] +notation:100 x " ᵍ⊗ₜ" y:100 => tmul _ x y + +@[inherit_doc] +notation:100 x " ᵍ⊗ₜ[" R "] " y:100 => tmul R x y + +variable (R) in +/-- An auxiliary construction to move between the graded tensor product of internally-graded objects +and the tensor product of direct sums. -/ +noncomputable def auxEquiv : (𝒜 ᵍ⊗[R] ℬ) ≃ₗ[R] (⨁ i, 𝒜 i) ⊗[R] (⨁ i, ℬ i) := + let fA := (decomposeAlgEquiv 𝒜).toLinearEquiv + let fB := (decomposeAlgEquiv ℬ).toLinearEquiv + (of R 𝒜 ℬ).symm.trans (TensorProduct.congr fA fB) + +@[simp] theorem auxEquiv_tmul (a : A) (b : B) : + auxEquiv R 𝒜 ℬ (a ᵍ⊗ₜ b) = decompose 𝒜 a ⊗ₜ decompose ℬ b := rfl + +@[simp] theorem auxEquiv_one : auxEquiv R 𝒜 ℬ 1 = 1 := by + rw [← of_one, Algebra.TensorProduct.one_def, auxEquiv_tmul 𝒜 ℬ, DirectSum.decompose_one, + DirectSum.decompose_one, Algebra.TensorProduct.one_def] + +@[simp, nolint simpNF] -- simpNF linter crashes +theorem auxEquiv_symm_one : (auxEquiv R 𝒜 ℬ).symm 1 = 1 := + (LinearEquiv.symm_apply_eq _).mpr (auxEquiv_one _ _).symm + +/-- Auxiliary construction used to build the `Mul` instance and get distributivity of `+` and +`\smul`. -/ +noncomputable def mulHom : (𝒜 ᵍ⊗[R] ℬ) →ₗ[R] (𝒜 ᵍ⊗[R] ℬ) →ₗ[R] (𝒜 ᵍ⊗[R] ℬ) := by + letI fAB1 := auxEquiv R 𝒜 ℬ + have := ((gradedMul R (𝒜 ·) (ℬ ·)).compl₁₂ fAB1.toLinearMap fAB1.toLinearMap).compr₂ + fAB1.symm.toLinearMap + exact this + +theorem mulHom_apply (x y : 𝒜 ᵍ⊗[R] ℬ) : + mulHom 𝒜 ℬ x y + = (auxEquiv R 𝒜 ℬ).symm (gradedMul R (𝒜 ·) (ℬ ·) (auxEquiv R 𝒜 ℬ x) (auxEquiv R 𝒜 ℬ y)) := + rfl + +/-- The multipication on the graded tensor product. + +See `GradedTensorProduct.coe_mul_coe` for a characterization on pure tensors. -/ +instance : Mul (𝒜 ᵍ⊗[R] ℬ) where mul x y := mulHom 𝒜 ℬ x y + +theorem mul_def (x y : 𝒜 ᵍ⊗[R] ℬ) : x * y = mulHom 𝒜 ℬ x y := rfl + +@[simp] +theorem auxEquiv_mul (x y : 𝒜 ᵍ⊗[R] ℬ) : + auxEquiv R 𝒜 ℬ (x * y) = gradedMul R (𝒜 ·) (ℬ ·) (auxEquiv R 𝒜 ℬ x) (auxEquiv R 𝒜 ℬ y) := + LinearEquiv.eq_symm_apply _ |>.mp rfl + +instance instMonoid : Monoid (𝒜 ᵍ⊗[R] ℬ) where + mul_one x := by + rw [mul_def, mulHom_apply, auxEquiv_one, gradedMul_one, LinearEquiv.symm_apply_apply] + one_mul x := by + rw [mul_def, mulHom_apply, auxEquiv_one, one_gradedMul, LinearEquiv.symm_apply_apply] + mul_assoc x y z := by + simp_rw [mul_def, mulHom_apply, LinearEquiv.apply_symm_apply] + rw [gradedMul_assoc] + +instance instRing : Ring (𝒜 ᵍ⊗[R] ℬ) where + __ := instAddCommGroupWithOne 𝒜 ℬ + __ := instMonoid 𝒜 ℬ + right_distrib x y z := by simp_rw [mul_def, LinearMap.map_add₂] + left_distrib x y z := by simp_rw [mul_def, map_add] + mul_zero x := by simp_rw [mul_def, map_zero] + zero_mul x := by simp_rw [mul_def, LinearMap.map_zero₂] + +/-- The characterization of this multiplication on partially homogenous elements. -/ +theorem tmul_coe_mul_coe_tmul {j₁ i₂ : ι} (a₁ : A) (b₁ : ℬ j₁) (a₂ : 𝒜 i₂) (b₂ : B) : + (a₁ ᵍ⊗ₜ[R] (b₁ : B) * (a₂ : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) = + (-1 : ℤˣ)^(j₁ * i₂) • ((a₁ * a₂ : A) ᵍ⊗ₜ (b₁ * b₂ : B)) := by + dsimp only [mul_def, mulHom_apply, of_symm_of] + dsimp [auxEquiv, tmul] + erw [decompose_coe, decompose_coe] + simp_rw [← lof_eq_of R] + rw [tmul_of_gradedMul_of_tmul] + simp_rw [lof_eq_of R] + rw [LinearEquiv.symm_symm] + rw [@Units.smul_def _ _ (_) (_), zsmul_eq_smul_cast R, map_smul, map_smul, + ← zsmul_eq_smul_cast R, ← @Units.smul_def _ _ (_) (_)] + rw [congr_symm_tmul] + dsimp + simp_rw [decompose_symm_mul, decompose_symm_of, Equiv.symm_apply_apply] + +/-- A special case for when `b₁` has grade 0. -/ +theorem tmul_zero_coe_mul_coe_tmul {i₂ : ι} (a₁ : A) (b₁ : ℬ 0) (a₂ : 𝒜 i₂) (b₂ : B) : + (a₁ ᵍ⊗ₜ[R] (b₁ : B) * (a₂ : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) = + ((a₁ * a₂ : A) ᵍ⊗ₜ (b₁ * b₂ : B)) := by + rw [tmul_coe_mul_coe_tmul, zero_mul, uzpow_zero, one_smul] + +/-- A special case for when `a₂` has grade 0. -/ +theorem tmul_coe_mul_zero_coe_tmul {j₁ : ι} (a₁ : A) (b₁ : ℬ j₁) (a₂ : 𝒜 0) (b₂ : B) : + (a₁ ᵍ⊗ₜ[R] (b₁ : B) * (a₂ : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) = + ((a₁ * a₂ : A) ᵍ⊗ₜ (b₁ * b₂ : B)) := by + rw [tmul_coe_mul_coe_tmul, mul_zero, uzpow_zero, one_smul] + +theorem tmul_one_mul_coe_tmul {i₂ : ι} (a₁ : A) (a₂ : 𝒜 i₂) (b₂ : B) : + (a₁ ᵍ⊗ₜ[R] (1 : B) * (a₂ : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) = (a₁ * a₂ : A) ᵍ⊗ₜ (b₂ : B) := by + convert tmul_zero_coe_mul_coe_tmul 𝒜 ℬ a₁ (@GradedMonoid.GOne.one _ (ℬ ·) _ _) a₂ b₂ + rw [SetLike.coe_gOne, one_mul] + +theorem tmul_coe_mul_one_tmul {j₁ : ι} (a₁ : A) (b₁ : ℬ j₁) (b₂ : B) : + (a₁ ᵍ⊗ₜ[R] (b₁ : B) * (1 : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) = (a₁ : A) ᵍ⊗ₜ (b₁ * b₂ : B) := by + convert tmul_coe_mul_zero_coe_tmul 𝒜 ℬ a₁ b₁ (@GradedMonoid.GOne.one _ (𝒜 ·) _ _) b₂ + rw [SetLike.coe_gOne, mul_one] + +theorem tmul_one_mul_one_tmul (a₁ : A) (b₂ : B) : + (a₁ ᵍ⊗ₜ[R] (1 : B) * (1 : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) = (a₁ : A) ᵍ⊗ₜ (b₂ : B) := by + convert tmul_coe_mul_zero_coe_tmul 𝒜 ℬ + a₁ (@GradedMonoid.GOne.one _ (ℬ ·) _ _) (@GradedMonoid.GOne.one _ (𝒜 ·) _ _) b₂ + · rw [SetLike.coe_gOne, mul_one] + · rw [SetLike.coe_gOne, one_mul] + +/-- The ring morphism `A →+* A ⊗[R] B` sending `a` to `a ⊗ₜ 1`. -/ +@[simps] +def includeLeftRingHom : A →+* 𝒜 ᵍ⊗[R] ℬ where + toFun a := a ᵍ⊗ₜ 1 + map_zero' := by simp + map_add' := by simp [tmul, TensorProduct.add_tmul] + map_one' := rfl + map_mul' a₁ a₂ := by + dsimp + classical + rw [← DirectSum.sum_support_decompose 𝒜 a₂, Finset.mul_sum] + simp_rw [tmul, sum_tmul, map_sum, Finset.mul_sum] + congr + ext i + rw [← SetLike.coe_gOne ℬ, tmul_coe_mul_coe_tmul, zero_mul, uzpow_zero, one_smul, + SetLike.coe_gOne, one_mul] + +instance instAlgebra : Algebra R (𝒜 ᵍ⊗[R] ℬ) where + toRingHom := (includeLeftRingHom 𝒜 ℬ).comp (algebraMap R A) + commutes' r x := by + dsimp [mul_def, mulHom_apply, auxEquiv_tmul] + simp_rw [DirectSum.decompose_algebraMap, DirectSum.decompose_one, algebraMap_gradedMul, + gradedMul_algebraMap] + smul_def' r x := by + dsimp [mul_def, mulHom_apply, auxEquiv_tmul] + simp_rw [DirectSum.decompose_algebraMap, DirectSum.decompose_one, algebraMap_gradedMul, + map_smul, LinearEquiv.symm_apply_apply] + +lemma algebraMap_def (r : R) : algebraMap R (𝒜 ᵍ⊗[R] ℬ) r = algebraMap R A r ᵍ⊗ₜ[R] 1 := rfl + +theorem tmul_algebraMap_mul_coe_tmul {i₂ : ι} (a₁ : A) (r : R) (a₂ : 𝒜 i₂) (b₂ : B) : + (a₁ ᵍ⊗ₜ[R] algebraMap R B r * (a₂ : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) + = (a₁ * a₂ : A) ᵍ⊗ₜ (algebraMap R B r * b₂ : B) := + tmul_zero_coe_mul_coe_tmul 𝒜 ℬ a₁ (GAlgebra.toFun (A := (ℬ ·)) r) a₂ b₂ + +theorem tmul_coe_mul_algebraMap_tmul {j₁ : ι} (a₁ : A) (b₁ : ℬ j₁) (r : R) (b₂ : B) : + (a₁ ᵍ⊗ₜ[R] (b₁ : B) * algebraMap R A r ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) + = (a₁ * algebraMap R A r : A) ᵍ⊗ₜ (b₁ * b₂ : B) := + tmul_coe_mul_zero_coe_tmul 𝒜 ℬ a₁ b₁ (GAlgebra.toFun (A := (𝒜 ·)) r) b₂ + +/-- The algebra morphism `A →ₐ[R] A ⊗[R] B` sending `a` to `a ⊗ₜ 1`. -/ +@[simps!] +def includeLeft : A →ₐ[R] 𝒜 ᵍ⊗[R] ℬ where + toRingHom := includeLeftRingHom 𝒜 ℬ + commutes' _ := rfl + +/-- The algebra morphism `B →ₐ[R] A ⊗[R] B` sending `b` to `1 ⊗ₜ b`. -/ +@[simps!] +def includeRight : B →ₐ[R] (𝒜 ᵍ⊗[R] ℬ) := + AlgHom.ofLinearMap (R := R) (A := B) (B := 𝒜 ᵍ⊗[R] ℬ) + (f := { + toFun := fun b => 1 ᵍ⊗ₜ b + map_add' := by simp [tmul, TensorProduct.tmul_add] + map_smul' := by simp [tmul, TensorProduct.tmul_smul] }) + (map_one := rfl) + (map_mul := by + rw [LinearMap.map_mul_iff] + refine DirectSum.decompose_lhom_ext ℬ fun i₁ => ?_ + ext b₁ b₂ : 2 + dsimp + rw [tmul_coe_mul_one_tmul]) + +lemma algebraMap_def' (r : R) : algebraMap R (𝒜 ᵍ⊗[R] ℬ) r = 1 ᵍ⊗ₜ[R] algebraMap R B r := + (includeRight 𝒜 ℬ).commutes r |>.symm + +variable {C} [Ring C] [Algebra R C] + +/-- The forwards direction of the universal property; an algebra morphism out of the graded tensor +product can be assembed from maps on each component that (anti)commute on pure elements of the +corresponding graded algebras. -/ +def lift (f : A →ₐ[R] C) (g : B →ₐ[R] C) + (h_anti_commutes : ∀ ⦃i j⦄ (a : 𝒜 i) (b : ℬ j), f a * g b = (-1 : ℤˣ)^(j * i) • (g b * f a)) : + (𝒜 ᵍ⊗[R] ℬ) →ₐ[R] C := + AlgHom.ofLinearMap + (LinearMap.mul' R C + ∘ₗ (TensorProduct.map f.toLinearMap g.toLinearMap) + ∘ₗ ((of R 𝒜 ℬ).symm : 𝒜 ᵍ⊗[R] ℬ →ₗ[R] A ⊗[R] B)) + (by dsimp [Algebra.TensorProduct.one_def]; simp only [_root_.map_one, mul_one]) + (by + rw [LinearMap.map_mul_iff] + ext a₁ : 3 + refine DirectSum.decompose_lhom_ext ℬ fun j₁ => ?_ + ext b₁ : 3 + refine DirectSum.decompose_lhom_ext 𝒜 fun i₂ => ?_ + ext a₂ b₂ : 2 + dsimp + rw [tmul_coe_mul_coe_tmul] + rw [@Units.smul_def _ _ (_) (_), zsmul_eq_smul_cast R, map_smul, map_smul, map_smul] + rw [← zsmul_eq_smul_cast R, ← @Units.smul_def _ _ (_) (_)] + rw [of_symm_of, map_tmul, LinearMap.mul'_apply] + simp_rw [AlgHom.toLinearMap_apply, _root_.map_mul] + simp_rw [mul_assoc (f a₁), ← mul_assoc _ _ (g b₂), h_anti_commutes, mul_smul_comm, + smul_mul_assoc, smul_smul, Int.units_mul_self, one_smul]) + +@[simp] +theorem lift_tmul (f : A →ₐ[R] C) (g : B →ₐ[R] C) + (h_anti_commutes : ∀ ⦃i j⦄ (a : 𝒜 i) (b : ℬ j), f a * g b = (-1 : ℤˣ)^(j * i) • (g b * f a)) + (a : A) (b : B) : + lift 𝒜 ℬ f g h_anti_commutes (a ᵍ⊗ₜ b) = f a * g b := + rfl + +/-- The universal property of the graded tensor product; every algebra morphism uniquely factors +as a pair of algebra morphisms that anticommute with respect to the grading. -/ +def liftEquiv : + { fg : (A →ₐ[R] C) × (B →ₐ[R] C) // + ∀ ⦃i j⦄ (a : 𝒜 i) (b : ℬ j), fg.1 a * fg.2 b = (-1 : ℤˣ)^(j * i) • (fg.2 b * fg.1 a)} ≃ + ((𝒜 ᵍ⊗[R] ℬ) →ₐ[R] C) where + toFun fg := lift 𝒜 ℬ _ _ fg.prop + invFun F := ⟨(F.comp (includeLeft 𝒜 ℬ), F.comp (includeRight 𝒜 ℬ)), fun i j a b => by + dsimp + rw [← F.map_mul, ← F.map_mul, tmul_coe_mul_coe_tmul, one_mul, mul_one, AlgHom.map_smul_of_tower, + tmul_one_mul_one_tmul, smul_smul, Int.units_mul_self, one_smul]⟩ + left_inv fg := by ext <;> (dsimp; simp only [_root_.map_one, mul_one, one_mul]) + right_inv F := by + apply AlgHom.toLinearMap_injective + ext + dsimp + rw [← F.map_mul, tmul_one_mul_one_tmul] + +/-- Two algebra morphism from the graded tensor product agree if their compositions with the left +and right inclusions agree. -/ +@[ext] +lemma algHom_ext ⦃f g : (𝒜 ᵍ⊗[R] ℬ) →ₐ[R] C⦄ + (ha : f.comp (includeLeft 𝒜 ℬ) = g.comp (includeLeft 𝒜 ℬ)) + (hb : f.comp (includeRight 𝒜 ℬ) = g.comp (includeRight 𝒜 ℬ)) : f = g := + (liftEquiv 𝒜 ℬ).symm.injective <| Subtype.ext <| Prod.ext ha hb + +/-- The non-trivial symmetric braiding, sending $a \otimes b$ to +$(-1)^{\deg a' \deg b} (b \otimes a)$. -/ +def comm : (𝒜 ᵍ⊗[R] ℬ) ≃ₐ[R] (ℬ ᵍ⊗[R] 𝒜) := + AlgEquiv.ofLinearEquiv + (auxEquiv R 𝒜 ℬ ≪≫ₗ gradedComm R _ _ ≪≫ₗ (auxEquiv R ℬ 𝒜).symm) + (by + dsimp + simp_rw [auxEquiv_one, gradedComm_one, auxEquiv_symm_one]) + (fun x y => by + dsimp + simp_rw [auxEquiv_mul, gradedComm_gradedMul, LinearEquiv.symm_apply_eq, + ← gradedComm_gradedMul, auxEquiv_mul, LinearEquiv.apply_symm_apply, gradedComm_gradedMul]) + +@[simp] lemma auxEquiv_comm (x : 𝒜 ᵍ⊗[R] ℬ) : + auxEquiv R ℬ 𝒜 (comm 𝒜 ℬ x) = gradedComm R (𝒜 ·) (ℬ ·) (auxEquiv R 𝒜 ℬ x) := + LinearEquiv.eq_symm_apply _ |>.mp rfl + +@[simp] lemma comm_coe_tmul_coe {i j : ι} (a : 𝒜 i) (b : ℬ j) : + comm 𝒜 ℬ (a ᵍ⊗ₜ b) = (-1 : ℤˣ)^(j * i) • (b ᵍ⊗ₜ a : ℬ ᵍ⊗[R] 𝒜) := + (auxEquiv R ℬ 𝒜).injective <| by + simp_rw [auxEquiv_comm, auxEquiv_tmul, decompose_coe, ← lof_eq_of R, gradedComm_of_tmul_of, + @Units.smul_def _ _ (_) (_), zsmul_eq_smul_cast R, map_smul, auxEquiv_tmul, decompose_coe, + lof_eq_of] + +end GradedTensorProduct diff --git a/Mathlib/RingTheory/TensorProduct.lean b/Mathlib/RingTheory/TensorProduct.lean index 012abb6ecb3b5..0bda602a6d98c 100644 --- a/Mathlib/RingTheory/TensorProduct.lean +++ b/Mathlib/RingTheory/TensorProduct.lean @@ -699,7 +699,10 @@ theorem lift_comp_includeRight (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : Pairs of algebra morphisms that commute are equivalent to algebra morphisms from the tensor product. -This is `Algebra.TensorProduct.lift` as an equivalence. -/ +This is `Algebra.TensorProduct.lift` as an equivalence. + +See also `GradedTensorProduct.liftEquiv` for an alternative commutativity requirement for graded +algebra. -/ @[simps] def liftEquiv [IsScalarTower R S A] [IsScalarTower R S C] : {fg : (A →ₐ[S] C) × (B →ₐ[R] C) // ∀ x y, Commute (fg.1 x) (fg.2 y)} From 4abd905eb7556ffe89fe0ac16bbdc66108d85b06 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 18 Dec 2023 04:53:00 +0000 Subject: [PATCH 048/353] feat(RingTheory/NonUnitalSubsemiring): point-free statement of centrality (#9053) Also adds `isMulCentral_iff` using `mk_iff`. --- Mathlib/Algebra/Group/Hom/Instances.lean | 18 +++++++++++------- Mathlib/GroupTheory/Subsemigroup/Center.lean | 5 +++++ .../RingTheory/NonUnitalSubsemiring/Basic.lean | 13 +++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Mathlib/Algebra/Group/Hom/Instances.lean b/Mathlib/Algebra/Group/Hom/Instances.lean index 372a8d01165ae..cae4b2cc6ef35 100644 --- a/Mathlib/Algebra/Group/Hom/Instances.lean +++ b/Mathlib/Algebra/Group/Hom/Instances.lean @@ -331,6 +331,14 @@ theorem AddMonoidHom.map_mul_iff (f : R →+ S) : Iff.symm AddMonoidHom.ext_iff₂ #align add_monoid_hom.map_mul_iff AddMonoidHom.map_mul_iff +lemma AddMonoidHom.mulLeft_eq_mulRight_iff_forall_commute {a : R} : + mulLeft a = mulRight a ↔ ∀ b, Commute a b := + FunLike.ext_iff + +lemma AddMonoidHom.mulRight_eq_mulLeft_iff_forall_commute {b : R} : + mulRight b = mulLeft b ↔ ∀ a, Commute a b := + FunLike.ext_iff + /-- The left multiplication map: `(a, b) ↦ a * b`. See also `AddMonoidHom.mulLeft`. -/ @[simps!] def AddMonoid.End.mulLeft : R →+ AddMonoid.End R := @@ -345,10 +353,6 @@ def AddMonoid.End.mulRight : R →+ AddMonoid.End R := #align add_monoid.End.mul_right AddMonoid.End.mulRight #align add_monoid.End.mul_right_apply_apply AddMonoid.End.mulRight_apply_apply -lemma AddMonoid.End.mulRight_eq_mulLeft_of_commute (a : R) (h : ∀ (b : R), Commute a b) : - mulRight a = mulLeft a := - AddMonoidHom.ext fun _ ↦ (h _).eq.symm - end Semiring section CommSemiring @@ -357,9 +361,9 @@ variable {R S : Type*} [NonUnitalNonAssocCommSemiring R] namespace AddMonoid.End -lemma comm_mulRight_eq_mulLeft : mulRight = (mulLeft : R →+ AddMonoid.End R) := by - ext a - exact mulRight_eq_mulLeft_of_commute _ (Commute.all _) +lemma mulRight_eq_mulLeft : mulRight = (mulLeft : R →+ AddMonoid.End R) := + AddMonoidHom.ext fun _ => + Eq.symm <| AddMonoidHom.mulLeft_eq_mulRight_iff_forall_commute.2 (.all _) end AddMonoid.End diff --git a/Mathlib/GroupTheory/Subsemigroup/Center.lean b/Mathlib/GroupTheory/Subsemigroup/Center.lean index 976df673386c3..dd4c15de90db2 100644 --- a/Mathlib/GroupTheory/Subsemigroup/Center.lean +++ b/Mathlib/GroupTheory/Subsemigroup/Center.lean @@ -56,6 +56,11 @@ structure IsMulCentral [Mul M] (z : M) : Prop where /-- associative property for right multiplication -/ right_assoc (a b : M) : (a * b) * z = a * (b * z) +-- TODO: these should have explicit arguments (mathlib4#9129) +attribute [mk_iff isMulCentral_iff] IsMulCentral +attribute [mk_iff isAddCentral_iff] IsAddCentral +attribute [to_additive existing] isMulCentral_iff + namespace IsMulCentral variable {a b c : M} [Mul M] diff --git a/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean b/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean index f5bb57ffcafd9..d25cc3befe232 100644 --- a/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean +++ b/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean @@ -494,6 +494,19 @@ instance center.instNonUnitalCommSemiring : NonUnitalCommSemiring (center R) := { Subsemigroup.center.commSemigroup, NonUnitalSubsemiringClass.toNonUnitalNonAssocSemiring (center R) with } +/-- A point-free means of proving membership in the center, for a non-associative ring. + +This can be helpful when working with types that have ext lemmas for `R →+ R`. -/ +lemma _root_.Set.mem_center_iff_addMonoidHom (a : R) : + a ∈ Set.center R ↔ + AddMonoidHom.mulLeft a = .mulRight a ∧ + AddMonoidHom.compr₂ .mul (.mulLeft a) = .comp .mul (.mulLeft a) ∧ + AddMonoidHom.comp .mul (.mulRight a) = .compl₂ .mul (.mulLeft a) ∧ + AddMonoidHom.compr₂ .mul (.mulRight a) = .compl₂ .mul (.mulRight a) := by + rw [Set.mem_center_iff, isMulCentral_iff] + simp_rw [FunLike.ext_iff] + rfl + end NonUnitalNonAssocSemiring section NonUnitalSemiring From 7b7e8442189bd7fb23078d65db1bfb5876cdcba7 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 18 Dec 2023 04:53:02 +0000 Subject: [PATCH 049/353] chore: better error message for assert_not_exists (#9070) Co-authored-by: Scott Morrison Co-authored-by: Yury G. Kudryashov Co-authored-by: Kyle Miller --- Mathlib/Util/AssertExists.lean | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mathlib/Util/AssertExists.lean b/Mathlib/Util/AssertExists.lean index 8c1e855c80e9e..4c901b2d562da 100644 --- a/Mathlib/Util/AssertExists.lean +++ b/Mathlib/Util/AssertExists.lean @@ -49,4 +49,7 @@ You should *not* delete the `assert_not_exists` statement without careful discus -/ elab "assert_not_exists " n:ident : command => do let [] ← try resolveGlobalConstWithInfos n catch _ => return - | throw <| Exception.error n m!"Declaration {n} is not allowed to exist in this file" + | throw <| .error n <| m!"Declaration {n} is not allowed to be imported by this file.\n\n{ + ""}These invariants are maintained by `assert_not_exists` statements, { + ""}and exist in order to ensure that \"complicated\" parts of the library { + ""}are not accidentally introduced as dependencies of \"simple\" parts of the library." From f94379b4892c24c6ee67e02adebdd1ad62ec3867 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Mon, 18 Dec 2023 04:53:03 +0000 Subject: [PATCH 050/353] feat(Mathlib/FieldTheory/Separable): add `Polynomial.Separable.isIntegral` and golf (#9134) --- Mathlib/FieldTheory/Separable.lean | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Mathlib/FieldTheory/Separable.lean b/Mathlib/FieldTheory/Separable.lean index e634787807932..948a244ba1467 100644 --- a/Mathlib/FieldTheory/Separable.lean +++ b/Mathlib/FieldTheory/Separable.lean @@ -505,7 +505,7 @@ variable (F K : Type*) [CommRing F] [Ring K] [Algebra F K] -- to allow non-algebraic extensions, then the definition of `IsGalois` must also be changed. /-- Typeclass for separable field extension: `K` is a separable field extension of `F` iff the minimal polynomial of every `x : K` is separable. This implies that `K/F` is an algebraic -extension, because the minimal polynomial of a non-integral element is 0, which is not +extension, because the minimal polynomial of a non-integral element is `0`, which is not separable. We define this for general (commutative) rings and only assume `F` and `K` are fields if this @@ -521,11 +521,17 @@ theorem IsSeparable.separable [IsSeparable F K] : ∀ x : K, (minpoly F x).Separ IsSeparable.separable' #align is_separable.separable IsSeparable.separable -theorem IsSeparable.isIntegral [IsSeparable F K] : ∀ x : K, IsIntegral F x := fun x ↦ by +variable {F} in +/-- If the minimal polynomial of `x : K` over `F` is separable, then `x` is integral over `F`, +because the minimal polynomial of a non-integral element is `0`, which is not separable. -/ +theorem Polynomial.Separable.isIntegral {x : K} (h : (minpoly F x).Separable) : IsIntegral F x := by cases subsingleton_or_nontrivial F · haveI := Module.subsingleton F K exact ⟨1, monic_one, Subsingleton.elim _ _⟩ - · exact of_not_not fun h ↦ not_separable_zero (minpoly.eq_zero h ▸ IsSeparable.separable F x) + · exact of_not_not fun h' ↦ not_separable_zero (minpoly.eq_zero h' ▸ h) + +theorem IsSeparable.isIntegral [IsSeparable F K] : + ∀ x : K, IsIntegral F x := fun x ↦ (IsSeparable.separable F x).isIntegral #align is_separable.is_integral IsSeparable.isIntegral variable {F} From 608404e39ba9f6e75fba144fe973a46f4c91351b Mon Sep 17 00:00:00 2001 From: negiizhao Date: Mon, 18 Dec 2023 06:06:32 +0000 Subject: [PATCH 051/353] chore(Algebra/Order/Group): change simp lemmas (#7867) --- Mathlib/Algebra/Order/Group/Defs.lean | 12 ++++++++---- Mathlib/Algebra/Order/Sub/Defs.lean | 7 ++++--- Mathlib/Topology/MetricSpace/PseudoMetric.lean | 3 ++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Mathlib/Algebra/Order/Group/Defs.lean b/Mathlib/Algebra/Order/Group/Defs.lean index 0a29356297ca9..50d8582b69997 100644 --- a/Mathlib/Algebra/Order/Group/Defs.lean +++ b/Mathlib/Algebra/Order/Group/Defs.lean @@ -705,7 +705,7 @@ section Right variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} -@[to_additive (attr := simp)] +@[to_additive] theorem div_le_div_iff_right (c : α) : a / c ≤ b / c ↔ a ≤ b := by simpa only [div_eq_mul_inv] using mul_le_mul_iff_right _ #align div_le_div_iff_right div_le_div_iff_right @@ -727,7 +727,7 @@ alias ⟨le_of_sub_nonneg, sub_nonneg_of_le⟩ := sub_nonneg #align sub_nonneg_of_le sub_nonneg_of_le #align le_of_sub_nonneg le_of_sub_nonneg -@[to_additive (attr := simp) sub_nonpos] +@[to_additive sub_nonpos] theorem div_le_one' : a / b ≤ 1 ↔ a ≤ b := by rw [← mul_le_mul_iff_right b, one_mul, div_eq_mul_inv, inv_mul_cancel_right] #align div_le_one' div_le_one' @@ -753,6 +753,10 @@ theorem div_le_iff_le_mul : a / c ≤ b ↔ a ≤ b * c := by #align div_le_iff_le_mul div_le_iff_le_mul #align sub_le_iff_le_add sub_le_iff_le_add +-- Note: we intentionally don't have `@[simp]` for the additive version, +-- since the LHS simplifies with `tsub_le_iff_right` +attribute [simp] div_le_iff_le_mul + -- TODO: Should we get rid of `sub_le_iff_le_add` in favor of -- (a renamed version of) `tsub_le_iff_right`? -- see Note [lower instance priority] @@ -769,7 +773,7 @@ variable [CovariantClass α α (· * ·) (· ≤ ·)] variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} -@[to_additive (attr := simp)] +@[to_additive] theorem div_le_div_iff_left (a : α) : a / b ≤ a / c ↔ c ≤ b := by rw [div_eq_mul_inv, div_eq_mul_inv, ← mul_le_mul_iff_left a⁻¹, inv_mul_cancel_left, inv_mul_cancel_left, inv_le_inv_iff] @@ -1070,7 +1074,7 @@ theorem div_le_inv_mul_iff [CovariantClass α α (swap (· * ·)) (· ≤ ·)] : -- What is the point of this lemma? See comment about `div_le_inv_mul_iff` above. -- Note: we intentionally don't have `@[simp]` for the additive version, -- since the LHS simplifies with `tsub_le_iff_right` -@[to_additive, simp] +@[to_additive] theorem div_le_div_flip {α : Type*} [CommGroup α] [LinearOrder α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} : a / b ≤ b / a ↔ a ≤ b := by rw [div_eq_mul_inv b, mul_comm] diff --git a/Mathlib/Algebra/Order/Sub/Defs.lean b/Mathlib/Algebra/Order/Sub/Defs.lean index 964d88879b82a..cbe68060983a5 100644 --- a/Mathlib/Algebra/Order/Sub/Defs.lean +++ b/Mathlib/Algebra/Order/Sub/Defs.lean @@ -59,13 +59,14 @@ class OrderedSub (α : Type*) [LE α] [Add α] [Sub α] : Prop where section Add -variable [Preorder α] [Add α] [Sub α] [OrderedSub α] {a b c d : α} - @[simp] -theorem tsub_le_iff_right : a - b ≤ c ↔ a ≤ c + b := +theorem tsub_le_iff_right [LE α] [Add α] [Sub α] [OrderedSub α] {a b c : α} : + a - b ≤ c ↔ a ≤ c + b := OrderedSub.tsub_le_iff_right a b c #align tsub_le_iff_right tsub_le_iff_right +variable [Preorder α] [Add α] [Sub α] [OrderedSub α] {a b c d : α} + /-- See `add_tsub_cancel_right` for the equality if `ContravariantClass α α (+) (≤)`. -/ theorem add_tsub_le_right : a + b - b ≤ a := tsub_le_iff_right.mpr le_rfl diff --git a/Mathlib/Topology/MetricSpace/PseudoMetric.lean b/Mathlib/Topology/MetricSpace/PseudoMetric.lean index ad480a35f4372..745d0b44e1553 100644 --- a/Mathlib/Topology/MetricSpace/PseudoMetric.lean +++ b/Mathlib/Topology/MetricSpace/PseudoMetric.lean @@ -1564,7 +1564,8 @@ theorem NNReal.dist_eq (a b : ℝ≥0) : dist a b = |(a : ℝ) - b| := rfl theorem NNReal.nndist_eq (a b : ℝ≥0) : nndist a b = max (a - b) (b - a) := eq_of_forall_ge_iff fun _ => by - simp only [← NNReal.coe_le_coe, coe_nndist, dist_eq, max_le_iff, abs_sub_le_iff, + simp only [max_le_iff, tsub_le_iff_right (α := ℝ≥0)] + simp only [← NNReal.coe_le_coe, coe_nndist, dist_eq, abs_sub_le_iff, tsub_le_iff_right, NNReal.coe_add] #align nnreal.nndist_eq NNReal.nndist_eq From d61c95e1653dffe3f92c8927a905826929f50bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 18 Dec 2023 07:15:58 +0000 Subject: [PATCH 052/353] chore: Rename pow monotonicity lemmas (#9095) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The names for lemmas about monotonicity of `(a ^ ·)` and `(· ^ n)` were a mess. This PR tidies up everything related by following the naming convention for `(a * ·)` and `(· * b)`. Namely, `(a ^ ·)` is `pow_right` and `(· ^ n)` is `pow_left` in lemma names. All lemma renames follow the corresponding multiplication lemma names closely. ## Renames ### `Algebra.GroupPower.Order` * `pow_mono` → `pow_right_mono` * `pow_le_pow` → `pow_le_pow_right` * `pow_le_pow_of_le_left` → `pow_le_pow_left` * `pow_lt_pow_of_lt_left` → `pow_lt_pow_left` * `strictMonoOn_pow` → `pow_left_strictMonoOn` * `pow_strictMono_right` → `pow_right_strictMono` * `pow_lt_pow` → `pow_lt_pow_right` * `pow_lt_pow_iff` → `pow_lt_pow_iff_right` * `pow_le_pow_iff` → `pow_le_pow_iff_right` * `self_lt_pow` → `lt_self_pow` * `strictAnti_pow` → `pow_right_strictAnti` * `pow_lt_pow_iff_of_lt_one` → `pow_lt_pow_iff_right_of_lt_one` * `pow_lt_pow_of_lt_one` → `pow_lt_pow_right_of_lt_one` * `lt_of_pow_lt_pow` → `lt_of_pow_lt_pow_left` * `le_of_pow_le_pow` → `le_of_pow_le_pow_left` * `pow_lt_pow₀` → `pow_lt_pow_right₀` ### `Algebra.GroupPower.CovariantClass` * `pow_le_pow_of_le_left'` → `pow_le_pow_left'` * `nsmul_le_nsmul_of_le_right` → `nsmul_le_nsmul_right` * `pow_lt_pow'` → `pow_lt_pow_right'` * `nsmul_lt_nsmul` → `nsmul_lt_nsmul_left` * `pow_strictMono_left` → `pow_right_strictMono'` * `nsmul_strictMono_right` → `nsmul_left_strictMono` * `StrictMono.pow_right'` → `StrictMono.pow_const` * `StrictMono.nsmul_left` → `StrictMono.const_nsmul` * `pow_strictMono_right'` → `pow_left_strictMono` * `nsmul_strictMono_left` → `nsmul_right_strictMono` * `Monotone.pow_right` → `Monotone.pow_const` * `Monotone.nsmul_left` → `Monotone.const_nsmul` * `lt_of_pow_lt_pow'` → `lt_of_pow_lt_pow_left'` * `lt_of_nsmul_lt_nsmul` → `lt_of_nsmul_lt_nsmul_right` * `pow_le_pow'` → `pow_le_pow_right'` * `nsmul_le_nsmul` → `nsmul_le_nsmul_left` * `pow_le_pow_of_le_one'` → `pow_le_pow_right_of_le_one'` * `nsmul_le_nsmul_of_nonpos` → `nsmul_le_nsmul_left_of_nonpos` * `le_of_pow_le_pow'` → `le_of_pow_le_pow_left'` * `le_of_nsmul_le_nsmul'` → `le_of_nsmul_le_nsmul_right'` * `pow_le_pow_iff'` → `pow_le_pow_iff_right'` * `nsmul_le_nsmul_iff` → `nsmul_le_nsmul_iff_left` * `pow_lt_pow_iff'` → `pow_lt_pow_iff_right'` * `nsmul_lt_nsmul_iff` → `nsmul_lt_nsmul_iff_left` ### `Data.Nat.Pow` * `Nat.pow_lt_pow_of_lt_left` → `Nat.pow_lt_pow_left` * `Nat.pow_le_iff_le_left` → `Nat.pow_le_pow_iff_left` * `Nat.pow_lt_iff_lt_left` → `Nat.pow_lt_pow_iff_left` ## Lemmas added * `pow_le_pow_iff_left` * `pow_lt_pow_iff_left` * `pow_right_injective` * `pow_right_inj` * `Nat.pow_le_pow_left` to have the correct name since `Nat.pow_le_pow_of_le_left` is in Std. * `Nat.pow_le_pow_right` to have the correct name since `Nat.pow_le_pow_of_le_right` is in Std. ## Lemmas removed * `self_le_pow` was a duplicate of `le_self_pow`. * `Nat.pow_lt_pow_of_lt_right` is defeq to `pow_lt_pow_right`. * `Nat.pow_right_strictMono` is defeq to `pow_right_strictMono`. * `Nat.pow_le_iff_le_right` is defeq to `pow_le_pow_iff_right`. * `Nat.pow_lt_iff_lt_right` is defeq to `pow_lt_pow_iff_right`. ## Other changes * A bunch of proofs have been golfed. * Some lemma assumptions have been turned from `0 < n` or `1 ≤ n` to `n ≠ 0`. * A few `Nat` lemmas have been `protected`. * One docstring has been fixed. --- Archive/Imo/Imo1962Q1.lean | 5 +- Archive/Imo/Imo1969Q1.lean | 2 +- Archive/Imo/Imo2001Q2.lean | 2 +- Archive/Imo/Imo2006Q3.lean | 2 +- Archive/Imo/Imo2008Q3.lean | 4 +- Archive/Imo/Imo2008Q4.lean | 3 +- Archive/Wiedijk100Theorems/AbelRuffini.lean | 4 +- .../Wiedijk100Theorems/PerfectNumbers.lean | 2 +- .../SumOfPrimeReciprocalsDiverges.lean | 2 +- Mathlib/Algebra/GeomSum.lean | 4 +- .../Algebra/GroupPower/CovariantClass.lean | 114 ++++++----- Mathlib/Algebra/GroupPower/Lemmas.lean | 14 +- Mathlib/Algebra/GroupPower/Order.lean | 178 +++++++++--------- Mathlib/Algebra/Homology/LocalCohomology.lean | 4 +- Mathlib/Algebra/IsPrimePow.lean | 2 +- Mathlib/Algebra/Order/Archimedean.lean | 2 +- Mathlib/Algebra/Order/Field/Basic.lean | 5 +- Mathlib/Algebra/Order/Interval.lean | 4 +- Mathlib/Algebra/Order/Monovary.lean | 24 +-- Mathlib/Algebra/Tropical/Basic.lean | 4 +- Mathlib/Analysis/Analytic/Composition.lean | 4 +- Mathlib/Analysis/Asymptotics/Asymptotics.lean | 15 +- Mathlib/Analysis/BoxIntegral/Basic.lean | 2 +- .../Analysis/Calculus/FDeriv/Measurable.lean | 4 +- Mathlib/Analysis/Complex/Basic.lean | 5 +- .../Complex/UpperHalfPlane/Metric.lean | 2 +- .../Convex/SpecificFunctions/Deriv.lean | 5 +- .../Analysis/Distribution/SchwartzSpace.lean | 8 +- Mathlib/Analysis/InnerProductSpace/Basic.lean | 2 +- .../InnerProductSpace/Projection.lean | 2 +- Mathlib/Analysis/Normed/Field/Basic.lean | 2 +- .../Analysis/NormedSpace/FiniteDimension.lean | 2 +- .../NormedSpace/Multilinear/Basic.lean | 2 +- .../Analysis/NormedSpace/Star/Multiplier.lean | 2 +- Mathlib/Analysis/PSeries.lean | 6 +- Mathlib/Analysis/SpecialFunctions/Exp.lean | 2 +- .../SpecialFunctions/JapaneseBracket.lean | 2 +- .../SpecialFunctions/Pow/Continuity.lean | 2 +- Mathlib/Analysis/SpecificLimits/Basic.lean | 6 +- Mathlib/Analysis/SpecificLimits/FloorPow.lean | 6 +- Mathlib/Analysis/SpecificLimits/Normed.lean | 2 +- Mathlib/Combinatorics/Additive/Behrend.lean | 39 ++-- .../SetFamily/FourFunctions.lean | 3 +- Mathlib/Combinatorics/SetFamily/Kleitman.lean | 2 +- .../SimpleGraph/Regularity/Bound.lean | 2 +- .../SimpleGraph/Regularity/Chunk.lean | 6 +- .../SimpleGraph/Regularity/Increment.lean | 2 +- .../SimpleGraph/Regularity/Lemma.lean | 4 +- Mathlib/Computability/Ackermann.lean | 6 +- Mathlib/Data/Complex/Exponential.lean | 4 +- Mathlib/Data/Nat/Bitwise.lean | 4 +- Mathlib/Data/Nat/Choose/Factorization.lean | 2 +- Mathlib/Data/Nat/Factorial/Basic.lean | 23 +-- Mathlib/Data/Nat/Factorization/Basic.lean | 19 +- Mathlib/Data/Nat/Log.lean | 8 +- Mathlib/Data/Nat/Pow.lean | 99 ++++------ Mathlib/Data/Nat/Size.lean | 4 +- Mathlib/Data/Nat/Squarefree.lean | 2 +- Mathlib/Data/Num/Lemmas.lean | 2 +- .../Data/Polynomial/Degree/CardPowDegree.lean | 4 +- Mathlib/Data/Polynomial/Degree/Lemmas.lean | 2 +- Mathlib/Data/Real/ENNReal.lean | 6 +- Mathlib/Data/Real/Pi/Bounds.lean | 4 +- Mathlib/Data/Real/Pi/Leibniz.lean | 4 +- Mathlib/FieldTheory/Finite/Basic.lean | 4 +- Mathlib/FieldTheory/Finite/Polynomial.lean | 2 +- Mathlib/GroupTheory/Archimedean.lean | 2 +- Mathlib/GroupTheory/Schreier.lean | 2 +- Mathlib/LinearAlgebra/AdicCompletion.lean | 2 +- Mathlib/MeasureTheory/Group/AddCircle.lean | 2 +- .../MeasureTheory/Integral/PeakFunction.lean | 4 +- Mathlib/MeasureTheory/Measure/Hausdorff.lean | 2 +- .../Measure/Lebesgue/EqHaar.lean | 2 +- Mathlib/NumberTheory/Bertrand.lean | 4 +- .../ClassNumber/AdmissibleCardPowDegree.lean | 2 +- Mathlib/NumberTheory/ClassNumber/Finite.lean | 2 +- .../Cyclotomic/PrimitiveRoots.lean | 2 +- Mathlib/NumberTheory/Divisors.lean | 8 +- Mathlib/NumberTheory/EulerProduct/Basic.lean | 2 +- Mathlib/NumberTheory/FLT/Four.lean | 2 +- Mathlib/NumberTheory/FermatPsp.lean | 11 +- .../Liouville/LiouvilleNumber.lean | 2 +- Mathlib/NumberTheory/LucasLehmer.lean | 22 +-- Mathlib/NumberTheory/Multiplicity.lean | 20 +- .../NumberField/Discriminant.lean | 4 +- Mathlib/NumberTheory/NumberField/Units.lean | 2 +- Mathlib/NumberTheory/Padics/Hensel.lean | 6 +- .../NumberTheory/Padics/PadicIntegers.lean | 2 +- Mathlib/NumberTheory/Padics/PadicVal.lean | 2 +- Mathlib/NumberTheory/Padics/RingHoms.lean | 2 +- Mathlib/NumberTheory/PellMatiyasevic.lean | 4 +- Mathlib/NumberTheory/RamificationInertia.lean | 12 +- Mathlib/NumberTheory/SumFourSquares.lean | 2 +- Mathlib/Order/Filter/Archimedean.lean | 2 +- Mathlib/Order/Filter/AtTopBot.lean | 2 +- Mathlib/Probability/StrongLaw.lean | 2 +- Mathlib/RingTheory/Artinian.lean | 2 +- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 10 +- .../DiscreteValuationRing/TFAE.lean | 6 +- Mathlib/RingTheory/Etale.lean | 2 +- Mathlib/RingTheory/Finiteness.lean | 4 +- Mathlib/RingTheory/Henselian.lean | 6 +- Mathlib/RingTheory/Ideal/Operations.lean | 10 +- Mathlib/RingTheory/LittleWedderburn.lean | 2 +- Mathlib/RingTheory/Perfection.lean | 4 +- Mathlib/RingTheory/Polynomial/Basic.lean | 4 +- .../Polynomial/Cyclotomic/Expand.lean | 2 +- Mathlib/RingTheory/QuotientNilpotent.lean | 2 +- Mathlib/RingTheory/Valuation/Integral.lean | 4 +- Mathlib/RingTheory/WittVector/Frobenius.lean | 2 +- Mathlib/Tactic/GCongr.lean | 8 +- .../Topology/Algebra/InfiniteSum/Order.lean | 2 +- .../Algebra/Nonarchimedean/AdicTopology.lean | 8 +- .../Topology/EMetricSpace/Paracompact.lean | 2 +- Mathlib/Topology/Instances/NNReal.lean | 2 +- .../MetricSpace/HausdorffDistance.lean | 2 +- Mathlib/Topology/MetricSpace/PiNat.lean | 6 +- Mathlib/Topology/Metrizable/Uniformity.lean | 2 +- Mathlib/Topology/UnitInterval.lean | 4 +- 119 files changed, 449 insertions(+), 503 deletions(-) diff --git a/Archive/Imo/Imo1962Q1.lean b/Archive/Imo/Imo1962Q1.lean index 97245b3333242..6a05b328784b8 100644 --- a/Archive/Imo/Imo1962Q1.lean +++ b/Archive/Imo/Imo1962Q1.lean @@ -117,11 +117,10 @@ theorem case_more_digits {c n : ℕ} (h1 : (digits 10 c).length ≥ 6) (h2 : Pro intro h4 have h5 : (digits 10 c).length = 0 := by simp [h4] exact case_0_digit h5 h2 - have h6 : 2 ≤ 10 := by decide calc n ≥ 10 * c := le.intro h2.left.symm - _ ≥ 10 ^ (digits 10 c).length := (base_pow_length_digits_le 10 c h6 h3) - _ ≥ 10 ^ 6 := ((pow_le_iff_le_right h6).mpr h1) + _ ≥ 10 ^ (digits 10 c).length := (base_pow_length_digits_le 10 c (by decide) h3) + _ ≥ 10 ^ 6 := pow_le_pow_right (by decide) h1 _ ≥ 153846 := by norm_num #align imo1962_q1.case_more_digits Imo1962Q1.case_more_digits diff --git a/Archive/Imo/Imo1969Q1.lean b/Archive/Imo/Imo1969Q1.lean index ce92074f30253..e9f7210443165 100644 --- a/Archive/Imo/Imo1969Q1.lean +++ b/Archive/Imo/Imo1969Q1.lean @@ -86,7 +86,7 @@ theorem aChoice_good (b : ℕ) : aChoice b ∈ goodNats := /-- `aChoice` is a strictly monotone function; this is easily proven by chaining together lemmas in the `strictMono` namespace. -/ theorem aChoice_strictMono : StrictMono aChoice := - ((strictMono_id.const_add 2).nat_pow (by decide : 0 < 4)).const_mul (by decide : 0 < 4) + ((strictMono_id.const_add 2).nat_pow (by decide)).const_mul (by decide) #align imo1969_q1.a_choice_strict_mono Imo1969Q1.aChoice_strictMono end Imo1969Q1 diff --git a/Archive/Imo/Imo2001Q2.lean b/Archive/Imo/Imo2001Q2.lean index 3e8528f7ef2ef..619eb77abdf50 100644 --- a/Archive/Imo/Imo2001Q2.lean +++ b/Archive/Imo/Imo2001Q2.lean @@ -41,7 +41,7 @@ theorem bound (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : = a ^ 3 * (a * sqrt ((a ^ 3) ^ 2 + (8:ℝ) * b ^ 3 * c ^ 3)) := by ring _ ≤ a ^ 3 * (a ^ 4 + b ^ 4 + c ^ 4) := ?_ gcongr - apply le_of_pow_le_pow _ (by positivity) zero_lt_two + apply le_of_pow_le_pow_left two_ne_zero (by positivity) rw [mul_pow, sq_sqrt (by positivity), ← sub_nonneg] calc (a ^ 4 + b ^ 4 + c ^ 4) ^ 2 - a ^ 2 * ((a ^ 3) ^ 2 + 8 * b ^ 3 * c ^ 3) diff --git a/Archive/Imo/Imo2006Q3.lean b/Archive/Imo/Imo2006Q3.lean index 914ab33ee7c8c..9a31c97393455 100644 --- a/Archive/Imo/Imo2006Q3.lean +++ b/Archive/Imo/Imo2006Q3.lean @@ -71,7 +71,7 @@ theorem subst_wlog {x y z s : ℝ} (hxy : 0 ≤ x * y) (hxyz : x + y + z = 0) : _ ≤ (2 * (x ^ 2 + y ^ 2 + (x + y) ^ 2) + 2 * s ^ 2) ^ 4 / 4 ^ 4 := by gcongr (?_ + _) ^ 4 / _ apply rhs_ineq - refine le_of_pow_le_pow 2 (by positivity) (by positivity) ?_ + refine le_of_pow_le_pow_left two_ne_zero (by positivity) ?_ calc (32 * |x * y * z * s|) ^ 2 = 32 * (2 * s ^ 2 * (16 * x ^ 2 * y ^ 2 * (x + y) ^ 2)) := by rw [mul_pow, sq_abs, hz]; ring diff --git a/Archive/Imo/Imo2008Q3.lean b/Archive/Imo/Imo2008Q3.lean index 32d6e8437a59b..f199a524867c0 100644 --- a/Archive/Imo/Imo2008Q3.lean +++ b/Archive/Imo/Imo2008Q3.lean @@ -62,10 +62,10 @@ theorem p_lemma (p : ℕ) (hpp : Nat.Prime p) (hp_mod_4_eq_1 : p ≡ 1 [MOD 4]) have hreal₂ : (p : ℝ) > 20 := by assumption_mod_cast have hreal₃ : (k : ℝ) ^ 2 + 4 ≥ p := by assumption_mod_cast have hreal₅ : (k : ℝ) > 4 := by - refine' lt_of_pow_lt_pow 2 k.cast_nonneg _ + refine' lt_of_pow_lt_pow_left 2 k.cast_nonneg _ linarith only [hreal₂, hreal₃] have hreal₆ : (k : ℝ) > sqrt (2 * n) := by - refine' lt_of_pow_lt_pow 2 k.cast_nonneg _ + refine' lt_of_pow_lt_pow_left 2 k.cast_nonneg _ rw [sq_sqrt (mul_nonneg zero_le_two n.cast_nonneg)] linarith only [hreal₁, hreal₃, hreal₅] exact ⟨n, hnat₁, by linarith only [hreal₆, hreal₁]⟩ diff --git a/Archive/Imo/Imo2008Q4.lean b/Archive/Imo/Imo2008Q4.lean index 4619f634d21ab..f1a306321dc7f 100644 --- a/Archive/Imo/Imo2008Q4.lean +++ b/Archive/Imo/Imo2008Q4.lean @@ -29,8 +29,7 @@ open Real namespace Imo2008Q4 theorem abs_eq_one_of_pow_eq_one (x : ℝ) (n : ℕ) (hn : n ≠ 0) (h : x ^ n = 1) : |x| = 1 := by - rw [← pow_left_inj (abs_nonneg x) zero_le_one (pos_iff_ne_zero.2 hn), one_pow, pow_abs, h, - abs_one] + rw [← pow_left_inj (abs_nonneg x) zero_le_one hn, one_pow, pow_abs, h, abs_one] #align imo2008_q4.abs_eq_one_of_pow_eq_one Imo2008Q4.abs_eq_one_of_pow_eq_one end Imo2008Q4 diff --git a/Archive/Wiedijk100Theorems/AbelRuffini.lean b/Archive/Wiedijk100Theorems/AbelRuffini.lean index f0b4efa515e72..0e2091001b402 100644 --- a/Archive/Wiedijk100Theorems/AbelRuffini.lean +++ b/Archive/Wiedijk100Theorems/AbelRuffini.lean @@ -126,7 +126,7 @@ theorem real_roots_Phi_ge_aux (hab : b < a) : have hfa : 0 ≤ f a := by -- Porting note: was `simp_rw` simp only [hf, ← sq] - refine' add_nonneg (sub_nonneg.mpr (pow_le_pow ha _)) _ <;> norm_num + refine' add_nonneg (sub_nonneg.mpr (pow_le_pow_right ha _)) _ <;> norm_num obtain ⟨x, ⟨-, hx1⟩, hx2⟩ := intermediate_value_Ico' hle (hc _) (Set.mem_Ioc.mpr ⟨hf1, hf0⟩) obtain ⟨y, ⟨hy1, -⟩, hy2⟩ := intermediate_value_Ioc ha (hc _) (Set.mem_Ioc.mpr ⟨hf1, hfa⟩) exact ⟨x, y, (hx1.trans hy1).ne, hx2, hy2⟩ @@ -137,7 +137,7 @@ theorem real_roots_Phi_ge_aux (hab : b < a) : f (-a) = (a : ℝ) ^ 2 - (a : ℝ) ^ 5 + b := by norm_num [hf, ← sq, sub_eq_add_neg, add_comm, Odd.neg_pow (by decide : Odd 5)] _ ≤ (a : ℝ) ^ 2 - (a : ℝ) ^ 3 + (a - 1) := by - refine' add_le_add (sub_le_sub_left (pow_le_pow ha _) _) _ <;> linarith + refine' add_le_add (sub_le_sub_left (pow_le_pow_right ha _) _) _ <;> linarith _ = -((a : ℝ) - 1) ^ 2 * (a + 1) := by ring _ ≤ 0 := by nlinarith have ha' := neg_nonpos.mpr (hle.trans ha) diff --git a/Archive/Wiedijk100Theorems/PerfectNumbers.lean b/Archive/Wiedijk100Theorems/PerfectNumbers.lean index c610c03973978..f0bd7ac012d17 100644 --- a/Archive/Wiedijk100Theorems/PerfectNumbers.lean +++ b/Archive/Wiedijk100Theorems/PerfectNumbers.lean @@ -115,7 +115,7 @@ theorem eq_two_pow_mul_prime_mersenne_of_even_perfect {n : ℕ} (ev : Even n) (p | .succ k => apply ne_of_lt _ jcon2 rw [mersenne, ← Nat.pred_eq_sub_one, Nat.lt_pred_iff, ← pow_one (Nat.succ 1)] - apply pow_lt_pow (Nat.lt_succ_self 1) (Nat.succ_lt_succ (Nat.succ_pos k)) + apply pow_lt_pow_right (Nat.lt_succ_self 1) (Nat.succ_lt_succ (Nat.succ_pos k)) contrapose! hm simp [hm] #align theorems_100.nat.eq_two_pow_mul_prime_mersenne_of_even_perfect Theorems100.Nat.eq_two_pow_mul_prime_mersenne_of_even_perfect diff --git a/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean b/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean index ac3bc23dc7090..66e17dcf383cb 100644 --- a/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean +++ b/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean @@ -168,7 +168,7 @@ theorem card_le_two_pow {x k : ℕ} : card M₁ ≤ card (image f K) := card_le_of_subset h _ ≤ card K := card_image_le _ ≤ 2 ^ card (image Nat.succ (range k)) := by simp only [card_powerset]; rfl - _ ≤ 2 ^ card (range k) := (pow_le_pow one_le_two card_image_le) + _ ≤ 2 ^ card (range k) := (pow_le_pow_right one_le_two card_image_le) _ = 2 ^ k := by rw [card_range k] #align theorems_100.card_le_two_pow Theorems100.card_le_two_pow diff --git a/Mathlib/Algebra/GeomSum.lean b/Mathlib/Algebra/GeomSum.lean index 99d2b0e0e9b84..c5ed8501dd2b9 100644 --- a/Mathlib/Algebra/GeomSum.lean +++ b/Mathlib/Algebra/GeomSum.lean @@ -209,9 +209,9 @@ theorem sub_one_dvd_pow_sub_one [Ring α] (x : α) (n : ℕ) : theorem nat_sub_dvd_pow_sub_pow (x y n : ℕ) : x - y ∣ x ^ n - y ^ n := by cases' le_or_lt y x with h h - · have : y ^ n ≤ x ^ n := Nat.pow_le_pow_of_le_left h _ + · have : y ^ n ≤ x ^ n := Nat.pow_le_pow_left h _ exact mod_cast sub_dvd_pow_sub_pow (x : ℤ) (↑y) n - · have : x ^ n ≤ y ^ n := Nat.pow_le_pow_of_le_left h.le _ + · have : x ^ n ≤ y ^ n := Nat.pow_le_pow_left h.le _ exact (Nat.sub_eq_zero_of_le this).symm ▸ dvd_zero (x - y) #align nat_sub_dvd_pow_sub_pow nat_sub_dvd_pow_sub_pow diff --git a/Mathlib/Algebra/GroupPower/CovariantClass.lean b/Mathlib/Algebra/GroupPower/CovariantClass.lean index fde8ae6af4676..a89c22c72e81f 100644 --- a/Mathlib/Algebra/GroupPower/CovariantClass.lean +++ b/Mathlib/Algebra/GroupPower/CovariantClass.lean @@ -31,15 +31,15 @@ section Left variable [CovariantClass M M (· * ·) (· ≤ ·)] {x : M} -@[to_additive (attr := mono) nsmul_le_nsmul_of_le_right] -theorem pow_le_pow_of_le_left' [CovariantClass M M (swap (· * ·)) (· ≤ ·)] {a b : M} (hab : a ≤ b) : +@[to_additive (attr := mono) nsmul_le_nsmul_right] +theorem pow_le_pow_left' [CovariantClass M M (swap (· * ·)) (· ≤ ·)] {a b : M} (hab : a ≤ b) : ∀ i : ℕ, a ^ i ≤ b ^ i | 0 => by simp | k + 1 => by rw [pow_succ, pow_succ] - exact mul_le_mul' hab (pow_le_pow_of_le_left' hab k) -#align pow_le_pow_of_le_left' pow_le_pow_of_le_left' -#align nsmul_le_nsmul_of_le_right nsmul_le_nsmul_of_le_right + exact mul_le_mul' hab (pow_le_pow_left' hab k) +#align pow_le_pow_of_le_left' pow_le_pow_left' +#align nsmul_le_nsmul_of_le_right nsmul_le_nsmul_right @[to_additive nsmul_nonneg] theorem one_le_pow_of_one_le' {a : M} (H : 1 ≤ a) : ∀ n : ℕ, 1 ≤ a ^ n @@ -56,20 +56,20 @@ theorem pow_le_one' {a : M} (H : a ≤ 1) (n : ℕ) : a ^ n ≤ 1 := #align pow_le_one' pow_le_one' #align nsmul_nonpos nsmul_nonpos -@[to_additive nsmul_le_nsmul] -theorem pow_le_pow' {a : M} {n m : ℕ} (ha : 1 ≤ a) (h : n ≤ m) : a ^ n ≤ a ^ m := +@[to_additive nsmul_le_nsmul_left] +theorem pow_le_pow_right' {a : M} {n m : ℕ} (ha : 1 ≤ a) (h : n ≤ m) : a ^ n ≤ a ^ m := let ⟨k, hk⟩ := Nat.le.dest h calc a ^ n ≤ a ^ n * a ^ k := le_mul_of_one_le_right' (one_le_pow_of_one_le' ha _) _ = a ^ m := by rw [← hk, pow_add] -#align pow_le_pow' pow_le_pow' -#align nsmul_le_nsmul nsmul_le_nsmul +#align pow_le_pow' pow_le_pow_right' +#align nsmul_le_nsmul nsmul_le_nsmul_left -@[to_additive nsmul_le_nsmul_of_nonpos] -theorem pow_le_pow_of_le_one' {a : M} {n m : ℕ} (ha : a ≤ 1) (h : n ≤ m) : a ^ m ≤ a ^ n := - @pow_le_pow' Mᵒᵈ _ _ _ _ _ _ ha h -#align pow_le_pow_of_le_one' pow_le_pow_of_le_one' -#align nsmul_le_nsmul_of_nonpos nsmul_le_nsmul_of_nonpos +@[to_additive nsmul_le_nsmul_left_of_nonpos] +theorem pow_le_pow_right_of_le_one' {a : M} {n m : ℕ} (ha : a ≤ 1) (h : n ≤ m) : a ^ m ≤ a ^ n := + pow_le_pow_right' (M := Mᵒᵈ) ha h +#align pow_le_pow_of_le_one' pow_le_pow_right_of_le_one' +#align nsmul_le_nsmul_of_nonpos nsmul_le_nsmul_left_of_nonpos @[to_additive nsmul_pos] theorem one_lt_pow' {a : M} (ha : 1 < a) {k : ℕ} (hk : k ≠ 0) : 1 < a ^ k := by @@ -88,20 +88,20 @@ theorem pow_lt_one' {a : M} (ha : a < 1) {k : ℕ} (hk : k ≠ 0) : a ^ k < 1 := #align pow_lt_one' pow_lt_one' #align nsmul_neg nsmul_neg -@[to_additive nsmul_lt_nsmul] -theorem pow_lt_pow' [CovariantClass M M (· * ·) (· < ·)] {a : M} {n m : ℕ} (ha : 1 < a) +@[to_additive nsmul_lt_nsmul_left] +theorem pow_lt_pow_right' [CovariantClass M M (· * ·) (· < ·)] {a : M} {n m : ℕ} (ha : 1 < a) (h : n < m) : a ^ n < a ^ m := by rcases Nat.le.dest h with ⟨k, rfl⟩; clear h rw [pow_add, pow_succ', mul_assoc, ← pow_succ] exact lt_mul_of_one_lt_right' _ (one_lt_pow' ha k.succ_ne_zero) -#align pow_lt_pow' pow_lt_pow' -#align nsmul_lt_nsmul nsmul_lt_nsmul +#align pow_lt_pow_right' pow_lt_pow_right' +#align nsmul_lt_nsmul_left nsmul_lt_nsmul_left -@[to_additive nsmul_strictMono_right] -theorem pow_strictMono_left [CovariantClass M M (· * ·) (· < ·)] {a : M} (ha : 1 < a) : - StrictMono ((a ^ ·) : ℕ → M) := fun _ _ => pow_lt_pow' ha -#align pow_strict_mono_left pow_strictMono_left -#align nsmul_strict_mono_right nsmul_strictMono_right +@[to_additive nsmul_left_strictMono] +theorem pow_right_strictMono' [CovariantClass M M (· * ·) (· < ·)] {a : M} (ha : 1 < a) : + StrictMono ((a ^ ·) : ℕ → M) := fun _ _ => pow_lt_pow_right' ha +#align pow_strict_mono_left pow_right_strictMono' +#align nsmul_strict_mono_right nsmul_left_strictMono @[to_additive Left.pow_nonneg] theorem Left.one_le_pow_of_le (hx : 1 ≤ x) : ∀ {n : ℕ}, 1 ≤ x ^ n @@ -150,24 +150,22 @@ end Right section CovariantLTSwap variable [Preorder β] [CovariantClass M M (· * ·) (· < ·)] - [CovariantClass M M (swap (· * ·)) (· < ·)] {f : β → M} + [CovariantClass M M (swap (· * ·)) (· < ·)] {f : β → M} {n : ℕ} -@[to_additive StrictMono.nsmul_left] -theorem StrictMono.pow_right' (hf : StrictMono f) : ∀ {n : ℕ}, n ≠ 0 → StrictMono fun a => f a ^ n +@[to_additive StrictMono.const_nsmul] +theorem StrictMono.pow_const (hf : StrictMono f) : ∀ {n : ℕ}, n ≠ 0 → StrictMono (f · ^ n) | 0, hn => (hn rfl).elim | 1, _ => by simpa | Nat.succ <| Nat.succ n, _ => by - simp_rw [pow_succ _ (n + 1)] - exact hf.mul' (StrictMono.pow_right' hf n.succ_ne_zero) -#align strict_mono.pow_right' StrictMono.pow_right' -#align strict_mono.nsmul_left StrictMono.nsmul_left - -/-- See also `pow_strictMono_right` -/ -@[to_additive nsmul_strictMono_left] -- Porting note: nolint to_additive_doc -theorem pow_strictMono_right' {n : ℕ} (hn : n ≠ 0) : StrictMono fun a : M => a ^ n := - strictMono_id.pow_right' hn -#align pow_strict_mono_right' pow_strictMono_right' -#align nsmul_strict_mono_left nsmul_strictMono_left + simpa only [pow_succ] using hf.mul' (hf.pow_const n.succ_ne_zero) +#align strict_mono.pow_const StrictMono.pow_const +#align strict_mono.const_nsmul StrictMono.const_nsmul + +/-- See also `pow_left_strictMonoOn`. -/ +@[to_additive nsmul_right_strictMono] -- Porting note: nolint to_additive_doc +theorem pow_left_strictMono (hn : n ≠ 0) : StrictMono (· ^ n : M → M) := strictMono_id.pow_const hn +#align pow_strict_mono_right' pow_left_strictMono +#align nsmul_strict_mono_left nsmul_right_strictMono end CovariantLTSwap @@ -176,14 +174,14 @@ section CovariantLESwap variable [Preorder β] [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] -@[to_additive Monotone.nsmul_left] +@[to_additive Monotone.const_nsmul] theorem Monotone.pow_right {f : β → M} (hf : Monotone f) : ∀ n : ℕ, Monotone fun a => f a ^ n | 0 => by simpa using monotone_const | n + 1 => by simp_rw [pow_succ] exact hf.mul' (Monotone.pow_right hf _) #align monotone.pow_right Monotone.pow_right -#align monotone.nsmul_left Monotone.nsmul_left +#align monotone.const_nsmul Monotone.const_nsmul @[to_additive nsmul_mono_left] theorem pow_mono_right (n : ℕ) : Monotone fun a : M => a ^ n := @@ -258,17 +256,17 @@ theorem pow_eq_one_iff {x : M} {n : ℕ} (hn : n ≠ 0) : x ^ n = 1 ↔ x = 1 := variable [CovariantClass M M (· * ·) (· < ·)] {a : M} {m n : ℕ} -@[to_additive nsmul_le_nsmul_iff] -theorem pow_le_pow_iff' (ha : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := - (pow_strictMono_left ha).le_iff_le -#align pow_le_pow_iff' pow_le_pow_iff' -#align nsmul_le_nsmul_iff nsmul_le_nsmul_iff +@[to_additive nsmul_le_nsmul_iff_left] +theorem pow_le_pow_iff_right' (ha : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := + (pow_right_strictMono' ha).le_iff_le +#align pow_le_pow_iff' pow_le_pow_iff_right' +#align nsmul_le_nsmul_iff nsmul_le_nsmul_iff_left -@[to_additive nsmul_lt_nsmul_iff] -theorem pow_lt_pow_iff' (ha : 1 < a) : a ^ m < a ^ n ↔ m < n := - (pow_strictMono_left ha).lt_iff_lt -#align pow_lt_pow_iff' pow_lt_pow_iff' -#align nsmul_lt_nsmul_iff nsmul_lt_nsmul_iff +@[to_additive nsmul_lt_nsmul_iff_left] +theorem pow_lt_pow_iff_right' (ha : 1 < a) : a ^ m < a ^ n ↔ m < n := + (pow_right_strictMono' ha).lt_iff_lt +#align pow_lt_pow_iff' pow_lt_pow_iff_right' +#align nsmul_lt_nsmul_iff nsmul_lt_nsmul_iff_left end CovariantLE @@ -276,11 +274,11 @@ section CovariantLESwap variable [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] -@[to_additive lt_of_nsmul_lt_nsmul] -theorem lt_of_pow_lt_pow' {a b : M} (n : ℕ) : a ^ n < b ^ n → a < b := +@[to_additive lt_of_nsmul_lt_nsmul_right] +theorem lt_of_pow_lt_pow_left' {a b : M} (n : ℕ) : a ^ n < b ^ n → a < b := (pow_mono_right _).reflect_lt -#align lt_of_pow_lt_pow' lt_of_pow_lt_pow' -#align lt_of_nsmul_lt_nsmul lt_of_nsmul_lt_nsmul +#align lt_of_pow_lt_pow' lt_of_pow_lt_pow_left' +#align lt_of_nsmul_lt_nsmul lt_of_nsmul_lt_nsmul_right @[to_additive min_lt_of_add_lt_two_nsmul] theorem min_lt_of_mul_lt_sq {a b c : M} (h : a * b < c ^ 2) : min a b < c := by @@ -300,11 +298,11 @@ section CovariantLTSwap variable [CovariantClass M M (· * ·) (· < ·)] [CovariantClass M M (swap (· * ·)) (· < ·)] -@[to_additive le_of_nsmul_le_nsmul] -theorem le_of_pow_le_pow' {a b : M} {n : ℕ} (hn : n ≠ 0) : a ^ n ≤ b ^ n → a ≤ b := - (pow_strictMono_right' hn).le_iff_le.1 -#align le_of_pow_le_pow' le_of_pow_le_pow' -#align le_of_nsmul_le_nsmul le_of_nsmul_le_nsmul +@[to_additive le_of_nsmul_le_nsmul_right'] +theorem le_of_pow_le_pow_left' {a b : M} {n : ℕ} (hn : n ≠ 0) : a ^ n ≤ b ^ n → a ≤ b := + (pow_left_strictMono hn).le_iff_le.1 +#align le_of_pow_le_pow' le_of_pow_le_pow_left' +#align le_of_nsmul_le_nsmul le_of_nsmul_le_nsmul_right' @[to_additive min_le_of_add_le_two_nsmul] theorem min_le_of_mul_le_sq {a b c : M} (h : a * b ≤ c ^ 2) : min a b ≤ c := by diff --git a/Mathlib/Algebra/GroupPower/Lemmas.lean b/Mathlib/Algebra/GroupPower/Lemmas.lean index 5f081f7272ad8..9662035c32d90 100644 --- a/Mathlib/Algebra/GroupPower/Lemmas.lean +++ b/Mathlib/Algebra/GroupPower/Lemmas.lean @@ -326,12 +326,12 @@ theorem one_lt_zpow' (ha : 1 < a) {k : ℤ} (hk : (0 : ℤ) < k) : 1 < a ^ k := #align zsmul_pos zsmul_pos @[to_additive zsmul_strictMono_left] -theorem zpow_strictMono_right (ha : 1 < a) : StrictMono fun n : ℤ => a ^ n := fun m n h => +theorem zpow_right_strictMono (ha : 1 < a) : StrictMono fun n : ℤ => a ^ n := fun 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 -#align zpow_strict_mono_right zpow_strictMono_right +#align zpow_strict_mono_right zpow_right_strictMono #align zsmul_strict_mono_left zsmul_strictMono_left @[to_additive zsmul_mono_left] @@ -351,19 +351,19 @@ theorem zpow_le_zpow (ha : 1 ≤ a) (h : m ≤ n) : a ^ m ≤ a ^ n := @[to_additive] theorem zpow_lt_zpow (ha : 1 < a) (h : m < n) : a ^ m < a ^ n := - zpow_strictMono_right ha h + zpow_right_strictMono ha h #align zpow_lt_zpow zpow_lt_zpow #align zsmul_lt_zsmul zsmul_lt_zsmul @[to_additive] theorem zpow_le_zpow_iff (ha : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := - (zpow_strictMono_right ha).le_iff_le + (zpow_right_strictMono ha).le_iff_le #align zpow_le_zpow_iff zpow_le_zpow_iff #align zsmul_le_zsmul_iff zsmul_le_zsmul_iff @[to_additive] theorem zpow_lt_zpow_iff (ha : 1 < a) : a ^ m < a ^ n ↔ m < n := - (zpow_strictMono_right ha).lt_iff_lt + (zpow_right_strictMono ha).lt_iff_lt #align zpow_lt_zpow_iff zpow_lt_zpow_iff #align zsmul_lt_zsmul_iff zsmul_lt_zsmul_iff @@ -746,9 +746,9 @@ theorem strictMono_pow_bit1 (n : ℕ) : StrictMono fun a : R => a ^ bit1 n := by cases' le_total a 0 with ha ha · cases' le_or_lt b 0 with hb hb · rw [← neg_lt_neg_iff, ← neg_pow_bit1, ← neg_pow_bit1] - exact pow_lt_pow_of_lt_left (neg_lt_neg hab) (neg_nonneg.2 hb) (bit1_pos (zero_le n)) + exact pow_lt_pow_left (neg_lt_neg hab) (neg_nonneg.2 hb) n.bit1_ne_zero · exact (pow_bit1_nonpos_iff.2 ha).trans_lt (pow_bit1_pos_iff.2 hb) - · exact pow_lt_pow_of_lt_left hab ha (bit1_pos (zero_le n)) + · exact pow_lt_pow_left hab ha n.bit1_ne_zero #align strict_mono_pow_bit1 strictMono_pow_bit1 end bit1 diff --git a/Mathlib/Algebra/GroupPower/Order.lean b/Mathlib/Algebra/GroupPower/Order.lean index d24b7c00f7990..b75018c35ff98 100644 --- a/Mathlib/Algebra/GroupPower/Order.lean +++ b/Mathlib/Algebra/GroupPower/Order.lean @@ -19,6 +19,8 @@ Note that some lemmas are in `Algebra/GroupPower/Lemmas.lean` as they import fil depend on this file. -/ +open Function + variable {M R : Type*} namespace CanonicallyOrderedCommSemiring @@ -83,32 +85,26 @@ theorem one_le_pow_of_one_le (H : 1 ≤ a) : ∀ n : ℕ, 1 ≤ a ^ n mul_le_mul H (one_le_pow_of_one_le H n) zero_le_one (le_trans zero_le_one H) #align one_le_pow_of_one_le one_le_pow_of_one_le -theorem pow_mono (h : 1 ≤ a) : Monotone fun n : ℕ => a ^ n := +theorem pow_right_mono (h : 1 ≤ a) : Monotone (a ^ ·) := monotone_nat_of_le_succ fun n => by rw [pow_succ] exact le_mul_of_one_le_left (pow_nonneg (zero_le_one.trans h) _) h -#align pow_mono pow_mono +#align pow_mono pow_right_mono -theorem pow_le_pow (ha : 1 ≤ a) (h : n ≤ m) : a ^ n ≤ a ^ m := - pow_mono ha h -#align pow_le_pow pow_le_pow +theorem pow_le_pow_right (ha : 1 ≤ a) (h : n ≤ m) : a ^ n ≤ a ^ m := pow_right_mono ha h +#align pow_le_pow pow_le_pow_right -theorem le_self_pow (ha : 1 ≤ a) (h : m ≠ 0) : a ≤ a ^ m := - (pow_one a).symm.trans_le (pow_le_pow ha <| pos_iff_ne_zero.mpr h) +theorem le_self_pow (ha : 1 ≤ a) (h : m ≠ 0) : a ≤ a ^ m := by + simpa only [pow_one] using pow_le_pow_right ha <| pos_iff_ne_zero.2 h +#align self_le_pow le_self_pow #align le_self_pow le_self_pow @[mono] -theorem pow_le_pow_of_le_left {a b : R} (ha : 0 ≤ a) (hab : a ≤ b) : ∀ i : ℕ, a ^ i ≤ b ^ i := by - intro i - induction i with - | zero => simp - | succ k ih => - rw [pow_succ, pow_succ] - apply mul_le_mul hab - apply ih - apply pow_nonneg ha - apply le_trans ha hab -#align pow_le_pow_of_le_left pow_le_pow_of_le_left +theorem pow_le_pow_left {a b : R} (ha : 0 ≤ a) (hab : a ≤ b) : ∀ n, a ^ n ≤ b ^ n + | 0 => by simp + | n + 1 => by simpa only [pow_succ] + using mul_le_mul hab (pow_le_pow_left ha hab _) (pow_nonneg ha _) (ha.trans hab) +#align pow_le_pow_of_le_left pow_le_pow_left theorem one_lt_pow (ha : 1 < a) : ∀ {n : ℕ} (_ : n ≠ 0), 1 < a ^ n | 0, h => (h rfl).elim @@ -123,60 +119,52 @@ section StrictOrderedSemiring variable [StrictOrderedSemiring R] {a x y : R} {n m : ℕ} -theorem pow_lt_pow_of_lt_left (h : x < y) (hx : 0 ≤ x) : ∀ {n : ℕ}, 0 < n → x ^ n < y ^ n +theorem pow_lt_pow_left (h : x < y) (hx : 0 ≤ x) : ∀ {n : ℕ}, n ≠ 0 → x ^ n < y ^ n | 0, hn => by contradiction | n + 1, _ => by simpa only [pow_succ'] using - mul_lt_mul_of_le_of_le' (pow_le_pow_of_le_left hx h.le _) h (pow_pos (hx.trans_lt h) _) hx -#align pow_lt_pow_of_lt_left pow_lt_pow_of_lt_left + mul_lt_mul_of_le_of_le' (pow_le_pow_left hx h.le _) h (pow_pos (hx.trans_lt h) _) hx +#align pow_lt_pow_of_lt_left pow_lt_pow_left -theorem strictMonoOn_pow (hn : 0 < n) : StrictMonoOn (fun x : R => x ^ n) (Set.Ici 0) := - fun _ hx _ _ h => pow_lt_pow_of_lt_left h hx hn -#align strict_mono_on_pow strictMonoOn_pow +/-- See also `pow_left_strictMonoOn`. -/ +lemma pow_left_strictMonoOn (hn : n ≠ 0) : StrictMonoOn (· ^ n : R → R) (Set.Ici 0) := + fun _a ha _b _ hab ↦ pow_lt_pow_left hab ha hn +#align strict_mono_on_pow pow_left_strictMonoOn -theorem pow_strictMono_right (h : 1 < a) : StrictMono fun n : ℕ => a ^ n := +/-- See also `pow_right_strictMono'`. -/ +lemma pow_right_strictMono (h : 1 < a) : StrictMono (a ^ ·) := have : 0 < a := zero_le_one.trans_lt h strictMono_nat_of_lt_succ fun n => by simpa only [one_mul, pow_succ] using mul_lt_mul h (le_refl (a ^ n)) (pow_pos this _) this.le -#align pow_strict_mono_right pow_strictMono_right - -theorem pow_lt_pow (h : 1 < a) (h2 : n < m) : a ^ n < a ^ m := - pow_strictMono_right h h2 -#align pow_lt_pow pow_lt_pow +#align pow_strict_mono_right pow_right_strictMono -theorem pow_lt_pow_iff (h : 1 < a) : a ^ n < a ^ m ↔ n < m := - (pow_strictMono_right h).lt_iff_lt -#align pow_lt_pow_iff pow_lt_pow_iff +theorem pow_lt_pow_right (h : 1 < a) (hmn : m < n) : a ^ m < a ^ n := pow_right_strictMono h hmn +#align pow_lt_pow_right pow_lt_pow_right -theorem pow_le_pow_iff (h : 1 < a) : a ^ n ≤ a ^ m ↔ n ≤ m := - (pow_strictMono_right h).le_iff_le -#align pow_le_pow_iff pow_le_pow_iff +lemma pow_lt_pow_iff_right (h : 1 < a) : a ^ n < a ^ m ↔ n < m := (pow_right_strictMono h).lt_iff_lt +#align pow_lt_pow_iff_ pow_lt_pow_iff_right -theorem self_lt_pow (h : 1 < a) (h2 : 1 < m) : a < a ^ m := by - calc - a = a ^ 1 := (pow_one _).symm - _ < a ^ m := pow_lt_pow h h2 +lemma pow_le_pow_iff_right (h : 1 < a) : a ^ n ≤ a ^ m ↔ n ≤ m := (pow_right_strictMono h).le_iff_le +#align pow_le_pow_iff pow_le_pow_iff_right -theorem self_le_pow (h : 1 ≤ a) (h2 : 1 ≤ m) : a ≤ a ^ m := - le_self_pow h <| Nat.one_le_iff_ne_zero.mp h2 +theorem lt_self_pow (h : 1 < a) (hm : 1 < m) : a < a ^ m := by + simpa only [pow_one] using pow_lt_pow_right h hm -theorem strictAnti_pow (h₀ : 0 < a) (h₁ : a < 1) : StrictAnti fun n : ℕ => a ^ n := +theorem pow_right_strictAnti (h₀ : 0 < a) (h₁ : a < 1) : StrictAnti (a ^ ·) := strictAnti_nat_of_succ_lt fun n => by simpa only [pow_succ, one_mul] using mul_lt_mul h₁ le_rfl (pow_pos h₀ n) zero_le_one -#align strict_anti_pow strictAnti_pow +#align strict_anti_pow pow_right_strictAnti -theorem pow_lt_pow_iff_of_lt_one (h₀ : 0 < a) (h₁ : a < 1) : a ^ m < a ^ n ↔ n < m := - (strictAnti_pow h₀ h₁).lt_iff_lt -#align pow_lt_pow_iff_of_lt_one pow_lt_pow_iff_of_lt_one +theorem pow_lt_pow_iff_right_of_lt_one (h₀ : 0 < a) (h₁ : a < 1) : a ^ m < a ^ n ↔ n < m := + (pow_right_strictAnti h₀ h₁).lt_iff_lt +#align pow_lt_pow_iff_of_lt_one pow_lt_pow_iff_right_of_lt_one -theorem pow_lt_pow_of_lt_one (h : 0 < a) (ha : a < 1) {i j : ℕ} (hij : i < j) : a ^ j < a ^ i := - (pow_lt_pow_iff_of_lt_one h ha).2 hij -#align pow_lt_pow_of_lt_one pow_lt_pow_of_lt_one +theorem pow_lt_pow_right_of_lt_one (h₀ : 0 < a) (h₁ : a < 1) (hmn : m < n) : a ^ n < a ^ m := + (pow_lt_pow_iff_right_of_lt_one h₀ h₁).2 hmn +#align pow_lt_pow_of_lt_one pow_lt_pow_right_of_lt_one -theorem pow_lt_self_of_lt_one (h₀ : 0 < a) (h₁ : a < 1) (hn : 1 < n) : a ^ n < a := - calc - a ^ n < a ^ 1 := pow_lt_pow_of_lt_one h₀ h₁ hn - _ = a := pow_one _ +theorem pow_lt_self_of_lt_one (h₀ : 0 < a) (h₁ : a < 1) (hn : 1 < n) : a ^ n < a := by + simpa only [pow_one] using pow_lt_pow_right_of_lt_one h₀ h₁ hn #align pow_lt_self_of_lt_one pow_lt_self_of_lt_one theorem sq_pos_of_pos (ha : 0 < a) : 0 < a ^ 2 := by @@ -208,34 +196,46 @@ theorem sq_pos_of_neg (ha : a < 0) : 0 < a ^ 2 := end StrictOrderedRing section LinearOrderedSemiring +variable [LinearOrderedSemiring R] {a b : R} {m n : ℕ} + +lemma pow_le_pow_iff_left (ha : 0 ≤ a) (hb : 0 ≤ b) (hn : n ≠ 0) : a ^ n ≤ b ^ n ↔ a ≤ b := + (pow_left_strictMonoOn hn).le_iff_le ha hb + +lemma pow_lt_pow_iff_left (ha : 0 ≤ a) (hb : 0 ≤ b) (hn : n ≠ 0) : a ^ n < b ^ n ↔ a < b := + (pow_left_strictMonoOn hn).lt_iff_lt ha hb + +@[simp] +lemma pow_left_inj (ha : 0 ≤ a) (hb : 0 ≤ b) (hn : n ≠ 0) : a ^ n = b ^ n ↔ a = b := + (pow_left_strictMonoOn hn).eq_iff_eq ha hb +#align pow_left_inj pow_left_inj + +lemma pow_right_injective (ha₀ : 0 < a) (ha₁ : a ≠ 1) : Injective (a ^ ·) := by + obtain ha₁ | ha₁ := ha₁.lt_or_lt + · exact (pow_right_strictAnti ha₀ ha₁).injective + · exact (pow_right_strictMono ha₁).injective -variable [LinearOrderedSemiring R] {a b : R} +@[simp] +lemma pow_right_inj (ha₀ : 0 < a) (ha₁ : a ≠ 1) : a ^ m = a ^ n ↔ m = n := + (pow_right_injective ha₀ ha₁).eq_iff -theorem pow_le_one_iff_of_nonneg {a : R} (ha : 0 ≤ a) {n : ℕ} (hn : n ≠ 0) : a ^ n ≤ 1 ↔ a ≤ 1 := by - refine' ⟨_, pow_le_one n ha⟩ - rw [← not_lt, ← not_lt] - exact mt fun h => one_lt_pow h hn +theorem pow_le_one_iff_of_nonneg (ha : 0 ≤ a) (hn : n ≠ 0) : a ^ n ≤ 1 ↔ a ≤ 1 := by + simpa only [one_pow] using pow_le_pow_iff_left ha zero_le_one hn #align pow_le_one_iff_of_nonneg pow_le_one_iff_of_nonneg -theorem one_le_pow_iff_of_nonneg {a : R} (ha : 0 ≤ a) {n : ℕ} (hn : n ≠ 0) : 1 ≤ a ^ n ↔ 1 ≤ a := by - refine' ⟨_, fun h => one_le_pow_of_one_le h n⟩ - rw [← not_lt, ← not_lt] - exact mt fun h => pow_lt_one ha h hn +theorem one_le_pow_iff_of_nonneg (ha : 0 ≤ a) (hn : n ≠ 0) : 1 ≤ a ^ n ↔ 1 ≤ a := by + simpa only [one_pow] using pow_le_pow_iff_left (zero_le_one' R) ha hn #align one_le_pow_iff_of_nonneg one_le_pow_iff_of_nonneg -lemma pow_eq_one_iff_of_nonneg {a : R} (ha : 0 ≤ a) - {n : ℕ} (hn : n ≠ 0) : a ^ n = 1 ↔ a = 1 := - ⟨fun h ↦ le_antisymm ((pow_le_one_iff_of_nonneg ha hn).mp h.le) - ((one_le_pow_iff_of_nonneg ha hn).mp h.ge), - fun h ↦ by rw [h]; exact one_pow _⟩ +theorem pow_lt_one_iff_of_nonneg (ha : 0 ≤ a) (hn : n ≠ 0) : a ^ n < 1 ↔ a < 1 := + lt_iff_lt_of_le_iff_le (one_le_pow_iff_of_nonneg ha hn) +#align pow_lt_one_iff_of_nonneg pow_lt_one_iff_of_nonneg -theorem one_lt_pow_iff_of_nonneg {a : R} (ha : 0 ≤ a) {n : ℕ} (hn : n ≠ 0) : 1 < a ^ n ↔ 1 < a := - lt_iff_lt_of_le_iff_le (pow_le_one_iff_of_nonneg ha hn) +theorem one_lt_pow_iff_of_nonneg (ha : 0 ≤ a) (hn : n ≠ 0) : 1 < a ^ n ↔ 1 < a := by + simpa only [one_pow] using pow_lt_pow_iff_left (zero_le_one' R) ha hn #align one_lt_pow_iff_of_nonneg one_lt_pow_iff_of_nonneg -theorem pow_lt_one_iff_of_nonneg {a : R} (ha : 0 ≤ a) {n : ℕ} (hn : n ≠ 0) : a ^ n < 1 ↔ a < 1 := - lt_iff_lt_of_le_iff_le (one_le_pow_iff_of_nonneg ha hn) -#align pow_lt_one_iff_of_nonneg pow_lt_one_iff_of_nonneg +lemma pow_eq_one_iff_of_nonneg (ha : 0 ≤ a) (hn : n ≠ 0) : a ^ n = 1 ↔ a = 1 := by + simpa only [one_pow] using pow_left_inj ha zero_le_one hn theorem sq_le_one_iff {a : R} (ha : 0 ≤ a) : a ^ 2 ≤ 1 ↔ a ≤ 1 := pow_le_one_iff_of_nonneg ha (Nat.succ_ne_zero _) @@ -253,19 +253,13 @@ theorem one_lt_sq_iff {a : R} (ha : 0 ≤ a) : 1 < a ^ 2 ↔ 1 < a := one_lt_pow_iff_of_nonneg ha (Nat.succ_ne_zero _) #align one_lt_sq_iff one_lt_sq_iff -@[simp] -theorem pow_left_inj {x y : R} {n : ℕ} (Hxpos : 0 ≤ x) (Hypos : 0 ≤ y) (Hnpos : 0 < n) : - x ^ n = y ^ n ↔ x = y := - (@strictMonoOn_pow R _ _ Hnpos).eq_iff_eq Hxpos Hypos -#align pow_left_inj pow_left_inj - -theorem lt_of_pow_lt_pow {a b : R} (n : ℕ) (hb : 0 ≤ b) (h : a ^ n < b ^ n) : a < b := - lt_of_not_ge fun hn => not_lt_of_ge (pow_le_pow_of_le_left hb hn _) h -#align lt_of_pow_lt_pow lt_of_pow_lt_pow +theorem lt_of_pow_lt_pow_left (n : ℕ) (hb : 0 ≤ b) (h : a ^ n < b ^ n) : a < b := + lt_of_not_ge fun hn => not_lt_of_ge (pow_le_pow_left hb hn _) h +#align lt_of_pow_lt_pow lt_of_pow_lt_pow_left -theorem le_of_pow_le_pow {a b : R} (n : ℕ) (hb : 0 ≤ b) (hn : 0 < n) (h : a ^ n ≤ b ^ n) : a ≤ b := - le_of_not_lt fun h1 => not_le_of_lt (pow_lt_pow_of_lt_left h1 hb hn) h -#align le_of_pow_le_pow le_of_pow_le_pow +theorem le_of_pow_le_pow_left (hn : n ≠ 0) (hb : 0 ≤ b) (h : a ^ n ≤ b ^ n) : a ≤ b := + le_of_not_lt fun h1 => not_le_of_lt (pow_lt_pow_left h1 hb hn) h +#align le_of_pow_le_pow le_of_pow_le_pow_left @[simp] theorem sq_eq_sq {a b : R} (ha : 0 ≤ a) (hb : 0 ≤ b) : a ^ 2 = b ^ 2 ↔ a = b := @@ -274,7 +268,7 @@ theorem sq_eq_sq {a b : R} (ha : 0 ≤ a) (hb : 0 ≤ b) : a ^ 2 = b ^ 2 ↔ a = theorem lt_of_mul_self_lt_mul_self (hb : 0 ≤ b) : a * a < b * b → a < b := by simp_rw [← sq] - exact lt_of_pow_lt_pow _ hb + exact lt_of_pow_lt_pow_left _ hb #align lt_of_mul_self_lt_mul_self lt_of_mul_self_lt_mul_self end LinearOrderedSemiring @@ -290,7 +284,7 @@ theorem pow_abs (a : R) (n : ℕ) : |a| ^ n = |a ^ n| := theorem abs_neg_one_pow (n : ℕ) : |(-1 : R) ^ n| = 1 := by rw [← pow_abs, abs_neg, abs_one, one_pow] #align abs_neg_one_pow abs_neg_one_pow -theorem abs_pow_eq_one (a : R) {n : ℕ} (h : 0 < n) : |a ^ n| = 1 ↔ |a| = 1 := by +theorem abs_pow_eq_one (a : R) {n : ℕ} (h : n ≠ 0) : |a ^ n| = 1 ↔ |a| = 1 := by convert pow_left_inj (abs_nonneg a) zero_le_one h exacts [(pow_abs _ _).symm, (one_pow _).symm] #align abs_pow_eq_one abs_pow_eq_one @@ -346,7 +340,7 @@ theorem abs_sq (x : R) : |x ^ 2| = x ^ 2 := by simpa only [sq] using abs_mul_sel theorem sq_lt_sq : x ^ 2 < y ^ 2 ↔ |x| < |y| := by simpa only [sq_abs] using - (@strictMonoOn_pow R _ _ two_pos).lt_iff_lt (abs_nonneg x) (abs_nonneg y) + (pow_left_strictMonoOn two_ne_zero).lt_iff_lt (abs_nonneg x) (abs_nonneg y) #align sq_lt_sq sq_lt_sq theorem sq_lt_sq' (h1 : -y < x) (h2 : x < y) : x ^ 2 < y ^ 2 := @@ -355,7 +349,7 @@ theorem sq_lt_sq' (h1 : -y < x) (h2 : x < y) : x ^ 2 < y ^ 2 := theorem sq_le_sq : x ^ 2 ≤ y ^ 2 ↔ |x| ≤ |y| := by simpa only [sq_abs] using - (@strictMonoOn_pow R _ _ two_pos).le_iff_le (abs_nonneg x) (abs_nonneg y) + (pow_left_strictMonoOn two_ne_zero).le_iff_le (abs_nonneg x) (abs_nonneg y) #align sq_le_sq sq_le_sq theorem sq_le_sq' (h1 : -y ≤ x) (h2 : x ≤ y) : x ^ 2 ≤ y ^ 2 := @@ -403,7 +397,7 @@ theorem one_lt_sq_iff_one_lt_abs (x : R) : 1 < x ^ 2 ↔ 1 < |x| := by #align one_lt_sq_iff_one_lt_abs one_lt_sq_iff_one_lt_abs theorem 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 + (pow_mul x 2 2).symm ▸ pow_le_pow_left (sq_nonneg x) h 2 #align pow_four_le_pow_two_of_pow_two_le pow_four_le_pow_two_of_pow_two_le end LinearOrderedRing @@ -441,10 +435,10 @@ theorem pow_lt_pow_succ (ha : 1 < a) : a ^ n < a ^ n.succ := by exact mul_lt_right₀ _ ha (pow_ne_zero _ (zero_lt_one.trans ha).ne') #align pow_lt_pow_succ pow_lt_pow_succ -theorem pow_lt_pow₀ (ha : 1 < a) (hmn : m < n) : a ^ m < a ^ n := by +theorem pow_lt_pow_right₀ (ha : 1 < a) (hmn : m < n) : a ^ m < a ^ n := by induction' hmn with n _ ih exacts [pow_lt_pow_succ ha, lt_trans ih (pow_lt_pow_succ ha)] -#align pow_lt_pow₀ pow_lt_pow₀ +#align pow_lt_pow₀ pow_lt_pow_right₀ end LinearOrderedCommGroupWithZero diff --git a/Mathlib/Algebra/Homology/LocalCohomology.lean b/Mathlib/Algebra/Homology/LocalCohomology.lean index 48486eaa8f1de..196d87baa329b 100644 --- a/Mathlib/Algebra/Homology/LocalCohomology.lean +++ b/Mathlib/Algebra/Homology/LocalCohomology.lean @@ -145,7 +145,7 @@ variable {R : Type u} [CommRing R] /-- The functor sending a natural number `i` to the `i`-th power of the ideal `J` -/ def idealPowersDiagram (J : Ideal R) : ℕᵒᵖ ⥤ Ideal R where obj t := J ^ unop t - map w := ⟨⟨Ideal.pow_le_pow w.unop.down.down⟩⟩ + map w := ⟨⟨Ideal.pow_le_pow_right w.unop.down.down⟩⟩ #align local_cohomology.ideal_powers_diagram localCohomology.idealPowersDiagram /-- The full subcategory of all ideals with radical containing `J` -/ @@ -234,7 +234,7 @@ theorem Ideal.exists_pow_le_of_le_radical_of_fG (hIJ : I ≤ J.radical) (hJ : J. obtain ⟨k, hk⟩ := J.exists_radical_pow_le_of_fg hJ use k calc - I ^ k ≤ J.radical ^ k := Ideal.pow_mono hIJ _ + I ^ k ≤ J.radical ^ k := Ideal.pow_right_mono hIJ _ _ ≤ J := hk #align local_cohomology.ideal.exists_pow_le_of_le_radical_of_fg localCohomology.Ideal.exists_pow_le_of_le_radical_of_fG diff --git a/Mathlib/Algebra/IsPrimePow.lean b/Mathlib/Algebra/IsPrimePow.lean index e3f8d507fdcf8..4b342e70dd7aa 100644 --- a/Mathlib/Algebra/IsPrimePow.lean +++ b/Mathlib/Algebra/IsPrimePow.lean @@ -88,7 +88,7 @@ theorem isPrimePow_nat_iff_bounded (n : ℕ) : rintro ⟨p, k, hp, hk, rfl⟩ refine' ⟨p, _, k, (Nat.lt_pow_self hp.one_lt _).le, hp, hk, rfl⟩ conv => { lhs; rw [← (pow_one p)] } - exact (Nat.pow_le_iff_le_right hp.two_le).mpr hk + exact pow_le_pow_right hp.one_lt.le hk #align is_prime_pow_nat_iff_bounded isPrimePow_nat_iff_bounded instance {n : ℕ} : Decidable (IsPrimePow n) := diff --git a/Mathlib/Algebra/Order/Archimedean.lean b/Mathlib/Algebra/Order/Archimedean.lean index 52931a45ca0b0..002d784a47374 100644 --- a/Mathlib/Algebra/Order/Archimedean.lean +++ b/Mathlib/Algebra/Order/Archimedean.lean @@ -51,7 +51,7 @@ instance OrderDual.archimedean [OrderedAddCommGroup α] [Archimedean α] : Archi theorem exists_lt_nsmul [OrderedAddCommMonoid M] [Archimedean M] [CovariantClass M M (· + ·) (· < ·)] {a : M} (ha : 0 < a) (b : M) : ∃ n : ℕ, b < n • a := - let ⟨k, hk⟩ := Archimedean.arch b ha; ⟨k + 1, hk.trans_lt <| nsmul_lt_nsmul ha k.lt_succ_self⟩ + let ⟨k, hk⟩ := Archimedean.arch b ha; ⟨k + 1, hk.trans_lt $ nsmul_lt_nsmul_left ha k.lt_succ_self⟩ section LinearOrderedAddCommGroup diff --git a/Mathlib/Algebra/Order/Field/Basic.lean b/Mathlib/Algebra/Order/Field/Basic.lean index 22490b49341c4..078231becfd77 100644 --- a/Mathlib/Algebra/Order/Field/Basic.lean +++ b/Mathlib/Algebra/Order/Field/Basic.lean @@ -613,13 +613,14 @@ theorem one_div_strictAntiOn : StrictAntiOn (fun x : α => 1 / x) (Set.Ioi 0) := theorem one_div_pow_le_one_div_pow_of_le (a1 : 1 ≤ a) {m n : ℕ} (mn : m ≤ n) : 1 / a ^ n ≤ 1 / a ^ m := by - refine' (one_div_le_one_div _ _).mpr (pow_le_pow a1 mn) <;> + refine' (one_div_le_one_div _ _).mpr (pow_le_pow_right a1 mn) <;> exact pow_pos (zero_lt_one.trans_le a1) _ #align one_div_pow_le_one_div_pow_of_le one_div_pow_le_one_div_pow_of_le theorem one_div_pow_lt_one_div_pow_of_lt (a1 : 1 < a) {m n : ℕ} (mn : m < n) : 1 / a ^ n < 1 / a ^ m := by - refine' (one_div_lt_one_div _ _).mpr (pow_lt_pow a1 mn) <;> exact pow_pos (zero_lt_one.trans a1) _ + refine (one_div_lt_one_div ?_ ?_).2 (pow_lt_pow_right a1 mn) <;> + exact pow_pos (zero_lt_one.trans a1) _ #align one_div_pow_lt_one_div_pow_of_lt one_div_pow_lt_one_div_pow_of_lt theorem one_div_pow_anti (a1 : 1 ≤ a) : Antitone fun n : ℕ => 1 / a ^ n := fun _ _ => diff --git a/Mathlib/Algebra/Order/Interval.lean b/Mathlib/Algebra/Order/Interval.lean index c10dda5864a46..f314bb0db2ab0 100644 --- a/Mathlib/Algebra/Order/Interval.lean +++ b/Mathlib/Algebra/Order/Interval.lean @@ -230,7 +230,7 @@ end Mul -- TODO: if `to_additive` gets improved sufficiently, derive this from `hasPow` instance NonemptyInterval.hasNSMul [AddMonoid α] [Preorder α] [CovariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (swap (· + ·)) (· ≤ ·)] : SMul ℕ (NonemptyInterval α) := - ⟨fun n s => ⟨(n • s.fst, n • s.snd), nsmul_le_nsmul_of_le_right s.fst_le_snd _⟩⟩ + ⟨fun n s => ⟨(n • s.fst, n • s.snd), nsmul_le_nsmul_right s.fst_le_snd _⟩⟩ #align nonempty_interval.has_nsmul NonemptyInterval.hasNSMul section Pow @@ -240,7 +240,7 @@ variable [Monoid α] [Preorder α] [CovariantClass α α (· * ·) (· ≤ ·)] @[to_additive existing] instance NonemptyInterval.hasPow : Pow (NonemptyInterval α) ℕ := - ⟨fun s n => ⟨s.toProd ^ n, pow_le_pow_of_le_left' s.fst_le_snd _⟩⟩ + ⟨fun s n => ⟨s.toProd ^ n, pow_le_pow_left' s.fst_le_snd _⟩⟩ #align nonempty_interval.has_pow NonemptyInterval.hasPow namespace NonemptyInterval diff --git a/Mathlib/Algebra/Order/Monovary.lean b/Mathlib/Algebra/Order/Monovary.lean index 30fe1693595b8..dec508e80301d 100644 --- a/Mathlib/Algebra/Order/Monovary.lean +++ b/Mathlib/Algebra/Order/Monovary.lean @@ -86,10 +86,10 @@ lemma antivaryOn_inv_right : AntivaryOn f g⁻¹ s ↔ MonovaryOn f g s := by AntivaryOn (f₁ / f₂) g s := fun _i hi _j hj hij ↦ div_le_div'' (h₁ hi hj hij) (h₂ hi hj hij) @[to_additive] lemma MonovaryOn.pow_left (hfg : MonovaryOn f g s) (n : ℕ) : - MonovaryOn (f ^ n) g s := fun _i hi _j hj hij ↦ pow_le_pow_of_le_left' (hfg hi hj hij) _ + MonovaryOn (f ^ n) g s := fun _i hi _j hj hij ↦ pow_le_pow_left' (hfg hi hj hij) _ @[to_additive] lemma AntivaryOn.pow_left (hfg : AntivaryOn f g s) (n : ℕ) : - AntivaryOn (f ^ n) g s := fun _i hi _j hj hij ↦ pow_le_pow_of_le_left' (hfg hi hj hij) _ + AntivaryOn (f ^ n) g s := fun _i hi _j hj hij ↦ pow_le_pow_left' (hfg hi hj hij) _ @[to_additive] lemma Monovary.mul_left (h₁ : Monovary f₁ g) (h₂ : Monovary f₂ g) : Monovary (f₁ * f₂) g := @@ -108,10 +108,10 @@ lemma Antivary.div_left (h₁ : Antivary f₁ g) (h₂ : Monovary f₂ g) : Anti fun _i _j hij ↦ div_le_div'' (h₁ hij) (h₂ hij) @[to_additive] lemma Monovary.pow_left (hfg : Monovary f g) (n : ℕ) : Monovary (f ^ n) g := - fun _i _j hij ↦ pow_le_pow_of_le_left' (hfg hij) _ + fun _i _j hij ↦ pow_le_pow_left' (hfg hij) _ @[to_additive] lemma Antivary.pow_left (hfg : Antivary f g) (n : ℕ) : Antivary (f ^ n) g := - fun _i _j hij ↦ pow_le_pow_of_le_left' (hfg hij) _ + fun _i _j hij ↦ pow_le_pow_left' (hfg hij) _ end OrderedCommGroup @@ -136,10 +136,10 @@ variable [OrderedCommGroup α] [LinearOrderedCommGroup β] {s : Set ι} {f f₁ fun _i hi _j hj hij ↦ (lt_or_lt_of_div_lt_div hij).elim (h₁ hi hj) $ h₂ hj hi @[to_additive] lemma MonovaryOn.pow_right (hfg : MonovaryOn f g s) (n : ℕ) : - MonovaryOn f (g ^ n) s := fun _i hi _j hj hij ↦ hfg hi hj $ lt_of_pow_lt_pow' _ hij + MonovaryOn f (g ^ n) s := fun _i hi _j hj hij ↦ hfg hi hj $ lt_of_pow_lt_pow_left' _ hij @[to_additive] lemma AntivaryOn.pow_right (hfg : AntivaryOn f g s) (n : ℕ) : - AntivaryOn f (g ^ n) s := fun _i hi _j hj hij ↦ hfg hi hj $ lt_of_pow_lt_pow' _ hij + AntivaryOn f (g ^ n) s := fun _i hi _j hj hij ↦ hfg hi hj $ lt_of_pow_lt_pow_left' _ hij @[to_additive] lemma Monovary.mul_right (h₁ : Monovary f g₁) (h₂ : Monovary f g₂) : Monovary f (g₁ * g₂) := @@ -158,10 +158,10 @@ variable [OrderedCommGroup α] [LinearOrderedCommGroup β] {s : Set ι} {f f₁ fun _i _j hij ↦ (lt_or_lt_of_div_lt_div hij).elim (fun h ↦ h₁ h) $ fun h ↦ h₂ h @[to_additive] lemma Monovary.pow_right (hfg : Monovary f g) (n : ℕ) : Monovary f (g ^ n) := - fun _i _j hij ↦ hfg $ lt_of_pow_lt_pow' _ hij + fun _i _j hij ↦ hfg $ lt_of_pow_lt_pow_left' _ hij @[to_additive] lemma Antivary.pow_right (hfg : Antivary f g) (n : ℕ) : Antivary f (g ^ n) := - fun _i _j hij ↦ hfg $ lt_of_pow_lt_pow' _ hij + fun _i _j hij ↦ hfg $ lt_of_pow_lt_pow_left' _ hij end LinearOrderedCommGroup @@ -178,11 +178,11 @@ lemma AntivaryOn.mul_left₀ (hf₁ : ∀ i ∈ s, 0 ≤ f₁ i) (hf₂ : ∀ i lemma MonovaryOn.pow_left₀ (hf : ∀ i ∈ s, 0 ≤ f i) (hfg : MonovaryOn f g s) (n : ℕ) : MonovaryOn (f ^ n) g s := - fun _i hi _j hj hij ↦ pow_le_pow_of_le_left (hf _ hi) (hfg hi hj hij) _ + fun _i hi _j hj hij ↦ pow_le_pow_left (hf _ hi) (hfg hi hj hij) _ lemma AntivaryOn.pow_left₀ (hf : ∀ i ∈ s, 0 ≤ f i) (hfg : AntivaryOn f g s) (n : ℕ) : AntivaryOn (f ^ n) g s := - fun _i hi _j hj hij ↦ pow_le_pow_of_le_left (hf _ hj) (hfg hi hj hij) _ + fun _i hi _j hj hij ↦ pow_le_pow_left (hf _ hj) (hfg hi hj hij) _ lemma Monovary.mul_left₀ (hf₁ : 0 ≤ f₁) (hf₂ : 0 ≤ f₂) (h₁ : Monovary f₁ g) (h₂ : Monovary f₂ g) : Monovary (f₁ * f₂) g := fun _i _j hij ↦ mul_le_mul (h₁ hij) (h₂ hij) (hf₂ _) (hf₁ _) @@ -191,10 +191,10 @@ lemma Antivary.mul_left₀ (hf₁ : 0 ≤ f₁) (hf₂ : 0 ≤ f₂) (h₁ : Ant Antivary (f₁ * f₂) g := fun _i _j hij ↦ mul_le_mul (h₁ hij) (h₂ hij) (hf₂ _) (hf₁ _) lemma Monovary.pow_left₀ (hf : 0 ≤ f) (hfg : Monovary f g) (n : ℕ) : Monovary (f ^ n) g := - fun _i _j hij ↦ pow_le_pow_of_le_left (hf _) (hfg hij) _ + fun _i _j hij ↦ pow_le_pow_left (hf _) (hfg hij) _ lemma Antivary.pow_left₀ (hf : 0 ≤ f) (hfg : Antivary f g) (n : ℕ) : Antivary (f ^ n) g := - fun _i _j hij ↦ pow_le_pow_of_le_left (hf _) (hfg hij) _ + fun _i _j hij ↦ pow_le_pow_left (hf _) (hfg hij) _ end OrderedSemiring diff --git a/Mathlib/Algebra/Tropical/Basic.lean b/Mathlib/Algebra/Tropical/Basic.lean index de073e688ab86..c595d65b5d981 100644 --- a/Mathlib/Algebra/Tropical/Basic.lean +++ b/Mathlib/Algebra/Tropical/Basic.lean @@ -544,8 +544,8 @@ theorem add_pow [LinearOrder R] [AddMonoid R] [CovariantClass R R (· + ·) (· [CovariantClass R R (Function.swap (· + ·)) (· ≤ ·)] (x y : Tropical R) (n : ℕ) : (x + y) ^ n = x ^ n + y ^ n := by cases' le_total x y with h h - · rw [add_eq_left h, add_eq_left (pow_le_pow_of_le_left' h _)] - · rw [add_eq_right h, add_eq_right (pow_le_pow_of_le_left' h _)] + · rw [add_eq_left h, add_eq_left (pow_le_pow_left' h _)] + · rw [add_eq_right h, add_eq_right (pow_le_pow_left' h _)] #align tropical.add_pow Tropical.add_pow end Distrib diff --git a/Mathlib/Analysis/Analytic/Composition.lean b/Mathlib/Analysis/Analytic/Composition.lean index 6a070f62ee43a..8a8945c8e29a6 100644 --- a/Mathlib/Analysis/Analytic/Composition.lean +++ b/Mathlib/Analysis/Analytic/Composition.lean @@ -499,7 +499,7 @@ theorem comp_summable_nnreal (q : FormalMultilinearSeries 𝕜 F G) (p : FormalM simp only [Finset.prod_mul_distrib, Finset.prod_pow_eq_pow_sum, c.sum_blocksFun] _ ≤ ∏ _i : Fin c.length, Cp := (Finset.prod_le_prod' fun i _ => hCp _) _ = Cp ^ c.length := by simp - _ ≤ Cp ^ n := pow_le_pow hCp1 c.length_le + _ ≤ Cp ^ n := pow_le_pow_right hCp1 c.length_le calc ‖q.compAlongComposition p c‖₊ * r ^ n ≤ (‖q c.length‖₊ * ∏ i, ‖p (c.blocksFun i)‖₊) * r ^ n := @@ -842,7 +842,7 @@ theorem HasFPowerSeriesAt.comp {g : F → G} {f : E → F} {q : FormalMultilinea _ ≤ ‖compAlongComposition q p c‖ * (r : ℝ) ^ n := by apply mul_le_mul_of_nonneg_left _ (norm_nonneg _) rw [Finset.prod_const, Finset.card_fin] - apply pow_le_pow_of_le_left (norm_nonneg _) + apply pow_le_pow_left (norm_nonneg _) rw [EMetric.mem_ball, edist_eq_coe_nnnorm] at hy have := le_trans (le_of_lt hy) (min_le_right _ _) rwa [ENNReal.coe_le_coe, ← NNReal.coe_le_coe, coe_nnnorm] at this diff --git a/Mathlib/Analysis/Asymptotics/Asymptotics.lean b/Mathlib/Analysis/Asymptotics/Asymptotics.lean index 4a6ecf09d8d13..4f8636d9e4510 100644 --- a/Mathlib/Analysis/Asymptotics/Asymptotics.lean +++ b/Mathlib/Analysis/Asymptotics/Asymptotics.lean @@ -1664,14 +1664,13 @@ theorem IsBigOWith.pow [NormOneClass R] {f : α → R} {g : α → 𝕜} (h : Is theorem IsBigOWith.of_pow {n : ℕ} {f : α → 𝕜} {g : α → R} (h : IsBigOWith c l (f ^ n) (g ^ n)) (hn : n ≠ 0) (hc : c ≤ c' ^ n) (hc' : 0 ≤ c') : IsBigOWith c' l f g := - IsBigOWith.of_bound <| - (h.weaken hc).bound.mono fun x hx => - le_of_pow_le_pow n (mul_nonneg hc' <| norm_nonneg _) hn.bot_lt <| - calc - ‖f x‖ ^ n = ‖f x ^ n‖ := (norm_pow _ _).symm - _ ≤ c' ^ n * ‖g x ^ n‖ := hx - _ ≤ c' ^ n * ‖g x‖ ^ n := by gcongr; exact norm_pow_le' _ hn.bot_lt - _ = (c' * ‖g x‖) ^ n := (mul_pow _ _ _).symm + IsBigOWith.of_bound <| (h.weaken hc).bound.mono fun x hx ↦ + le_of_pow_le_pow_left hn (by positivity) <| + calc + ‖f x‖ ^ n = ‖f x ^ n‖ := (norm_pow _ _).symm + _ ≤ c' ^ n * ‖g x ^ n‖ := hx + _ ≤ c' ^ n * ‖g x‖ ^ n := by gcongr; exact norm_pow_le' _ hn.bot_lt + _ = (c' * ‖g x‖) ^ n := (mul_pow _ _ _).symm #align asymptotics.is_O_with.of_pow Asymptotics.IsBigOWith.of_pow theorem IsBigO.pow {f : α → R} {g : α → 𝕜} (h : f =O[l] g) (n : ℕ) : diff --git a/Mathlib/Analysis/BoxIntegral/Basic.lean b/Mathlib/Analysis/BoxIntegral/Basic.lean index f3c8fe8c90b1a..5f127649461bd 100644 --- a/Mathlib/Analysis/BoxIntegral/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Basic.lean @@ -766,7 +766,7 @@ theorem HasIntegral.of_bRiemann_eq_false_of_forall_isLittleO (hl : l.bRiemann = refine' (sum_le_sum _).trans (hεs _ _) · rintro b - rw [← Nat.cast_two, ← Nat.cast_pow, ← nsmul_eq_mul] - refine' nsmul_le_nsmul (hεs0 _).le _ + refine' nsmul_le_nsmul_left (hεs0 _).le _ refine' (Finset.card_le_of_subset _).trans ((hπδ.isHenstock hlH).card_filter_tag_eq_le b) exact filter_subset_filter _ (filter_subset _ _) · rw [Finset.coe_image, Set.image_subset_iff] diff --git a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean index 21b0746eb5faf..1e45579362f25 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean @@ -328,7 +328,7 @@ theorem D_subset_differentiable_set {K : Set (E →L[𝕜] F)} (hK : IsComplete -- the scale is large enough (as `y` is small enough) have k_gt : n e < k := by have : ((1 : ℝ) / 2) ^ (k + 1) < (1 / 2) ^ (n e + 1) := lt_trans hk y_lt - rw [pow_lt_pow_iff_of_lt_one (by norm_num : (0 : ℝ) < 1 / 2) (by norm_num)] at this + rw [pow_lt_pow_iff_right_of_lt_one (by norm_num : (0 : ℝ) < 1 / 2) (by norm_num)] at this linarith set m := k - 1 have m_ge : n e ≤ m := Nat.le_sub_one_of_lt k_gt @@ -691,7 +691,7 @@ theorem D_subset_differentiable_set {K : Set F} (hK : IsComplete K) : -- the scale is large enough (as `y - x` is small enough) have k_gt : n e < k := by have : ((1 : ℝ) / 2) ^ (k + 1) < (1 / 2) ^ (n e + 1) := lt_of_lt_of_le hk y_le - rw [pow_lt_pow_iff_of_lt_one (by norm_num : (0 : ℝ) < 1 / 2) (by norm_num)] at this + rw [pow_lt_pow_iff_right_of_lt_one (by norm_num : (0 : ℝ) < 1 / 2) (by norm_num)] at this linarith set m := k - 1 have m_ge : n e ≤ m := Nat.le_sub_one_of_lt k_gt diff --git a/Mathlib/Analysis/Complex/Basic.lean b/Mathlib/Analysis/Complex/Basic.lean index 56292525977b9..9e1c2f1a459ea 100644 --- a/Mathlib/Analysis/Complex/Basic.lean +++ b/Mathlib/Analysis/Complex/Basic.lean @@ -194,9 +194,8 @@ theorem nnnorm_int (n : ℤ) : ‖(n : ℂ)‖₊ = ‖n‖₊ := Subtype.ext norm_int #align complex.nnnorm_int Complex.nnnorm_int -theorem nnnorm_eq_one_of_pow_eq_one {ζ : ℂ} {n : ℕ} (h : ζ ^ n = 1) (hn : n ≠ 0) : ‖ζ‖₊ = 1 := by - refine' (@pow_left_inj NNReal _ _ _ _ zero_le' zero_le' hn.bot_lt).mp _ - rw [← nnnorm_pow, h, nnnorm_one, one_pow] +theorem nnnorm_eq_one_of_pow_eq_one {ζ : ℂ} {n : ℕ} (h : ζ ^ n = 1) (hn : n ≠ 0) : ‖ζ‖₊ = 1 := + (pow_left_inj zero_le' zero_le' hn).1 $ by rw [← nnnorm_pow, h, nnnorm_one, one_pow] #align complex.nnnorm_eq_one_of_pow_eq_one Complex.nnnorm_eq_one_of_pow_eq_one theorem norm_eq_one_of_pow_eq_one {ζ : ℂ} {n : ℕ} (h : ζ ^ n = 1) (hn : n ≠ 0) : ‖ζ‖ = 1 := diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean index e5010c8add85b..7120d654c35e3 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean @@ -190,7 +190,7 @@ theorem cmp_dist_eq_cmp_dist_coe_center (z w : ℍ) (r : ℝ) : have hr₀' : 0 ≤ w.im * Real.sinh r := mul_nonneg w.im_pos.le (sinh_nonneg_iff.2 hr₀) have hzw₀ : 0 < 2 * z.im * w.im := mul_pos (mul_pos two_pos z.im_pos) w.im_pos simp only [← cosh_strictMonoOn.cmp_map_eq dist_nonneg hr₀, ← - (@strictMonoOn_pow ℝ _ _ two_pos).cmp_map_eq dist_nonneg hr₀', dist_coe_center_sq] + (pow_left_strictMonoOn two_ne_zero).cmp_map_eq dist_nonneg hr₀', dist_coe_center_sq] rw [← cmp_mul_pos_left hzw₀, ← cmp_sub_zero, ← mul_sub, ← cmp_add_right, zero_add] #align upper_half_plane.cmp_dist_eq_cmp_dist_coe_center UpperHalfPlane.cmp_dist_eq_cmp_dist_coe_center diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean index 95872b239c3f4..101bc4ca6a098 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean @@ -38,9 +38,8 @@ open scoped BigOperators NNReal theorem strictConvexOn_pow {n : ℕ} (hn : 2 ≤ n) : StrictConvexOn ℝ (Ici 0) fun x : ℝ => x ^ n := by apply StrictMonoOn.strictConvexOn_of_deriv (convex_Ici _) (continuousOn_pow _) rw [deriv_pow', interior_Ici] - exact fun x (hx : 0 < x) y hy hxy => - mul_lt_mul_of_pos_left (pow_lt_pow_of_lt_left hxy hx.le <| Nat.sub_pos_of_lt hn) - (Nat.cast_pos.2 <| zero_lt_two.trans_le hn) + exact fun x (hx : 0 < x) y _ hxy => mul_lt_mul_of_pos_left + (pow_lt_pow_left hxy hx.le <| Nat.sub_ne_zero_of_lt hn) (by positivity) #align strict_convex_on_pow strictConvexOn_pow /-- `x^n`, `n : ℕ` is strictly convex on the whole real line whenever `n ≠ 0` is even. -/ diff --git a/Mathlib/Analysis/Distribution/SchwartzSpace.lean b/Mathlib/Analysis/Distribution/SchwartzSpace.lean index 45dab0b1f2d27..87a3d62095514 100644 --- a/Mathlib/Analysis/Distribution/SchwartzSpace.lean +++ b/Mathlib/Analysis/Distribution/SchwartzSpace.lean @@ -629,7 +629,7 @@ theorem _root_.Function.HasTemperateGrowth.norm_iteratedFDeriv_le_uniform_aux {f · simp only [Finset.le_sup'_iff, le_max_iff] right exact ⟨N, hN, rfl.le⟩ - refine' pow_le_pow (by simp only [le_add_iff_nonneg_right, norm_nonneg]) _ + refine' pow_le_pow_right (by simp only [le_add_iff_nonneg_right, norm_nonneg]) _ exact Finset.le_sup hN #align function.has_temperate_growth.norm_iterated_fderiv_le_uniform_aux Function.HasTemperateGrowth.norm_iteratedFDeriv_le_uniform_aux @@ -777,7 +777,7 @@ def bilinLeftCLM (B : E →L[ℝ] F →L[ℝ] G) {g : D → F} (hg : g.HasTemper refine' mul_le_mul_of_nonneg_right _ (norm_nonneg _) rw [pow_add] refine' mul_le_mul_of_nonneg_left _ (by positivity) - refine' pow_le_pow_of_le_left (norm_nonneg _) _ _ + refine' pow_le_pow_left (norm_nonneg _) _ _ simp only [zero_le_one, le_add_iff_nonneg_left]) #align schwartz_map.bilin_left_clm SchwartzMap.bilinLeftCLM @@ -819,7 +819,7 @@ def compCLM {g : D → E} (hg : g.HasTemperateGrowth) let seminorm_f := ((Finset.Iic (k', n)).sup (schwartzSeminormFamily 𝕜 _ _)) f have hg_upper'' : (1 + ‖x‖) ^ (k + l * n) ≤ (1 + Cg) ^ (k + l * n) * (1 + ‖g x‖) ^ k' := by rw [pow_mul, ← mul_pow] - refine' pow_le_pow_of_le_left (by positivity) _ _ + refine' pow_le_pow_left (by positivity) _ _ rw [add_mul] refine' add_le_add _ (hg_upper' x) nth_rw 1 [← one_mul (1 : ℝ)] @@ -844,7 +844,7 @@ def compCLM {g : D → E} (hg : g.HasTemperateGrowth) simp only [le_add_iff_nonneg_right, norm_nonneg] have := norm_iteratedFDeriv_comp_le f.smooth' hg.1 le_top x hbound hgrowth' have hxk : ‖x‖ ^ k ≤ (1 + ‖x‖) ^ k := - pow_le_pow_of_le_left (norm_nonneg _) (by simp only [zero_le_one, le_add_iff_nonneg_left]) _ + pow_le_pow_left (norm_nonneg _) (by simp only [zero_le_one, le_add_iff_nonneg_left]) _ refine' le_trans (mul_le_mul hxk this (by positivity) (by positivity)) _ have rearrange : (1 + ‖x‖) ^ k * diff --git a/Mathlib/Analysis/InnerProductSpace/Basic.lean b/Mathlib/Analysis/InnerProductSpace/Basic.lean index 9d0e64cc20201..4b9c1bf5d02a9 100644 --- a/Mathlib/Analysis/InnerProductSpace/Basic.lean +++ b/Mathlib/Analysis/InnerProductSpace/Basic.lean @@ -1200,7 +1200,7 @@ instance (priority := 100) InnerProductSpace.toUniformConvexSpace : UniformConve refine' le_sqrt_of_sq_le _ rw [sq, eq_sub_iff_add_eq.2 (parallelogram_law_with_norm ℝ x y), ← sq ‖x - y‖, hx, hy] ring_nf - exact sub_le_sub_left (pow_le_pow_of_le_left hε.le hxy _) 4⟩ + exact sub_le_sub_left (pow_le_pow_left hε.le hxy _) 4⟩ #align inner_product_space.to_uniform_convex_space InnerProductSpace.toUniformConvexSpace section Complex diff --git a/Mathlib/Analysis/InnerProductSpace/Projection.lean b/Mathlib/Analysis/InnerProductSpace/Projection.lean index 25c01f65fd1e6..d5c66fa74ff05 100644 --- a/Mathlib/Analysis/InnerProductSpace/Projection.lean +++ b/Mathlib/Analysis/InnerProductSpace/Projection.lean @@ -492,7 +492,7 @@ def orthogonalProjection : E →L[𝕜] K := simp [eq_orthogonalProjectionFn_of_mem_of_inner_eq_zero hm ho] } 1 fun x => by simp only [one_mul, LinearMap.coe_mk] - refine' le_of_pow_le_pow 2 (norm_nonneg _) (by norm_num) _ + refine' le_of_pow_le_pow_left two_ne_zero (norm_nonneg _) _ change ‖orthogonalProjectionFn K x‖ ^ 2 ≤ ‖x‖ ^ 2 nlinarith [orthogonalProjectionFn_norm_sq K x] #align orthogonal_projection orthogonalProjection diff --git a/Mathlib/Analysis/Normed/Field/Basic.lean b/Mathlib/Analysis/Normed/Field/Basic.lean index 7dc7ac0acaa57..ee66ae3aeab78 100644 --- a/Mathlib/Analysis/Normed/Field/Basic.lean +++ b/Mathlib/Analysis/Normed/Field/Basic.lean @@ -789,7 +789,7 @@ instance (priority := 100) NormedDivisionRing.to_topologicalDivisionRing : Topol theorem norm_map_one_of_pow_eq_one [Monoid β] (φ : β →* α) {x : β} {k : ℕ+} (h : x ^ (k : ℕ) = 1) : ‖φ x‖ = 1 := by rw [← pow_left_inj, ← norm_pow, ← map_pow, h, map_one, norm_one, one_pow] - exacts [norm_nonneg _, zero_le_one, k.pos] + exacts [norm_nonneg _, zero_le_one, k.ne_zero] #align norm_map_one_of_pow_eq_one norm_map_one_of_pow_eq_one theorem norm_one_of_pow_eq_one {x : α} {k : ℕ+} (h : x ^ (k : ℕ) = 1) : ‖x‖ = 1 := diff --git a/Mathlib/Analysis/NormedSpace/FiniteDimension.lean b/Mathlib/Analysis/NormedSpace/FiniteDimension.lean index de87532d58585..a904d1090e685 100644 --- a/Mathlib/Analysis/NormedSpace/FiniteDimension.lean +++ b/Mathlib/Analysis/NormedSpace/FiniteDimension.lean @@ -283,7 +283,7 @@ theorem Basis.op_nnnorm_le {ι : Type*} [Fintype ι] (v : Basis ι 𝕜 E) {u : gcongr calc ∑ i, ‖v.equivFun 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 ι • (‖φ‖₊ * ‖e‖₊) := nsmul_le_nsmul_right (φ.le_op_nnnorm e) _ _ = Fintype.card ι • ‖φ‖₊ * M * ‖e‖₊ := by simp only [smul_mul_assoc, mul_right_comm] #align basis.op_nnnorm_le Basis.op_nnnorm_le diff --git a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean index 703113e545b05..193888790ef6c 100644 --- a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean +++ b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean @@ -663,7 +663,7 @@ theorem continuous_eval : Continuous _ ≤ (‖p‖ + 1) * Fintype.card ι * (‖p‖ + 1) ^ (Fintype.card ι - 1) * ‖q - p‖ + ‖q - p‖ * ∏ i, ‖p.2 i‖ := by apply_rules [add_le_add, mul_le_mul, le_refl, le_trans (norm_fst_le q) A, Nat.cast_nonneg, - mul_nonneg, pow_le_pow_of_le_left, pow_nonneg, norm_snd_le (q - p), norm_nonneg, + mul_nonneg, pow_le_pow_left, pow_nonneg, norm_snd_le (q - p), norm_nonneg, norm_fst_le (q - p), prod_nonneg] _ = ((‖p‖ + 1) * Fintype.card ι * (‖p‖ + 1) ^ (Fintype.card ι - 1) + ∏ i, ‖p.2 i‖) * dist q p := by diff --git a/Mathlib/Analysis/NormedSpace/Star/Multiplier.lean b/Mathlib/Analysis/NormedSpace/Star/Multiplier.lean index a43fb4eda6c5e..7a790033364cb 100644 --- a/Mathlib/Analysis/NormedSpace/Star/Multiplier.lean +++ b/Mathlib/Analysis/NormedSpace/Star/Multiplier.lean @@ -709,7 +709,7 @@ instance instCstarRing : CstarRing 𝓜(𝕜, A) where rintro - ⟨y, hy, rfl⟩ exact key (star x) y ((nnnorm_star x).trans_le hx') (mem_closedBall_zero_iff.1 hy) · simpa only [a.central, star_star, CstarRing.nnnorm_star_mul_self, NNReal.sq_sqrt, ← sq] - using pow_lt_pow_of_lt_left hxr zero_le' two_pos + using pow_lt_pow_left hxr zero_le' two_ne_zero end DenselyNormed diff --git a/Mathlib/Analysis/PSeries.lean b/Mathlib/Analysis/PSeries.lean index 6a4e0d1481561..3739a9197021f 100644 --- a/Mathlib/Analysis/PSeries.lean +++ b/Mathlib/Analysis/PSeries.lean @@ -86,7 +86,7 @@ theorem sum_condensed_le' (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n → f n ≤ f m theorem sum_condensed_le (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n → f n ≤ f m) (n : ℕ) : (∑ k in range (n + 1), 2 ^ k • f (2 ^ k)) ≤ f 1 + 2 • ∑ k in Ico 2 (2 ^ n + 1), f k := by - convert add_le_add_left (nsmul_le_nsmul_of_le_right (sum_condensed_le' hf n) 2) (f 1) + convert add_le_add_left (nsmul_le_nsmul_right (sum_condensed_le' hf n) 2) (f 1) simp [sum_range_succ', add_comm, pow_succ, mul_nsmul', sum_nsmul] #align finset.sum_condensed_le Finset.sum_condensed_le @@ -111,7 +111,7 @@ theorem tsum_condensed_le (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n → f n ≤ f m iSup_le fun n => le_trans _ (add_le_add_left - (nsmul_le_nsmul_of_le_right (ENNReal.sum_le_tsum <| Finset.Ico 2 (2 ^ n + 1)) _) _) + (nsmul_le_nsmul_right (ENNReal.sum_le_tsum <| Finset.Ico 2 (2 ^ n + 1)) _) _) simpa using Finset.sum_condensed_le hf n #align ennreal.tsum_condensed_le ENNReal.tsum_condensed_le @@ -332,7 +332,7 @@ theorem sum_Ioo_inv_sq_le (k n : ℕ) : (∑ i in Ioo k n, (i ^ 2 : α)⁻¹) have A : (1 : α) ≤ k + 1 := by simp only [le_add_iff_nonneg_left, Nat.cast_nonneg] simp_rw [← one_div] gcongr - simpa using pow_le_pow A one_le_two + simpa using pow_le_pow_right A one_le_two _ = 2 / (k + 1) := by ring #align sum_Ioo_inv_sq_le sum_Ioo_inv_sq_le diff --git a/Mathlib/Analysis/SpecialFunctions/Exp.lean b/Mathlib/Analysis/SpecialFunctions/Exp.lean index 7aacf5b2df0a8..4dcce95fbf30f 100644 --- a/Mathlib/Analysis/SpecialFunctions/Exp.lean +++ b/Mathlib/Analysis/SpecialFunctions/Exp.lean @@ -225,7 +225,7 @@ theorem tendsto_exp_div_pow_atTop (n : ℕ) : Tendsto (fun x => exp x / x ^ n) a have hx₀ : 0 < x := (Nat.cast_nonneg N).trans_lt hx rw [Set.mem_Ici, le_div_iff (pow_pos hx₀ _), ← le_div_iff' hC₀] calc - x ^ n ≤ ⌈x⌉₊ ^ n := mod_cast pow_le_pow_of_le_left hx₀.le (Nat.le_ceil _) _ + x ^ n ≤ ⌈x⌉₊ ^ n := mod_cast pow_le_pow_left hx₀.le (Nat.le_ceil _) _ _ ≤ exp ⌈x⌉₊ / (exp 1 * C) := mod_cast (hN _ (Nat.lt_ceil.2 hx).le).le _ ≤ exp (x + 1) / (exp 1 * C) := (div_le_div_of_le (mul_pos (exp_pos _) hC₀).le diff --git a/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean b/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean index b73d3edc39161..ac0728f081189 100644 --- a/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean +++ b/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean @@ -83,7 +83,7 @@ theorem finite_integral_rpow_sub_one_pow_aux {r : ℝ} (n : ℕ) (hnr : (n : ℝ ENNReal.ofReal ((x ^ (-r⁻¹) - 1) ^ n) ≤ ENNReal.ofReal (x ^ (-(r⁻¹ * n))) := fun x hx ↦ by apply ENNReal.ofReal_le_ofReal rw [← neg_mul, rpow_mul hx.1.le, rpow_nat_cast] - refine' pow_le_pow_of_le_left _ (by simp only [sub_le_self_iff, zero_le_one]) n + refine' pow_le_pow_left _ (by simp only [sub_le_self_iff, zero_le_one]) n rw [le_sub_iff_add_le', add_zero] refine' Real.one_le_rpow_of_pos_of_le_one_of_nonpos hx.1 hx.2 _ rw [Right.neg_nonpos_iff, inv_nonneg] diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean index 7dce3327aaad1..cc599f1328a88 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean @@ -451,7 +451,7 @@ theorem eventually_pow_one_div_le (x : ℝ≥0) {y : ℝ≥0} (hy : 1 < y) : rw [tsub_add_cancel_of_le hy.le] at hm refine' eventually_atTop.2 ⟨m + 1, fun n hn => _⟩ simpa only [NNReal.rpow_one_div_le_iff (Nat.cast_pos.2 <| m.succ_pos.trans_le hn), - NNReal.rpow_nat_cast] using hm.le.trans (pow_le_pow hy.le (m.le_succ.trans hn)) + NNReal.rpow_nat_cast] using hm.le.trans (pow_le_pow_right hy.le (m.le_succ.trans hn)) #align nnreal.eventually_pow_one_div_le NNReal.eventually_pow_one_div_le end NNReal diff --git a/Mathlib/Analysis/SpecificLimits/Basic.lean b/Mathlib/Analysis/SpecificLimits/Basic.lean index 97b565219fce2..20e45259933f5 100644 --- a/Mathlib/Analysis/SpecificLimits/Basic.lean +++ b/Mathlib/Analysis/SpecificLimits/Basic.lean @@ -96,7 +96,7 @@ theorem tendsto_coe_nat_div_add_atTop {𝕜 : Type*} [DivisionRing 𝕜] [Topolo theorem tendsto_add_one_pow_atTop_atTop_of_pos [LinearOrderedSemiring α] [Archimedean α] {r : α} (h : 0 < r) : Tendsto (fun n : ℕ ↦ (r + 1) ^ n) atTop atTop := - (tendsto_atTop_atTop_of_monotone' fun _ _ ↦ pow_le_pow (le_add_of_nonneg_left (le_of_lt h))) <| + tendsto_atTop_atTop_of_monotone' (fun _ _ ↦ pow_le_pow_right $ le_add_of_nonneg_left h.le) <| not_bddAbove_iff.2 fun _ ↦ Set.exists_range_iff.2 <| add_one_pow_unbounded_of_pos _ h #align tendsto_add_one_pow_at_top_at_top_of_pos tendsto_add_one_pow_atTop_atTop_of_pos @@ -131,7 +131,7 @@ theorem tendsto_pow_atTop_nhds_0_of_lt_1 {𝕜 : Type*} [LinearOrderedField 𝕜 simp only [hr.symm, one_pow] at h exact zero_ne_one <| tendsto_nhds_unique h tendsto_const_nhds · apply @not_tendsto_nhds_of_tendsto_atTop 𝕜 ℕ _ _ _ _ atTop _ (fun n ↦ |r| ^ n) _ 0 _ - refine (pow_strictMono_right $ lt_of_le_of_ne (le_of_not_lt hr_le) + refine (pow_right_strictMono $ lt_of_le_of_ne (le_of_not_lt hr_le) hr).monotone.tendsto_atTop_atTop (fun b ↦ ?_) obtain ⟨n, hn⟩ := (pow_unbounded_of_one_lt b (lt_of_le_of_ne (le_of_not_lt hr_le) hr)) exacts [⟨n, le_of_lt hn⟩, by simpa only [← abs_pow]] @@ -465,7 +465,7 @@ theorem summable_one_div_pow_of_le {m : ℝ} {f : ℕ → ℕ} (hm : 1 < m) (fi (summable_geometric_of_lt_1 (one_div_nonneg.mpr (zero_le_one.trans hm.le)) ((one_div_lt (zero_lt_one.trans hm) zero_lt_one).mpr (one_div_one.le.trans_lt hm))) rw [div_pow, one_pow] - refine' (one_div_le_one_div _ _).mpr (pow_le_pow hm.le (fi a)) <;> + refine' (one_div_le_one_div _ _).mpr (pow_le_pow_right hm.le (fi a)) <;> exact pow_pos (zero_lt_one.trans hm) _ #align summable_one_div_pow_of_le summable_one_div_pow_of_le diff --git a/Mathlib/Analysis/SpecificLimits/FloorPow.lean b/Mathlib/Analysis/SpecificLimits/FloorPow.lean index 9be939fc3a6d3..a9a3408c43b1e 100644 --- a/Mathlib/Analysis/SpecificLimits/FloorPow.lean +++ b/Mathlib/Analysis/SpecificLimits/FloorPow.lean @@ -250,7 +250,7 @@ theorem sum_div_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : ℝ} (hc have : c ^ 3 = c ^ 2 * c := by ring simp only [mul_sub, this, mul_one, inv_pow, sub_le_sub_iff_left] rw [mul_assoc, mul_comm c, ← mul_assoc, mul_inv_cancel (sq_pos_of_pos cpos).ne', one_mul] - simpa using pow_le_pow hc.le one_le_two + simpa using pow_le_pow_right hc.le one_le_two calc (∑ i in (range N).filter fun i => j < c ^ i, (1 : ℝ) / (c ^ i) ^ 2) ≤ ∑ i in Ico ⌊Real.log j / Real.log c⌋₊ N, (1 : ℝ) / (c ^ i) ^ 2 := by @@ -307,7 +307,7 @@ theorem mul_pow_le_nat_floor_pow {c : ℝ} (hc : 1 < c) (i : ℕ) : (1 - c⁻¹) (1 - c⁻¹) * c ^ i = c ^ i - c ^ i * c⁻¹ := by ring _ ≤ c ^ i - 1 := by simpa only [← div_eq_mul_inv, sub_le_sub_iff_left, one_le_div cpos, pow_one] using - pow_le_pow hc.le hident + pow_le_pow_right hc.le hident _ ≤ ⌊c ^ i⌋₊ := (Nat.sub_one_lt_floor _).le #align mul_pow_le_nat_floor_pow mul_pow_le_nat_floor_pow @@ -337,7 +337,7 @@ theorem sum_div_nat_floor_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : simp only [Nat.le_floor, one_le_pow_of_one_le, hc.le, Nat.one_le_cast, Nat.cast_one] · exact sq_pos_of_pos (pow_pos cpos _) rw [one_mul, ← mul_pow] - apply pow_le_pow_of_le_left (pow_nonneg cpos.le _) + apply pow_le_pow_left (pow_nonneg cpos.le _) rw [← div_eq_inv_mul, le_div_iff A, mul_comm] exact mul_pow_le_nat_floor_pow hc i _ ≤ (1 - c⁻¹)⁻¹ ^ 2 * (c ^ 3 * (c - 1)⁻¹) / j ^ 2 := by diff --git a/Mathlib/Analysis/SpecificLimits/Normed.lean b/Mathlib/Analysis/SpecificLimits/Normed.lean index 9a93c7c549190..4240f7b44c35e 100644 --- a/Mathlib/Analysis/SpecificLimits/Normed.lean +++ b/Mathlib/Analysis/SpecificLimits/Normed.lean @@ -319,7 +319,7 @@ theorem summable_geometric_iff_norm_lt_1 : (Summable fun n : ℕ ↦ ξ ^ n) ↔ (h.tendsto_cofinite_zero.eventually (ball_mem_nhds _ zero_lt_one)).exists simp only [norm_pow, dist_zero_right] at hk rw [← one_pow k] at hk - exact lt_of_pow_lt_pow _ zero_le_one hk + exact lt_of_pow_lt_pow_left _ zero_le_one hk #align summable_geometric_iff_norm_lt_1 summable_geometric_iff_norm_lt_1 end Geometric diff --git a/Mathlib/Combinatorics/Additive/Behrend.lean b/Mathlib/Combinatorics/Additive/Behrend.lean index 2e79d0e562e29..2aaf38f36d47b 100644 --- a/Mathlib/Combinatorics/Additive/Behrend.lean +++ b/Mathlib/Combinatorics/Additive/Behrend.lean @@ -196,7 +196,7 @@ theorem addSalemSpencer_image_sphere : theorem sum_sq_le_of_mem_box (hx : x ∈ box n d) : ∑ i : Fin n, x i ^ 2 ≤ n * (d - 1) ^ 2 := by rw [mem_box] at hx have : ∀ i, x i ^ 2 ≤ (d - 1) ^ 2 := fun i => - Nat.pow_le_pow_of_le_left (Nat.le_sub_one_of_lt (hx i)) _ + Nat.pow_le_pow_left (Nat.le_sub_one_of_lt (hx i)) _ exact (sum_le_card_nsmul univ _ _ fun i _ => this i).trans (by rw [card_fin, smul_eq_mul]) #align behrend.sum_sq_le_of_mem_box Behrend.sum_sq_le_of_mem_box @@ -371,22 +371,14 @@ noncomputable def nValue (N : ℕ) : ℕ := #align behrend.n_value Behrend.nValue /-- The (almost) optimal value of `d` in `Behrend.bound_aux`. -/ -noncomputable def dValue (N : ℕ) : ℕ := - ⌊(N : ℝ) ^ (1 / nValue N : ℝ) / 2⌋₊ +noncomputable def dValue (N : ℕ) : ℕ := ⌊(N : ℝ) ^ (nValue N : ℝ)⁻¹ / 2⌋₊ #align behrend.d_value Behrend.dValue theorem nValue_pos (hN : 2 ≤ N) : 0 < nValue N := ceil_pos.2 <| Real.sqrt_pos.2 <| log_pos <| one_lt_cast.2 <| hN #align behrend.n_value_pos Behrend.nValue_pos -theorem two_le_nValue (hN : 3 ≤ N) : 2 ≤ nValue N := by - refine' succ_le_of_lt (lt_ceil.2 <| lt_sqrt_of_sq_lt _) - rw [cast_one, one_pow, lt_log_iff_exp_lt] - refine' lt_of_lt_of_le _ (cast_le.2 hN) - · exact exp_one_lt_d9.trans_le (by norm_num) - rw [cast_pos] - exact (zero_lt_succ _).trans_le hN -#align behrend.two_le_n_value Behrend.two_le_nValue +#noalign behrend.two_le_n_value theorem three_le_nValue (hN : 64 ≤ N) : 3 ≤ nValue N := by rw [nValue, ← lt_iff_add_one_le, lt_ceil, cast_two] @@ -405,7 +397,7 @@ theorem three_le_nValue (hN : 64 ≤ N) : 3 ≤ nValue N := by theorem dValue_pos (hN₃ : 8 ≤ N) : 0 < dValue N := by have hN₀ : 0 < (N : ℝ) := cast_pos.2 (succ_pos'.trans_le hN₃) rw [dValue, floor_pos, ← log_le_log zero_lt_one, log_one, log_div _ two_ne_zero, log_rpow hN₀, - div_mul_eq_mul_div, one_mul, sub_nonneg, le_div_iff] + inv_mul_eq_div, sub_nonneg, le_div_iff] · have : (nValue N : ℝ) ≤ 2 * sqrt (log N) := by apply (ceil_lt_add_one <| sqrt_nonneg _).le.trans rw [two_mul, add_le_add_iff_left] @@ -427,13 +419,13 @@ theorem dValue_pos (hN₃ : 8 ≤ N) : 0 < dValue N := by theorem le_N (hN : 2 ≤ N) : (2 * dValue N - 1) ^ nValue N ≤ N := by have : (2 * dValue N - 1) ^ nValue N ≤ (2 * dValue N) ^ nValue N := - Nat.pow_le_pow_of_le_left (Nat.sub_le _ _) _ + Nat.pow_le_pow_left (Nat.sub_le _ _) _ apply this.trans suffices ((2 * dValue N) ^ nValue N : ℝ) ≤ N from mod_cast this - suffices i : (2 * dValue N : ℝ) ≤ (N : ℝ) ^ (1 / nValue N : ℝ) + suffices i : (2 * dValue N : ℝ) ≤ (N : ℝ) ^ (nValue N : ℝ)⁻¹ · rw [← rpow_nat_cast] apply (rpow_le_rpow (mul_nonneg zero_le_two (cast_nonneg _)) i (cast_nonneg _)).trans - rw [← rpow_mul (cast_nonneg _), one_div_mul_cancel, rpow_one] + rw [← rpow_mul (cast_nonneg _), inv_mul_cancel, rpow_one] rw [cast_ne_zero] apply (nValue_pos hN).ne' rw [← le_div_iff'] @@ -442,9 +434,9 @@ theorem le_N (hN : 2 ≤ N) : (2 * dValue N - 1) ^ nValue N ≤ N := by set_option linter.uppercaseLean3 false in #align behrend.le_N Behrend.le_N -theorem bound (hN : 4096 ≤ N) : (N : ℝ) ^ (1 / nValue N : ℝ) / exp 1 < dValue N := by +theorem bound (hN : 4096 ≤ N) : (N : ℝ) ^ (nValue N : ℝ)⁻¹ / exp 1 < dValue N := by apply div_lt_floor _ - rw [← log_le_log, log_rpow, mul_comm, ← div_eq_mul_one_div] + rw [← log_le_log, log_rpow, mul_comm, ← div_eq_mul_inv] · apply le_trans _ (div_le_div_of_le_left _ _ (ceil_lt_mul _).le) rw [mul_comm, ← div_div, div_sqrt, le_div_iff] · norm_num; exact le_sqrt_log hN @@ -484,14 +476,15 @@ theorem roth_lower_bound_explicit (hN : 4096 ≤ N) : have hn : 0 < (n : ℝ) := cast_pos.2 (nValue_pos <| hN.trans' <| by norm_num1) have hd : 0 < dValue N := dValue_pos (hN.trans' <| by norm_num1) have hN₀ : 0 < (N : ℝ) := cast_pos.2 (hN.trans' <| by norm_num1) - have hn₂ : 2 ≤ n := two_le_nValue (hN.trans' <| by norm_num1) + have hn₂ : 2 < n := three_le_nValue $ hN.trans' $ by norm_num1 have : (2 * dValue N - 1) ^ n ≤ N := le_N (hN.trans' <| by norm_num1) - refine' ((bound_aux hd.ne' hn₂).trans <| cast_le.2 <| rothNumberNat.mono this).trans_lt' _ - refine' (div_lt_div_of_lt hn <| pow_lt_pow_of_lt_left (bound hN) _ _).trans_le' _ - · exact div_nonneg (rpow_nonneg_of_nonneg (cast_nonneg _) _) (exp_pos _).le - · exact tsub_pos_of_lt (three_le_nValue <| hN.trans' <| by norm_num1) + calc + _ ≤ (N ^ (nValue N : ℝ)⁻¹ / rexp 1 : ℝ) ^ (n - 2) / n := ?_ + _ < _ := by gcongr; exacts [(tsub_pos_of_lt hn₂).ne', bound hN] + _ ≤ rothNumberNat ((2 * dValue N - 1) ^ n) := bound_aux hd.ne' hn₂.le + _ ≤ rothNumberNat N := mod_cast rothNumberNat.mono this rw [← rpow_nat_cast, div_rpow (rpow_nonneg_of_nonneg hN₀.le _) (exp_pos _).le, ← rpow_mul hN₀.le, - mul_comm (_ / _), mul_one_div, cast_sub hn₂, cast_two, same_sub_div hn.ne', exp_one_rpow, + inv_mul_eq_div, cast_sub hn₂.le, cast_two, same_sub_div hn.ne', exp_one_rpow, div_div, rpow_sub hN₀, rpow_one, div_div, div_eq_mul_inv] refine' mul_le_mul_of_nonneg_left _ (cast_nonneg _) rw [mul_inv, mul_inv, ← exp_neg, ← rpow_neg (cast_nonneg _), neg_sub, ← div_eq_mul_inv] diff --git a/Mathlib/Combinatorics/SetFamily/FourFunctions.lean b/Mathlib/Combinatorics/SetFamily/FourFunctions.lean index 12049feaf31d6..a75d667611083 100644 --- a/Mathlib/Combinatorics/SetFamily/FourFunctions.lean +++ b/Mathlib/Combinatorics/SetFamily/FourFunctions.lean @@ -358,4 +358,5 @@ lemma Finset.le_card_diffs_mul_card_diffs (s t : Finset α) : /-- The **Marica-Schönheim Inequality**. -/ lemma Finset.card_le_card_diffs (s : Finset α) : s.card ≤ (s \\ s).card := - le_of_pow_le_pow 2 (zero_le _) two_pos $ by simpa [← sq] using s.le_card_diffs_mul_card_diffs s + le_of_pow_le_pow_left two_ne_zero (zero_le _) $ by + simpa [← sq] using s.le_card_diffs_mul_card_diffs s diff --git a/Mathlib/Combinatorics/SetFamily/Kleitman.lean b/Mathlib/Combinatorics/SetFamily/Kleitman.lean index 21c5d6084a869..559b18e16d228 100644 --- a/Mathlib/Combinatorics/SetFamily/Kleitman.lean +++ b/Mathlib/Combinatorics/SetFamily/Kleitman.lean @@ -81,6 +81,6 @@ theorem Finset.card_biUnion_le_of_intersecting (s : Finset ι) (f : ι → Finse (ih _ (fun i hi ↦ (hf₁ _ <| subset_cons _ hi).2.2) ((card_le_of_subset <| subset_cons _).trans hs)) _).trans _ rw [mul_tsub, two_mul, ← pow_succ, - ← add_tsub_assoc_of_le (pow_le_pow' (one_le_two : (1 : ℕ) ≤ 2) tsub_le_self), + ← add_tsub_assoc_of_le (pow_le_pow_right' (one_le_two : (1 : ℕ) ≤ 2) tsub_le_self), tsub_add_eq_add_tsub hs, card_cons, add_tsub_add_eq_tsub_right] #align finset.card_bUnion_le_of_intersecting Finset.card_biUnion_le_of_intersecting diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean index 866a22b248f8c..87b8f92135ef7 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean @@ -74,7 +74,7 @@ private theorem eps_pos {ε : ℝ} {n : ℕ} (h : 100 ≤ (4 : ℝ) ^ n * ε ^ 5 (pos_of_mul_pos_right ((show 0 < (100 : ℝ) by norm_num).trans_le h) (by positivity)) private theorem m_pos [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) : 0 < m := - Nat.div_pos ((Nat.mul_le_mul_left _ <| Nat.pow_le_pow_of_le_left (by norm_num) _).trans hPα) <| + Nat.div_pos ((Nat.mul_le_mul_left _ <| Nat.pow_le_pow_left (by norm_num) _).trans hPα) <| stepBound_pos (P.parts_nonempty <| univ_nonempty.ne_empty).card_pos /-- Local extension for the `positivity` tactic: A few facts that are needed many times for the diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean index 4d389e9f879b4..0b50659e47bda 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean @@ -120,7 +120,7 @@ private theorem card_nonuniformWitness_sdiff_biUnion_star (hV : V ∈ P.parts) ( rw [sum_const] refine' mul_le_mul_right' _ _ have t := card_filter_atomise_le_two_pow (s := U) hX - refine' t.trans (pow_le_pow (by norm_num) <| tsub_le_tsub_right _ _) + refine' t.trans (pow_le_pow_right (by norm_num) <| tsub_le_tsub_right _ _) exact card_image_le.trans (card_le_of_subset <| filter_subset _ _) private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ P.parts) @@ -245,7 +245,7 @@ private theorem m_add_one_div_m_le_one_add [Nonempty α] have : ↑1 + ↑1 / (m : ℝ) ≤ ↑1 + ε ^ 5 / 100 := by rw [add_le_add_iff_left, ← one_div_div (100 : ℝ)] exact one_div_le_one_div_of_le (by sz_positivity) (hundred_div_ε_pow_five_le_m hPα hPε) - refine' (pow_le_pow_of_le_left _ this 2).trans _ + refine' (pow_le_pow_left _ this 2).trans _ · positivity rw [add_sq, one_pow, add_assoc, add_le_add_iff_left, mul_one, ← le_sub_iff_add_le', div_eq_mul_one_div _ (49 : ℝ), mul_div_left_comm (2 : ℝ), ← mul_sub_left_distrib, div_pow, @@ -367,7 +367,7 @@ private theorem edgeDensity_chunk_aux [Nonempty α] · rw [biUnion_parts, biUnion_parts] · rw [card_chunk (m_pos hPα).ne', card_chunk (m_pos hPα).ne', ← cast_mul, ← mul_pow, cast_pow] norm_cast - refine' le_trans _ (pow_le_pow_of_le_left hGε this 2) + refine' le_trans _ (pow_le_pow_left hGε this 2) rw [sub_sq, sub_add, sub_le_sub_iff_left] refine' (sub_le_self _ <| sq_nonneg <| ε ^ 5 / 50).trans _ rw [mul_right_comm, mul_div_left_comm, div_eq_mul_inv (ε ^ 5), diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean index 2e0c36d7492bf..0be6b52ec2371 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean @@ -65,7 +65,7 @@ variable {hP G ε} theorem card_increment (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPG : ¬P.IsUniform G ε) : (increment hP G ε).parts.card = stepBound P.parts.card := by have hPα' : stepBound P.parts.card ≤ card α := - (mul_le_mul_left' (pow_le_pow_of_le_left' (by norm_num) _) _).trans hPα + (mul_le_mul_left' (pow_le_pow_left' (by norm_num) _) _).trans hPα have hPpos : 0 < stepBound P.parts.card := stepBound_pos (nonempty_of_not_uniform hPG).card_pos rw [increment, card_bind] simp_rw [chunk, apply_dite Finpartition.parts, apply_dite card, sum_dite] diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean index ab1ac9b9e648f..caad9b8ea7bf5 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean @@ -104,7 +104,7 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : refine' ⟨P, hP₁, (le_initialBound _ _).trans hP₂, hP₃.trans _, hP₄.resolve_right fun hPenergy => lt_irrefl (1 : ℝ) _⟩ · rw [iterate_succ_apply'] - exact mul_le_mul_left' (pow_le_pow_of_le_left (by norm_num) (by norm_num) _) _ + exact mul_le_mul_left' (pow_le_pow_left (by norm_num) (by norm_num) _) _ calc (1 : ℝ) = ε ^ 5 / ↑4 * (↑4 / ε ^ 5) := by rw [mul_comm, div_mul_div_cancel 4 (pow_pos hε 5).ne']; norm_num @@ -131,7 +131,7 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : -- We gather a few numerical facts. have hεl' : ↑100 < ↑4 ^ P.parts.card * ε ^ 5 := (hundred_lt_pow_initialBound_mul hε l).trans_le - (mul_le_mul_of_nonneg_right (pow_le_pow (by norm_num) hP₂) <| by positivity) + (mul_le_mul_of_nonneg_right (pow_le_pow_right (by norm_num) hP₂) <| by positivity) have hi : (i : ℝ) ≤ 4 / ε ^ 5 := by have hi : ε ^ 5 / 4 * ↑i ≤ 1 := hP₄.trans (mod_cast P.energy_le_one G) rw [div_mul_eq_mul_div, div_le_iff (show (0 : ℝ) < 4 by norm_num)] at hi diff --git a/Mathlib/Computability/Ackermann.lean b/Mathlib/Computability/Ackermann.lean index 2a4625465eeec..436e1d581b3a1 100644 --- a/Mathlib/Computability/Ackermann.lean +++ b/Mathlib/Computability/Ackermann.lean @@ -101,7 +101,7 @@ theorem ack_three (n : ℕ) : ack 3 n = 2 ^ (n + 3) - 3 := by Nat.mul_sub_left_distrib, ← Nat.sub_add_comm, two_mul 3, Nat.add_sub_add_right] have H : 2 * 3 ≤ 2 * 2 ^ 3 := by norm_num apply H.trans - simp [pow_le_pow (show 1 ≤ 2 by norm_num)] + simp [pow_le_pow_right (show 1 ≤ 2 by norm_num)] #align ack_three ack_three theorem ack_pos : ∀ m n, 0 < ack m n @@ -297,7 +297,7 @@ theorem ack_ack_lt_ack_max_add_two (m n k : ℕ) : ack m (ack n k) < ack (max m theorem ack_add_one_sq_lt_ack_add_four (m n : ℕ) : ack m ((n + 1) ^ 2) < ack (m + 4) n := calc ack m ((n + 1) ^ 2) < ack m ((ack m n + 1) ^ 2) := - ack_strictMono_right m <| pow_lt_pow_of_lt_left (succ_lt_succ <| lt_ack_right m n) zero_lt_two + ack_strictMono_right m <| Nat.pow_lt_pow_left (succ_lt_succ <| lt_ack_right m n) two_ne_zero _ ≤ ack m (ack (m + 3) n) := ack_mono_right m <| ack_add_one_sq_lt_ack_add_three m n _ ≤ ack (m + 2) (ack (m + 3) n) := ack_mono_left _ <| by linarith _ = ack (m + 3) (n + 1) := (ack_succ_succ _ n).symm @@ -332,7 +332,7 @@ theorem exists_lt_ack_of_nat_primrec {f : ℕ → ℕ} (hf : Nat.Primrec f) : · refine' ⟨max a b + 3, fun n => (pair_lt_max_add_one_sq _ _).trans_le <| - (pow_le_pow_of_le_left (add_le_add_right _ _) 2).trans <| + (Nat.pow_le_pow_left (add_le_add_right _ _) 2).trans <| ack_add_one_sq_lt_ack_add_three _ _⟩ rw [max_ack_left] exact max_le_max (ha n).le (hb n).le diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index bfa38712bcf97..5c3bddf507301 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -1584,7 +1584,7 @@ theorem cosh_pos (x : ℝ) : 0 < Real.cosh x := #align real.cosh_pos Real.cosh_pos theorem sinh_lt_cosh : sinh x < cosh x := - lt_of_pow_lt_pow 2 (cosh_pos _).le <| (cosh_sq x).symm ▸ lt_add_one _ + lt_of_pow_lt_pow_left 2 (cosh_pos _).le <| (cosh_sq x).symm ▸ lt_add_one _ #align real.sinh_lt_cosh Real.sinh_lt_cosh end Real @@ -2007,7 +2007,7 @@ theorem one_sub_div_pow_le_exp_neg {n : ℕ} {t : ℝ} (ht' : t ≤ n) : (1 - t rcases eq_or_ne n 0 with (rfl | hn) · simp rwa [Nat.cast_zero] at ht' - convert pow_le_pow_of_le_left ?_ (one_sub_le_exp_neg (t / n)) n using 2 + convert pow_le_pow_left ?_ (one_sub_le_exp_neg (t / n)) n using 2 · rw [← Real.exp_nat_mul] congr 1 field_simp diff --git a/Mathlib/Data/Nat/Bitwise.lean b/Mathlib/Data/Nat/Bitwise.lean index 49d6f62404066..2223d72162f89 100644 --- a/Mathlib/Data/Nat/Bitwise.lean +++ b/Mathlib/Data/Nat/Bitwise.lean @@ -281,7 +281,7 @@ theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = f cases' hm.lt_or_lt with hm hm · rw [Nat.div_eq_of_lt] · simp - · exact Nat.pow_lt_pow_of_lt_right one_lt_two hm + · exact pow_lt_pow_right one_lt_two hm · rw [pow_div hm.le zero_lt_two, ← tsub_add_cancel_of_le (succ_le_of_lt <| tsub_pos_of_lt hm)] -- Porting note: XXX why does this make it work? rw [(rfl : succ 0 = 1)] @@ -490,6 +490,6 @@ lemma shiftLeft_lt {x n m : ℕ} (h : x < 2 ^ n) : x <<< m < 2 ^ (n + m) := by lemma append_lt {x y n m} (hx : x < 2 ^ n) (hy : y < 2 ^ m) : y <<< n ||| x < 2 ^ (n + m) := by apply bitwise_lt · rw [add_comm]; apply shiftLeft_lt hy - · apply lt_of_lt_of_le hx <| pow_le_pow (le_succ _) (le_add_right _ _) + · apply lt_of_lt_of_le hx <| pow_le_pow_right (le_succ _) (le_add_right _ _) end Nat diff --git a/Mathlib/Data/Nat/Choose/Factorization.lean b/Mathlib/Data/Nat/Choose/Factorization.lean index 7f0dcf923109f..c81ab23f61e04 100644 --- a/Mathlib/Data/Nat/Choose/Factorization.lean +++ b/Mathlib/Data/Nat/Choose/Factorization.lean @@ -85,7 +85,7 @@ theorem factorization_choose_of_lt_three_mul (hp' : p ≠ 2) (hk : p ≤ k) (hk' n < 3 * p := hn _ ≤ p * p := mul_le_mul_right' this p _ = p ^ 2 := (sq p).symm - _ ≤ p ^ i := pow_le_pow hp.one_lt.le hi + _ ≤ p ^ i := pow_le_pow_right hp.one_lt.le hi rwa [mod_eq_of_lt (lt_of_le_of_lt hkn hn), mod_eq_of_lt (lt_of_le_of_lt tsub_le_self hn), add_tsub_cancel_of_le hkn] #align nat.factorization_choose_of_lt_three_mul Nat.factorization_choose_of_lt_three_mul diff --git a/Mathlib/Data/Nat/Factorial/Basic.lean b/Mathlib/Data/Nat/Factorial/Basic.lean index 0d7f963f8dda6..7a2b7b4d7626e 100644 --- a/Mathlib/Data/Nat/Factorial/Basic.lean +++ b/Mathlib/Data/Nat/Factorial/Basic.lean @@ -202,13 +202,9 @@ theorem add_factorial_le_factorial_add (i : ℕ) {n : ℕ} (n1 : 1 ≤ n) : i + #align nat.add_factorial_le_factorial_add Nat.add_factorial_le_factorial_add theorem factorial_mul_pow_sub_le_factorial {n m : ℕ} (hnm : n ≤ m) : n ! * n ^ (m - n) ≤ m ! := by - suffices n ! * (n + 1) ^ (m - n) ≤ m ! from by - apply LE.le.trans _ this - apply mul_le_mul_left - apply pow_le_pow_of_le_left (le_succ n) - have := @Nat.factorial_mul_pow_le_factorial n (m - n) - simp? [hnm] at this says simp only [ge_iff_le, hnm, add_tsub_cancel_of_le] at this - exact this + calc + _ ≤ n ! * (n + 1) ^ (m - n) := mul_le_mul_left' (Nat.pow_le_pow_left n.le_succ _) _ + _ ≤ _ := by simpa [hnm] using @Nat.factorial_mul_pow_le_factorial n (m - n) #align nat.factorial_mul_pow_sub_le_factorial Nat.factorial_mul_pow_sub_le_factorial end Factorial @@ -297,7 +293,7 @@ theorem ascFactorial_le_pow_add (n : ℕ) : ∀ k : ℕ, n.ascFactorial k ≤ (n rw [ascFactorial_succ, pow_succ, ← add_assoc, mul_comm _ (succ (n + k))] exact Nat.mul_le_mul_of_nonneg_left - ((ascFactorial_le_pow_add _ k).trans (Nat.pow_le_pow_of_le_left (le_succ _) _)) + ((ascFactorial_le_pow_add _ k).trans (Nat.pow_le_pow_left (le_succ _) _)) #align nat.asc_factorial_le_pow_add Nat.ascFactorial_le_pow_add theorem ascFactorial_lt_pow_add (n : ℕ) : ∀ {k : ℕ}, 2 ≤ k → n.ascFactorial k < (n + k) ^ k @@ -306,11 +302,8 @@ theorem ascFactorial_lt_pow_add (n : ℕ) : ∀ {k : ℕ}, 2 ≤ k → n.ascFact | k + 2 => fun _ => by rw [ascFactorial_succ, pow_succ] rw [add_assoc n (k + 1) 1, mul_comm <| (n + (k + 2)) ^ (k + 1)] - refine' - Nat.mul_lt_mul' le_rfl - ((ascFactorial_le_pow_add n _).trans_lt - (pow_lt_pow_of_lt_left (lt_add_one _) (succ_pos _))) - (succ_pos _) + exact mul_lt_mul_of_pos_left ((ascFactorial_le_pow_add n _).trans_lt $ + Nat.pow_lt_pow_left (lt_add_one _) k.succ_ne_zero) (succ_pos _) #align nat.asc_factorial_lt_pow_add Nat.ascFactorial_lt_pow_add theorem ascFactorial_pos (n k : ℕ) : 0 < n.ascFactorial k := @@ -409,7 +402,7 @@ theorem pow_sub_le_descFactorial (n : ℕ) : ∀ k : ℕ, (n + 1 - k) ^ k ≤ n. | k + 1 => by rw [descFactorial_succ, pow_succ, succ_sub_succ, mul_comm] apply Nat.mul_le_mul_of_nonneg_left - exact (le_trans (Nat.pow_le_pow_of_le_left (tsub_le_tsub_right (le_succ _) _) k) + exact (le_trans (Nat.pow_le_pow_left (tsub_le_tsub_right (le_succ _) _) k) (pow_sub_le_descFactorial n k)) #align nat.pow_sub_le_desc_factorial Nat.pow_sub_le_descFactorial @@ -423,7 +416,7 @@ theorem pow_sub_lt_descFactorial' {n : ℕ} : | k + 1 => fun h => by rw [descFactorial_succ, pow_succ, mul_comm] apply Nat.mul_lt_mul_of_pos_left - · refine' ((Nat.pow_le_pow_of_le_left (tsub_le_tsub_right (le_succ n) _) _).trans_lt _) + · refine' ((Nat.pow_le_pow_left (tsub_le_tsub_right (le_succ n) _) _).trans_lt _) rw [succ_sub_succ] exact pow_sub_lt_descFactorial' ((le_succ _).trans h) · apply tsub_pos_of_lt; apply h diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index eb01479ad42c0..9ffc3a06ff529 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -395,12 +395,8 @@ theorem ord_compl_mul (a b p : ℕ) : ord_compl[p] (a * b) = ord_compl[p] a * or /-- A crude upper bound on `n.factorization p` -/ theorem factorization_lt {n : ℕ} (p : ℕ) (hn : n ≠ 0) : n.factorization p < n := by by_cases pp : p.Prime - case neg => - simp only [factorization_eq_zero_of_non_prime n pp] - exact hn.bot_lt - rw [← pow_lt_iff_lt_right pp.two_le] - apply lt_of_le_of_lt (ord_proj_le p hn) - exact lt_of_lt_of_le (lt_two_pow n) (pow_le_pow_of_le_left pp.two_le n) + · exact (pow_lt_pow_iff_right pp.one_lt).1 $ (ord_proj_le p hn).trans_lt $ lt_pow_self pp.one_lt _ + · simpa only [factorization_eq_zero_of_non_prime n pp] using hn.bot_lt #align nat.factorization_lt Nat.factorization_lt /-- An upper bound on `n.factorization p` -/ @@ -408,7 +404,7 @@ theorem factorization_le_of_le_pow {n p b : ℕ} (hb : n ≤ p ^ b) : n.factoriz rcases eq_or_ne n 0 with (rfl | hn) · simp by_cases pp : p.Prime - · exact (pow_le_iff_le_right pp.two_le).1 (le_trans (ord_proj_le p hn) hb) + · exact (pow_le_pow_iff_right pp.one_lt).1 ((ord_proj_le p hn).trans hb) · simp [factorization_eq_zero_of_non_prime n pp] #align nat.factorization_le_of_le_pow Nat.factorization_le_of_le_pow @@ -702,8 +698,8 @@ theorem Ico_filter_pow_dvd_eq {n p b : ℕ} (pp : p.Prime) (hn : n ≠ 0) (hb : ext x simp only [Finset.mem_filter, mem_Ico, mem_Icc, and_congr_left_iff, and_congr_right_iff] rintro h1 - - simp [lt_of_pow_dvd_right hn pp.two_le h1, - (pow_le_iff_le_right pp.two_le).1 ((le_of_dvd hn.bot_lt h1).trans hb)] + exact iff_of_true (lt_of_pow_dvd_right hn pp.two_le h1) $ + (pow_le_pow_iff_right pp.one_lt).1 $ (le_of_dvd hn.bot_lt h1).trans hb #align nat.Ico_filter_pow_dvd_eq Nat.Ico_filter_pow_dvd_eq /-! ### Factorization and coprimes -/ @@ -763,10 +759,7 @@ def recOnPrimePow {P : ℕ → Sort*} (h0 : P 0) (h1 : P 1) · rw [Nat.mul_div_cancel' hpt] · rw [Nat.dvd_div_iff hpt, ← pow_succ] exact pow_succ_factorization_not_dvd (k + 1).succ_ne_zero hp - · rw [lt_mul_iff_one_lt_left Nat.succ_pos', one_lt_pow_iff htp.ne] - exact hp.one_lt - -- Porting note: was - -- simp [lt_mul_iff_one_lt_left Nat.succ_pos', one_lt_pow_iff htp.ne, hp.one_lt] + · simp [lt_mul_iff_one_lt_left Nat.succ_pos', one_lt_pow_iff htp.ne', hp.one_lt] #align nat.rec_on_prime_pow Nat.recOnPrimePow /-- Given `P 0`, `P 1`, and `P (p ^ n)` for positive prime powers, and a way to extend `P a` and diff --git a/Mathlib/Data/Nat/Log.lean b/Mathlib/Data/Nat/Log.lean index 003252fd98157..b247618d89f9c 100644 --- a/Mathlib/Data/Nat/Log.lean +++ b/Mathlib/Data/Nat/Log.lean @@ -140,7 +140,7 @@ theorem log_eq_iff {b m n : ℕ} (h : m ≠ 0 ∨ 1 < b ∧ n ≠ 0) : rw [not_and_or, not_lt, Ne.def, not_not] at hbn rcases hbn with (hb | rfl) · simpa only [log_of_left_le_one hb, hm.symm, false_iff_iff, not_and, not_lt] using - le_trans (pow_le_pow_of_le_one' hb m.le_succ) + le_trans (pow_le_pow_right_of_le_one' hb m.le_succ) · simpa only [log_zero_right, hm.symm, nonpos_iff_eq_zero, false_iff, not_and, not_lt, add_pos_iff, zero_lt_one, or_true, pow_eq_zero_iff] using pow_eq_zero #align nat.log_eq_iff Nat.log_eq_iff @@ -154,7 +154,7 @@ theorem log_eq_of_pow_le_of_lt_pow {b m n : ℕ} (h₁ : b ^ m ≤ n) (h₂ : n #align nat.log_eq_of_pow_le_of_lt_pow Nat.log_eq_of_pow_le_of_lt_pow theorem log_pow {b : ℕ} (hb : 1 < b) (x : ℕ) : log b (b ^ x) = x := - log_eq_of_pow_le_of_lt_pow le_rfl (pow_lt_pow hb x.lt_succ_self) + log_eq_of_pow_le_of_lt_pow le_rfl (pow_lt_pow_right hb x.lt_succ_self) #align nat.log_pow Nat.log_pow theorem log_eq_one_iff' {b n : ℕ} : log b n = 1 ↔ b ≤ n ∧ n < b * b := by @@ -195,7 +195,7 @@ theorem log_anti_left {b c n : ℕ} (hc : 1 < c) (hb : c ≤ b) : log b n ≤ lo rcases eq_or_ne n 0 with (rfl | hn); · rw [log_zero_right, log_zero_right] apply le_log_of_pow_le hc calc - c ^ log b n ≤ b ^ log b n := pow_le_pow_of_le_left' hb _ + c ^ log b n ≤ b ^ log b n := pow_le_pow_left' hb _ _ ≤ n := pow_log_le_self _ hn #align nat.log_anti_left Nat.log_anti_left @@ -340,7 +340,7 @@ theorem clog_anti_left {b c n : ℕ} (hc : 1 < c) (hb : c ≤ b) : clog b n ≤ rw [← le_pow_iff_clog_le (lt_of_lt_of_le hc hb)] calc n ≤ c ^ clog c n := le_pow_clog hc _ - _ ≤ b ^ clog c n := pow_le_pow_of_le_left hb _ + _ ≤ b ^ clog c n := Nat.pow_le_pow_left hb _ #align nat.clog_anti_left Nat.clog_anti_left theorem clog_monotone (b : ℕ) : Monotone (clog b) := fun _ _ => clog_mono_right _ diff --git a/Mathlib/Data/Nat/Pow.lean b/Mathlib/Data/Nat/Pow.lean index ba5c2d1bbc43b..8b23728b822ad 100644 --- a/Mathlib/Data/Nat/Pow.lean +++ b/Mathlib/Data/Nat/Pow.lean @@ -14,26 +14,29 @@ Results on the power operation on natural numbers. namespace Nat +variable {m n x y : ℕ} /-! ### `pow` -/ -- Porting note: the next two lemmas have moved into `Std`. +-- TODO: Rename `Nat.pow_le_pow_of_le_left` to `Nat.pow_le_pow_left`, protect it, remove the alias +-- TODO: Rename `Nat.pow_le_pow_of_le_right` to `Nat.pow_le_pow_right`, protect it, remove the alias --- The global `pow_le_pow_of_le_left` needs an extra hypothesis `0 ≤ x`. -#align nat.pow_le_pow_of_le_left Nat.pow_le_pow_of_le_left -#align nat.pow_le_pow_of_le_right Nat.pow_le_pow_of_le_right +-- The global `pow_le_pow_left` needs an extra hypothesis `0 ≤ x`. +protected alias pow_le_pow_left := pow_le_pow_of_le_left +protected alias pow_le_pow_right := pow_le_pow_of_le_right +#align nat.pow_le_pow_of_le_left Nat.pow_le_pow_left +#align nat.pow_le_pow_of_le_right Nat.pow_le_pow_right -theorem pow_lt_pow_of_lt_left {x y : ℕ} (H : x < y) {i} (h : 0 < i) : x ^ i < y ^ i := - _root_.pow_lt_pow_of_lt_left H (zero_le _) h -#align nat.pow_lt_pow_of_lt_left Nat.pow_lt_pow_of_lt_left +protected theorem pow_lt_pow_left (h : x < y) (hn : n ≠ 0) : x ^ n < y ^ n := + pow_lt_pow_left h (zero_le _) hn +#align nat.pow_lt_pow_of_lt_left Nat.pow_lt_pow_left -theorem pow_lt_pow_of_lt_right {x : ℕ} (H : 1 < x) {i j : ℕ} (h : i < j) : x ^ i < x ^ j := - pow_lt_pow H h -#align nat.pow_lt_pow_of_lt_right Nat.pow_lt_pow_of_lt_right +#align nat.pow_lt_pow_of_lt_right pow_lt_pow_right theorem pow_lt_pow_succ {p : ℕ} (h : 1 < p) (n : ℕ) : p ^ n < p ^ (n + 1) := - pow_lt_pow_of_lt_right h n.lt_succ_self + pow_lt_pow_right h n.lt_succ_self #align nat.pow_lt_pow_succ Nat.pow_lt_pow_succ theorem le_self_pow {n : ℕ} (hn : n ≠ 0) : ∀ m : ℕ, m ≤ m ^ n @@ -66,9 +69,9 @@ theorem one_le_two_pow (n : ℕ) : 1 ≤ 2 ^ n := one_le_pow n 2 (by decide) #align nat.one_le_two_pow Nat.one_le_two_pow -theorem one_lt_pow (n m : ℕ) (h₀ : 0 < n) (h₁ : 1 < m) : 1 < m ^ n := by +theorem one_lt_pow (n m : ℕ) (h₀ : n ≠ 0) (h₁ : 1 < m) : 1 < m ^ n := by rw [← one_pow n] - exact pow_lt_pow_of_lt_left h₁ h₀ + exact Nat.pow_lt_pow_left h₁ h₀ #align nat.one_lt_pow Nat.one_lt_pow theorem two_pow_pos (n : ℕ) : 0 < 2^n := Nat.pos_pow_of_pos _ (by decide) @@ -76,50 +79,32 @@ theorem two_pow_pos (n : ℕ) : 0 < 2^n := Nat.pos_pow_of_pos _ (by decide) theorem two_pow_succ (n : ℕ) : 2^(n + 1) = 2^n + 2^n := by simp [pow_succ, mul_two] theorem one_lt_pow' (n m : ℕ) : 1 < (m + 2) ^ (n + 1) := - one_lt_pow (n + 1) (m + 2) (succ_pos n) (Nat.lt_of_sub_eq_succ rfl) + one_lt_pow (n + 1) (m + 2) n.succ_ne_zero (Nat.lt_of_sub_eq_succ rfl) #align nat.one_lt_pow' Nat.one_lt_pow' @[simp] -theorem one_lt_pow_iff {k n : ℕ} (h : 0 ≠ k) : 1 < n ^ k ↔ 1 < n := by - rcases n with (rfl | n) - · cases k <;> simp [zero_pow_eq] - rcases n with (rfl | n) - · rw [← Nat.one_eq_succ_zero, one_pow] - refine' ⟨fun _ => one_lt_succ_succ n, fun _ => _⟩ - induction' k with k hk - · exact absurd rfl h - rcases k with (rfl | k) - · simp [← Nat.one_eq_succ_zero] - rw [pow_succ'] - exact one_lt_mul (one_lt_succ_succ _).le (hk (succ_ne_zero k).symm) +theorem one_lt_pow_iff {k n : ℕ} (h : k ≠ 0) : 1 < n ^ k ↔ 1 < n := + one_lt_pow_iff_of_nonneg (zero_le _) h #align nat.one_lt_pow_iff Nat.one_lt_pow_iff -theorem one_lt_two_pow (n : ℕ) (h₀ : 0 < n) : 1 < 2 ^ n := - one_lt_pow n 2 h₀ (by decide) +theorem one_lt_two_pow (n : ℕ) (h₀ : n ≠ 0) : 1 < 2 ^ n := one_lt_pow n 2 h₀ (by decide) #align nat.one_lt_two_pow Nat.one_lt_two_pow theorem one_lt_two_pow' (n : ℕ) : 1 < 2 ^ (n + 1) := - one_lt_pow (n + 1) 2 (succ_pos n) (by decide) + one_lt_pow (n + 1) 2 n.succ_ne_zero (by decide) #align nat.one_lt_two_pow' Nat.one_lt_two_pow' -theorem pow_right_strictMono {x : ℕ} (k : 2 ≤ x) : StrictMono fun n : ℕ => x ^ n := fun _ _ => - pow_lt_pow_of_lt_right k -#align nat.pow_right_strict_mono Nat.pow_right_strictMono +#align nat.pow_right_strict_mono pow_right_strictMono +#align nat.pow_le_iff_lt_right pow_le_pow_iff_right +#align nat.pow_lt_iff_lt_right pow_lt_pow_iff_right -theorem pow_le_iff_le_right {x m n : ℕ} (k : 2 ≤ x) : x ^ m ≤ x ^ n ↔ m ≤ n := - StrictMono.le_iff_le (pow_right_strictMono k) -#align nat.pow_le_iff_le_right Nat.pow_le_iff_le_right - -theorem pow_lt_iff_lt_right {x m n : ℕ} (k : 2 ≤ x) : x ^ m < x ^ n ↔ m < n := - StrictMono.lt_iff_lt (pow_right_strictMono k) -#align nat.pow_lt_iff_lt_right Nat.pow_lt_iff_lt_right - -theorem pow_right_injective {x : ℕ} (k : 2 ≤ x) : Function.Injective fun n : ℕ => x ^ n := - StrictMono.injective (pow_right_strictMono k) +protected lemma pow_right_injective (hx : 2 ≤ x) : Function.Injective (x ^ ·) := + StrictMono.injective (pow_right_strictMono hx) #align nat.pow_right_injective Nat.pow_right_injective -theorem pow_left_strictMono {m : ℕ} (k : 1 ≤ m) : StrictMono fun x : ℕ => x ^ m := fun _ _ h => - pow_lt_pow_of_lt_left h k +/-- See also `pow_left_strictMonoOn`. -/ +protected theorem pow_left_strictMono (hn : n ≠ 0) : StrictMono (. ^ n : ℕ → ℕ) := + fun _ _ h ↦ Nat.pow_lt_pow_left h hn #align nat.pow_left_strict_mono Nat.pow_left_strictMono theorem mul_lt_mul_pow_succ {n a q : ℕ} (a0 : 0 < a) (q1 : 1 < q) : n * q < a * q ^ (n + 1) := by @@ -127,25 +112,21 @@ theorem mul_lt_mul_pow_succ {n a q : ℕ} (a0 : 0 < a) (q1 : 1 < q) : n * q < a exact lt_mul_of_one_le_of_lt (Nat.succ_le_iff.mpr a0) (Nat.lt_pow_self q1 n) #align nat.mul_lt_mul_pow_succ Nat.mul_lt_mul_pow_succ -end Nat - -theorem StrictMono.nat_pow {n : ℕ} (hn : 1 ≤ n) {f : ℕ → ℕ} (hf : StrictMono f) : +theorem _root_.StrictMono.nat_pow {n : ℕ} (hn : n ≠ 0) {f : ℕ → ℕ} (hf : StrictMono f) : StrictMono fun m => f m ^ n := (Nat.pow_left_strictMono hn).comp hf #align strict_mono.nat_pow StrictMono.nat_pow -namespace Nat - -theorem pow_le_iff_le_left {m x y : ℕ} (k : 1 ≤ m) : x ^ m ≤ y ^ m ↔ x ≤ y := - StrictMono.le_iff_le (pow_left_strictMono k) -#align nat.pow_le_iff_le_left Nat.pow_le_iff_le_left +protected theorem pow_le_pow_iff_left (hm : m ≠ 0) : x ^ m ≤ y ^ m ↔ x ≤ y := + pow_le_pow_iff_left (zero_le _) (zero_le _) hm +#align nat.pow_le_iff_le_left Nat.pow_le_pow_iff_left -theorem pow_lt_iff_lt_left {m x y : ℕ} (k : 1 ≤ m) : x ^ m < y ^ m ↔ x < y := - StrictMono.lt_iff_lt (pow_left_strictMono k) -#align nat.pow_lt_iff_lt_left Nat.pow_lt_iff_lt_left +protected theorem pow_lt_pow_iff_left (hm : m ≠ 0) : x ^ m < y ^ m ↔ x < y := + pow_lt_pow_iff_left (zero_le _) (zero_le _) hm +#align nat.pow_lt_iff_lt_left Nat.pow_lt_pow_iff_left -theorem pow_left_injective {m : ℕ} (k : 1 ≤ m) : Function.Injective fun x : ℕ => x ^ m := - StrictMono.injective (pow_left_strictMono k) +theorem pow_left_injective (hm : m ≠ 0) : Function.Injective fun x : ℕ => x ^ m := + (Nat.pow_left_strictMono hm).injective #align nat.pow_left_injective Nat.pow_left_injective theorem sq_sub_sq (a b : ℕ) : a ^ 2 - b ^ 2 = (a + b) * (a - b) := by @@ -203,14 +184,14 @@ theorem pow_dvd_pow_iff_pow_le_pow {k l : ℕ} : ∀ {x : ℕ} (_ : 0 < x), x ^ · intro a cases' x with x · simp - · have le := (pow_le_iff_le_right (Nat.le_add_left _ _)).mp a + · have le := (pow_le_pow_iff_right $ by simp).mp a use (x + 2) ^ (l - k) rw [← pow_add, add_comm k, tsub_add_cancel_of_le le] #align nat.pow_dvd_pow_iff_pow_le_pow Nat.pow_dvd_pow_iff_pow_le_pow /-- If `1 < x`, then `x^k` divides `x^l` if and only if `k` is at most `l`. -/ theorem pow_dvd_pow_iff_le_right {x k l : ℕ} (w : 1 < x) : x ^ k ∣ x ^ l ↔ k ≤ l := by - rw [pow_dvd_pow_iff_pow_le_pow (lt_of_succ_lt w), pow_le_iff_le_right w] + rw [pow_dvd_pow_iff_pow_le_pow (lt_of_succ_lt w), pow_le_pow_iff_right w] #align nat.pow_dvd_pow_iff_le_right Nat.pow_dvd_pow_iff_le_right theorem pow_dvd_pow_iff_le_right' {b k l : ℕ} : (b + 2) ^ k ∣ (b + 2) ^ l ↔ k ≤ l := @@ -242,7 +223,7 @@ theorem pow_div {x m n : ℕ} (h : n ≤ m) (hx : 0 < x) : x ^ m / x ^ n = x ^ ( #align nat.pow_div Nat.pow_div theorem lt_of_pow_dvd_right {p i n : ℕ} (hn : n ≠ 0) (hp : 2 ≤ p) (h : p ^ i ∣ n) : i < n := by - rw [← pow_lt_iff_lt_right hp] + rw [← pow_lt_pow_iff_right (succ_le_iff.1 hp)] exact lt_of_le_of_lt (le_of_dvd hn.bot_lt h) (lt_pow_self (succ_le_iff.mp hp) n) #align nat.lt_of_pow_dvd_right Nat.lt_of_pow_dvd_right diff --git a/Mathlib/Data/Nat/Size.lean b/Mathlib/Data/Nat/Size.lean index 0feaee57900ea..606a5e1e4a053 100644 --- a/Mathlib/Data/Nat/Size.lean +++ b/Mathlib/Data/Nat/Size.lean @@ -95,7 +95,7 @@ theorem size_shiftLeft' {b m n} (h : shiftLeft' b m n ≠ 0) : simp only [zero_add, one_mul] at this obtain rfl : n = 0 := Nat.eq_zero_of_le_zero - (le_of_not_gt fun hn => ne_of_gt (pow_lt_pow_of_lt_right (by decide) hn) this) + (le_of_not_gt fun hn => ne_of_gt (pow_lt_pow_right (by decide) hn) this) rfl #align nat.size_shiftl' Nat.size_shiftLeft' @@ -148,7 +148,7 @@ theorem size_eq_zero {n : ℕ} : size n = 0 ↔ n = 0 := by #align nat.size_eq_zero Nat.size_eq_zero theorem size_pow {n : ℕ} : size (2 ^ n) = n + 1 := - le_antisymm (size_le.2 <| pow_lt_pow_of_lt_right (by decide) (lt_succ_self _)) + le_antisymm (size_le.2 <| pow_lt_pow_right (by decide) (lt_succ_self _)) (lt_size.2 <| le_rfl) #align nat.size_pow Nat.size_pow diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index 20e7bd2170f90..e324c6530e488 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -354,7 +354,7 @@ theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) : refine' Nat.lt_le_asymm _ (Finset.le_max' S ((b * x) ^ 2) _) -- Porting note: these two goals were in the opposite order in Lean 3 · convert lt_mul_of_one_lt_right hlts - (one_lt_pow 2 x zero_lt_two (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩)) + (one_lt_pow 2 x two_ne_zero (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩)) using 1 rw [mul_pow] · simp_rw [hsa, Finset.mem_filter, Finset.mem_range] diff --git a/Mathlib/Data/Num/Lemmas.lean b/Mathlib/Data/Num/Lemmas.lean index 63ac9effd8277..b4a612239c28f 100644 --- a/Mathlib/Data/Num/Lemmas.lean +++ b/Mathlib/Data/Num/Lemmas.lean @@ -952,7 +952,7 @@ theorem castNum_shiftRight (m : Num) (n : Nat) : ↑(m >>> n) = (m : ℕ) >>> (n · rw [Nat.shiftRight_eq_div_pow] symm apply Nat.div_eq_of_lt - simp [@Nat.pow_lt_pow_of_lt_right 2 (by decide) 0 (n + 1) (Nat.succ_pos _)] + simp · trans apply IH change Nat.shiftRight m n = Nat.shiftRight (_root_.bit1 m) (n + 1) diff --git a/Mathlib/Data/Polynomial/Degree/CardPowDegree.lean b/Mathlib/Data/Polynomial/Degree/CardPowDegree.lean index be6609d0c9334..99474b5b3dd54 100644 --- a/Mathlib/Data/Polynomial/Degree/CardPowDegree.lean +++ b/Mathlib/Data/Polynomial/Degree/CardPowDegree.lean @@ -61,7 +61,7 @@ noncomputable def cardPowDegree : AbsoluteValue Fq[X] ℤ := · simp only [hpq, hp, hq, eq_self_iff_true, if_true, if_false] exact add_nonneg (pow_pos _).le (pow_pos _).le simp only [hpq, hp, hq, if_false] - refine' le_trans (pow_le_pow (by linarith) (Polynomial.natDegree_add_le _ _)) _ + refine' le_trans (pow_le_pow_right (by linarith) (Polynomial.natDegree_add_le _ _)) _ refine' le_trans (le_max_iff.mpr _) (max_le_add_of_nonneg (pow_nonneg (by linarith) _) (pow_nonneg (by linarith) _)) @@ -104,7 +104,7 @@ theorem cardPowDegree_isEuclidean : IsEuclidean (cardPowDegree : AbsoluteValue F · simp only [hp, hq, degree_zero, Ne.def, bot_lt_iff_ne_bot, degree_eq_bot, pow_pos, not_false_iff] · simp only [hp, hq, degree_zero, not_lt_bot, (pow_pos _).not_lt] - · rw [degree_eq_natDegree hp, degree_eq_natDegree hq, Nat.cast_lt, pow_lt_pow_iff] + · rw [degree_eq_natDegree hp, degree_eq_natDegree hq, Nat.cast_lt, pow_lt_pow_iff_right] exact mod_cast @Fintype.one_lt_card Fq _ _ } #align polynomial.card_pow_degree_is_euclidean Polynomial.cardPowDegree_isEuclidean diff --git a/Mathlib/Data/Polynomial/Degree/Lemmas.lean b/Mathlib/Data/Polynomial/Degree/Lemmas.lean index 6fb20d164aacd..90965bb8c1969 100644 --- a/Mathlib/Data/Polynomial/Degree/Lemmas.lean +++ b/Mathlib/Data/Polynomial/Degree/Lemmas.lean @@ -51,7 +51,7 @@ theorem natDegree_comp_le : natDegree (p.comp q) ≤ natDegree p * natDegree q : _ ≤ natDegree (C (coeff p n)) + n • degree q := (add_le_add degree_le_natDegree (degree_pow_le _ _)) _ ≤ natDegree (C (coeff p n)) + n • ↑(natDegree q) := - (add_le_add_left (nsmul_le_nsmul_of_le_right (@degree_le_natDegree _ _ q) n) _) + (add_le_add_left (nsmul_le_nsmul_right (@degree_le_natDegree _ _ q) n) _) _ = (n * natDegree q : ℕ) := by rw [natDegree_C, Nat.cast_zero, zero_add, nsmul_eq_mul]; simp diff --git a/Mathlib/Data/Real/ENNReal.lean b/Mathlib/Data/Real/ENNReal.lean index 16013ce9c274b..47f14748d308c 100644 --- a/Mathlib/Data/Real/ENNReal.lean +++ b/Mathlib/Data/Real/ENNReal.lean @@ -1030,7 +1030,7 @@ theorem pow_strictMono : ∀ {n : ℕ}, n ≠ 0 → StrictMono fun x : ℝ≥0 | (n + 1 + 1), _ => fun x y h => mul_lt_mul h (pow_strictMono n.succ_ne_zero h) #align ennreal.pow_strict_mono ENNReal.pow_strictMono -@[gcongr] protected theorem pow_lt_pow_of_lt_left (h : a < b) {n : ℕ} (hn : n ≠ 0) : +@[gcongr] protected theorem pow_lt_pow_left (h : a < b) {n : ℕ} (hn : n ≠ 0) : a ^ n < b ^ n := ENNReal.pow_strictMono hn h @@ -1977,13 +1977,13 @@ theorem Ioo_zero_top_eq_iUnion_Ico_zpow {y : ℝ≥0∞} (hy : 1 < y) (h'y : y theorem zpow_le_of_le {x : ℝ≥0∞} (hx : 1 ≤ x) {a b : ℤ} (h : a ≤ b) : x ^ a ≤ x ^ b := by induction' a with a a <;> induction' b with b b · simp only [Int.ofNat_eq_coe, zpow_ofNat] - exact pow_le_pow hx (Int.le_of_ofNat_le_ofNat h) + exact pow_le_pow_right hx (Int.le_of_ofNat_le_ofNat h) · apply absurd h (not_le_of_gt _) exact lt_of_lt_of_le (Int.negSucc_lt_zero _) (Int.ofNat_nonneg _) · simp only [zpow_negSucc, Int.ofNat_eq_coe, zpow_ofNat] refine' (ENNReal.inv_le_one.2 _).trans _ <;> exact one_le_pow_of_one_le' hx _ · simp only [zpow_negSucc, ENNReal.inv_le_inv] - apply pow_le_pow hx + apply pow_le_pow_right hx simpa only [← Int.ofNat_le, neg_le_neg_iff, Int.ofNat_add, Int.ofNat_one, Int.negSucc_eq] using h #align ennreal.zpow_le_of_le ENNReal.zpow_le_of_le diff --git a/Mathlib/Data/Real/Pi/Bounds.lean b/Mathlib/Data/Real/Pi/Bounds.lean index 4d05fd8800e2f..e4473ca0b6c14 100644 --- a/Mathlib/Data/Real/Pi/Bounds.lean +++ b/Mathlib/Data/Real/Pi/Bounds.lean @@ -45,11 +45,11 @@ theorem pi_lt_sqrtTwoAddSeries (n : ℕ) : · rw [div_le_iff'] · refine' le_trans pi_le_four _ simp only [show (4 : ℝ) = (2 : ℝ) ^ 2 by norm_num, mul_one] - apply pow_le_pow; norm_num; apply le_add_of_nonneg_left; apply Nat.zero_le + apply pow_le_pow_right; norm_num; apply le_add_of_nonneg_left; apply Nat.zero_le · apply pow_pos; norm_num apply add_le_add_left; rw [div_le_div_right] rw [le_div_iff, ← mul_pow] - refine' le_trans _ (le_of_eq (one_pow 3)); apply pow_le_pow_of_le_left + refine' le_trans _ (le_of_eq (one_pow 3)); apply pow_le_pow_left · apply le_of_lt; apply mul_pos; apply div_pos pi_pos; apply pow_pos; norm_num; apply pow_pos norm_num rw [← le_div_iff] diff --git a/Mathlib/Data/Real/Pi/Leibniz.lean b/Mathlib/Data/Real/Pi/Leibniz.lean index 644b510307692..a54c6ceb80ada 100644 --- a/Mathlib/Data/Real/Pi/Leibniz.lean +++ b/Mathlib/Data/Real/Pi/Leibniz.lean @@ -112,13 +112,13 @@ theorem tendsto_sum_pi_div_four : exact (le_add_of_nonneg_right (sq_nonneg x) : (1 : ℝ) ≤ _) have hbound1 : ∀ x ∈ Ico (U : ℝ) 1, |f' x| ≤ 1 := by rintro x ⟨hx_left, hx_right⟩ - have hincr := pow_le_pow_of_le_left (le_trans hU2 hx_left) (le_of_lt hx_right) (2 * k) + have hincr := pow_le_pow_left (le_trans hU2 hx_left) (le_of_lt hx_right) (2 * k) rw [one_pow (2 * k), ← abs_of_nonneg (le_trans hU2 hx_left)] at hincr rw [← abs_of_nonneg (le_trans hU2 hx_left)] at hx_right linarith [f'_bound x (mem_Icc.mpr (abs_le.mp (le_of_lt hx_right)))] have hbound2 : ∀ x ∈ Ico 0 (U : ℝ), |f' x| ≤ U ^ (2 * k) := by rintro x ⟨hx_left, hx_right⟩ - have hincr := pow_le_pow_of_le_left hx_left (le_of_lt hx_right) (2 * k) + have hincr := pow_le_pow_left hx_left (le_of_lt hx_right) (2 * k) rw [← abs_of_nonneg hx_left] at hincr hx_right rw [← abs_of_nonneg hU2] at hU1 hx_right exact (f'_bound x (mem_Icc.mpr (abs_le.mp (le_trans (le_of_lt hx_right) hU1)))).trans hincr diff --git a/Mathlib/FieldTheory/Finite/Basic.lean b/Mathlib/FieldTheory/Finite/Basic.lean index f94c126b11920..e7f3b3f42fee4 100644 --- a/Mathlib/FieldTheory/Finite/Basic.lean +++ b/Mathlib/FieldTheory/Finite/Basic.lean @@ -339,7 +339,7 @@ set_option linter.uppercaseLean3 false in theorem X_pow_card_pow_sub_X_natDegree_eq (hn : n ≠ 0) (hp : 1 < p) : (X ^ p ^ n - X : K'[X]).natDegree = p ^ n := - X_pow_card_sub_X_natDegree_eq K' <| Nat.one_lt_pow _ _ (Nat.pos_of_ne_zero hn) hp + X_pow_card_sub_X_natDegree_eq K' <| Nat.one_lt_pow _ _ hn hp set_option linter.uppercaseLean3 false in #align finite_field.X_pow_card_pow_sub_X_nat_degree_eq FiniteField.X_pow_card_pow_sub_X_natDegree_eq @@ -352,7 +352,7 @@ set_option linter.uppercaseLean3 false in #align finite_field.X_pow_card_sub_X_ne_zero FiniteField.X_pow_card_sub_X_ne_zero theorem X_pow_card_pow_sub_X_ne_zero (hn : n ≠ 0) (hp : 1 < p) : (X ^ p ^ n - X : K'[X]) ≠ 0 := - X_pow_card_sub_X_ne_zero K' <| Nat.one_lt_pow _ _ (Nat.pos_of_ne_zero hn) hp + X_pow_card_sub_X_ne_zero K' <| Nat.one_lt_pow _ _ hn hp set_option linter.uppercaseLean3 false in #align finite_field.X_pow_card_pow_sub_X_ne_zero FiniteField.X_pow_card_pow_sub_X_ne_zero diff --git a/Mathlib/FieldTheory/Finite/Polynomial.lean b/Mathlib/FieldTheory/Finite/Polynomial.lean index a10cbb36711a9..ce36f4958ce28 100644 --- a/Mathlib/FieldTheory/Finite/Polynomial.lean +++ b/Mathlib/FieldTheory/Finite/Polynomial.lean @@ -82,7 +82,7 @@ theorem degrees_indicator (c : σ → K) : refine' le_trans (degrees_prod _ _) (Finset.sum_le_sum fun s _ => _) refine' le_trans (degrees_sub _ _) _ rw [degrees_one, ← bot_eq_zero, bot_sup_eq] - refine' le_trans (degrees_pow _ _) (nsmul_le_nsmul_of_le_right _ _) + refine' le_trans (degrees_pow _ _) (nsmul_le_nsmul_right _ _) refine' le_trans (degrees_sub _ _) _ rw [degrees_C, ← bot_eq_zero, sup_bot_eq] exact degrees_X' _ diff --git a/Mathlib/GroupTheory/Archimedean.lean b/Mathlib/GroupTheory/Archimedean.lean index ac56be53d793d..9f6b570acc6c2 100644 --- a/Mathlib/GroupTheory/Archimedean.lean +++ b/Mathlib/GroupTheory/Archimedean.lean @@ -81,7 +81,7 @@ theorem AddSubgroup.exists_isLeast_pos {H : AddSubgroup G} (hbot : H ≠ ⊥) {a · exact hmin m hmn ⟨y, hyH, hm⟩ · refine disjoint_left.1 hd (sub_mem hxH hyH) ⟨sub_pos.2 hxy, sub_lt_iff_lt_add'.2 ?_⟩ calc x ≤ (n + 1) • a := hxn - _ ≤ (m + 1) • a := nsmul_le_nsmul h₀.le (add_le_add_right hnm _) + _ ≤ (m + 1) • a := nsmul_le_nsmul_left h₀.le (add_le_add_right hnm _) _ = m • a + a := succ_nsmul' _ _ _ < y + a := add_lt_add_right hm.1 _ diff --git a/Mathlib/GroupTheory/Schreier.lean b/Mathlib/GroupTheory/Schreier.lean index e066b6ab84ca0..ec755ac9c39ce 100644 --- a/Mathlib/GroupTheory/Schreier.lean +++ b/Mathlib/GroupTheory/Schreier.lean @@ -196,7 +196,7 @@ theorem card_commutator_le_of_finite_commutatorSet [Finite (commutatorSet G)] : (Nat.pow_le_pow_of_le_right Finite.card_pos (rank_closureCommutatorRepresentatives_le G)) replace h2 := h2.trans (pow_dvd_pow _ (add_le_add_right (mul_le_mul_right' h1 _) 1)) rw [← pow_succ'] at h2 - refine' (Nat.le_of_dvd _ h2).trans (Nat.pow_le_pow_of_le_left h1 _) + refine' (Nat.le_of_dvd _ h2).trans (Nat.pow_le_pow_left h1 _) exact pow_pos (Nat.pos_of_ne_zero FiniteIndex.finiteIndex) _ #align subgroup.card_commutator_le_of_finite_commutator_set Subgroup.card_commutator_le_of_finite_commutatorSet diff --git a/Mathlib/LinearAlgebra/AdicCompletion.lean b/Mathlib/LinearAlgebra/AdicCompletion.lean index 03809a972c51d..0de18c42ca6a3 100644 --- a/Mathlib/LinearAlgebra/AdicCompletion.lean +++ b/Mathlib/LinearAlgebra/AdicCompletion.lean @@ -90,7 +90,7 @@ In fact, this is only complete if the ideal is finitely generated. -/ def adicCompletion : Submodule R (∀ n : ℕ, M ⧸ (I ^ n • ⊤ : Submodule R M)) where carrier := { f | ∀ {m n} (h : m ≤ n), liftQ _ (mkQ _) (by rw [ker_mkQ] - exact smul_mono (Ideal.pow_le_pow h) le_rfl) + exact smul_mono (Ideal.pow_le_pow_right h) le_rfl) (f n) = f m } zero_mem' hmn := by rw [Pi.zero_apply, Pi.zero_apply, LinearMap.map_zero] add_mem' hf hg m n hmn := by diff --git a/Mathlib/MeasureTheory/Group/AddCircle.lean b/Mathlib/MeasureTheory/Group/AddCircle.lean index 861b5ac182994..6f2dd41d25695 100644 --- a/Mathlib/MeasureTheory/Group/AddCircle.lean +++ b/Mathlib/MeasureTheory/Group/AddCircle.lean @@ -74,7 +74,7 @@ theorem isAddFundamentalDomain_of_ae_ball (I : Set <| AddCircle T) (u x : AddCir rw [dist_eq_norm, add_sub_cancel, div_mul_eq_div_div, ← add_div, ← add_div, add_self_div_two, div_le_iff' (by positivity : 0 < (n : ℝ)), ← nsmul_eq_mul] refine' (le_add_order_smul_norm_of_isOfFinAddOrder (hu.of_mem_zmultiples hg) hg').trans - (nsmul_le_nsmul (norm_nonneg g) _) + (nsmul_le_nsmul_left (norm_nonneg g) _) exact Nat.le_of_dvd (addOrderOf_pos_iff.mpr hu) (addOrderOf_dvd_of_mem_zmultiples hg) · -- `∀ (g : G), QuasiMeasurePreserving (VAdd.vadd g) volume volume` exact fun g => quasiMeasurePreserving_add_left (G := AddCircle T) volume g diff --git a/Mathlib/MeasureTheory/Integral/PeakFunction.lean b/Mathlib/MeasureTheory/Integral/PeakFunction.lean index 864de31622f76..91450aa3457ae 100644 --- a/Mathlib/MeasureTheory/Integral/PeakFunction.lean +++ b/Mathlib/MeasureTheory/Integral/PeakFunction.lean @@ -252,12 +252,12 @@ theorem tendsto_set_integral_pow_smul_of_unique_maximum_of_isCompact_of_measure_ exact lt_of_le_of_lt (measure_mono (inter_subset_right _ _)) hs.measure_lt_top · exact (I n).mono (inter_subset_right _ _) le_rfl · intro x hx - exact pow_le_pow_of_le_left t'_pos.le (le_of_lt (hv hx)) _ + exact pow_le_pow_left t'_pos.le (le_of_lt (hv hx)) _ _ ≤ ∫ y in s, c y ^ n ∂μ := set_integral_mono_set (I n) (J n) (eventually_of_forall (inter_subset_right _ _)) simp_rw [← div_eq_inv_mul, div_pow, div_div] apply div_le_div (pow_nonneg t_pos n) _ _ B - · exact pow_le_pow_of_le_left (hnc _ hx.1) (ht x hx) _ + · exact pow_le_pow_left (hnc _ hx.1) (ht x hx) _ · apply mul_pos (pow_pos (t_pos.trans_lt tt') _) (ENNReal.toReal_pos (hμ v v_open x₀_v).ne' _) have : μ (v ∩ s) ≤ μ s := measure_mono (inter_subset_right _ _) exact ne_of_lt (lt_of_le_of_lt this hs.measure_lt_top) diff --git a/Mathlib/MeasureTheory/Measure/Hausdorff.lean b/Mathlib/MeasureTheory/Measure/Hausdorff.lean index 9dcee3830bdd6..a01a11bffec8f 100644 --- a/Mathlib/MeasureTheory/Measure/Hausdorff.lean +++ b/Mathlib/MeasureTheory/Measure/Hausdorff.lean @@ -1019,7 +1019,7 @@ theorem hausdorffMeasure_pi_real {ι : Type*} [Fintype ι] : apply Finset.sum_le_sum fun i _ => _ simp only [ENNReal.rpow_nat_cast] intros i _ - exact pow_le_pow_of_le_left' (hn i) _ + exact pow_le_pow_left' (hn i) _ · isBoundedDefault _ = liminf (fun n : ℕ => ∏ i : ι, (⌈((b i : ℝ) - a i) * n⌉₊ : ℝ≥0∞) / n) atTop := by simp only [Finset.card_univ, Nat.cast_prod, one_mul, Fintype.card_fin, Finset.sum_const, diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean index 7b4f47521df6d..60d510360cfc4 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean @@ -193,7 +193,7 @@ theorem addHaar_submodule {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] convert s.sub_mem hym hyn using 1 simp only [sub_smul, neg_sub_neg, add_sub_add_right_eq_sub] have H : c ^ n - c ^ m ≠ 0 := by - simpa only [sub_eq_zero, Ne.def] using (strictAnti_pow cpos cone).injective.ne hmn.symm + simpa only [sub_eq_zero, Ne.def] using (pow_right_strictAnti cpos cone).injective.ne hmn.symm have : x ∈ s := by convert s.smul_mem (c ^ n - c ^ m)⁻¹ A rw [smul_smul, inv_mul_cancel H, one_smul] diff --git a/Mathlib/NumberTheory/Bertrand.lean b/Mathlib/NumberTheory/Bertrand.lean index c7293c44fb0e9..6423b972525a4 100644 --- a/Mathlib/NumberTheory/Bertrand.lean +++ b/Mathlib/NumberTheory/Bertrand.lean @@ -178,13 +178,13 @@ theorem centralBinom_le_of_no_bertrand_prime (n : ℕ) (n_big : 2 < n) · exact pow_factorization_choose_le (mul_pos two_pos n_pos) have : (Finset.Icc 1 (sqrt (2 * n))).card = sqrt (2 * n) := by rw [card_Icc, Nat.add_sub_cancel] rw [Finset.prod_const] - refine' pow_le_pow n2_pos ((Finset.card_le_of_subset fun x hx => _).trans this.le) + refine' pow_le_pow_right n2_pos ((Finset.card_le_of_subset fun x hx => _).trans this.le) obtain ⟨h1, h2⟩ := Finset.mem_filter.1 hx exact Finset.mem_Icc.mpr ⟨(Finset.mem_filter.1 h1).2.one_lt.le, h2⟩ · refine' le_trans _ (primorial_le_4_pow (2 * n / 3)) refine' (Finset.prod_le_prod' fun p hp => (_ : f p ≤ p)).trans _ · obtain ⟨h1, h2⟩ := Finset.mem_filter.1 hp - refine' (pow_le_pow (Finset.mem_filter.1 h1).2.one_lt.le _).trans (pow_one p).le + refine' (pow_le_pow_right (Finset.mem_filter.1 h1).2.one_lt.le _).trans (pow_one p).le exact Nat.factorization_choose_le_one (sqrt_lt'.mp <| not_le.1 h2) refine' Finset.prod_le_prod_of_subset_of_one_le' (Finset.filter_subset _ _) _ exact fun p hp _ => (Finset.mem_filter.1 hp).2.one_lt.le diff --git a/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean b/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean index 814f1a5c0c94a..d8d7ad664d974 100644 --- a/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean +++ b/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean @@ -165,7 +165,7 @@ theorem cardPowDegree_anti_archimedean {x y z : Fq[X]} {a : ℤ} (hxy : cardPowD cardPowDegree_nonzero _ hyz'] have : (1 : ℤ) ≤ Fintype.card Fq := mod_cast (@Fintype.one_lt_card Fq _ _).le simp only [Int.cast_pow, Int.cast_ofNat, le_max_iff] - refine' Or.imp (pow_le_pow this) (pow_le_pow this) _ + refine' Or.imp (pow_le_pow_right this) (pow_le_pow_right this) _ rw [natDegree_le_iff_degree_le, natDegree_le_iff_degree_le, ← le_max_iff, ← degree_eq_natDegree hxy', ← degree_eq_natDegree hyz'] convert degree_add_le (x - y) (y - z) using 2 diff --git a/Mathlib/NumberTheory/ClassNumber/Finite.lean b/Mathlib/NumberTheory/ClassNumber/Finite.lean index 05b7d9e9e45a5..662c91b16e1e0 100644 --- a/Mathlib/NumberTheory/ClassNumber/Finite.lean +++ b/Mathlib/NumberTheory/ClassNumber/Finite.lean @@ -121,7 +121,7 @@ theorem norm_lt {T : Type*} [LinearOrderedRing T] (a : S) {y : T} apply (Int.cast_le.mpr (norm_le abv bS a hy')).trans_lt simp only [Int.cast_mul, Int.cast_pow] apply mul_lt_mul' le_rfl - · exact pow_lt_pow_of_lt_left this (Int.cast_nonneg.mpr y'_nonneg) (Fintype.card_pos_iff.mpr ⟨i⟩) + · exact pow_lt_pow_left this (Int.cast_nonneg.mpr y'_nonneg) (@Fintype.card_ne_zero _ _ ⟨i⟩) · exact pow_nonneg (Int.cast_nonneg.mpr y'_nonneg) _ · exact Int.cast_pos.mpr (normBound_pos abv bS) #align class_group.norm_lt ClassGroup.norm_lt diff --git a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean index 9ef15c8d2cbd4..e8762737fa5d2 100644 --- a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean +++ b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean @@ -447,7 +447,7 @@ theorem sub_one_norm_two {k : ℕ} (hζ : IsPrimitiveRoot ζ (2 ^ k)) (hk : 2 have : 2 < (2 : ℕ+) ^ k := by simp only [← coe_lt_coe, one_coe, pow_coe] nth_rw 1 [← pow_one 2] - exact pow_lt_pow one_lt_two (lt_of_lt_of_le one_lt_two hk) + exact pow_lt_pow_right one_lt_two (lt_of_lt_of_le one_lt_two hk) -- Porting note: `simpa using hirr` was `simp [hirr]`_ replace hirr : Irreducible (cyclotomic ((2 : ℕ+) ^ k : ℕ+) K) := by simpa using hirr -- Porting note: `simpa using hζ` was `simp [hζ]`_ diff --git a/Mathlib/NumberTheory/Divisors.lean b/Mathlib/NumberTheory/Divisors.lean index 9f85d351a8bdd..d628a349a5c8e 100644 --- a/Mathlib/NumberTheory/Divisors.lean +++ b/Mathlib/NumberTheory/Divisors.lean @@ -333,7 +333,7 @@ theorem Prime.properDivisors {p : ℕ} (pp : p.Prime) : properDivisors p = {1} : #align nat.prime.proper_divisors Nat.Prime.properDivisors theorem divisors_prime_pow {p : ℕ} (pp : p.Prime) (k : ℕ) : - divisors (p ^ k) = (Finset.range (k + 1)).map ⟨(p ^ ·), pow_right_injective pp.two_le⟩ := by + divisors (p ^ k) = (Finset.range (k + 1)).map ⟨(p ^ ·), Nat.pow_right_injective pp.two_le⟩ := by ext a rw [mem_divisors_prime_pow pp] simp [Nat.lt_succ, eq_comm] @@ -438,15 +438,15 @@ theorem mem_properDivisors_prime_pow {p : ℕ} (pp : p.Prime) (k : ℕ) {x : ℕ intro a constructor <;> intro h · rcases h with ⟨_h_left, rfl, h_right⟩ - rw [pow_lt_pow_iff pp.one_lt] at h_right + rw [pow_lt_pow_iff_right pp.one_lt] at h_right exact ⟨h_right, by rfl⟩ · rcases h with ⟨h_left, rfl⟩ - rw [pow_lt_pow_iff pp.one_lt] + rw [pow_lt_pow_iff_right pp.one_lt] simp [h_left, le_of_lt] #align nat.mem_proper_divisors_prime_pow Nat.mem_properDivisors_prime_pow theorem properDivisors_prime_pow {p : ℕ} (pp : p.Prime) (k : ℕ) : - properDivisors (p ^ k) = (Finset.range k).map ⟨HPow.hPow p, pow_right_injective pp.two_le⟩ := by + properDivisors (p ^ k) = (Finset.range k).map ⟨(p ^ ·), Nat.pow_right_injective pp.two_le⟩ := by ext a simp only [mem_properDivisors, Nat.isUnit_iff, mem_map, mem_range, Function.Embedding.coeFn_mk, pow_eq] diff --git a/Mathlib/NumberTheory/EulerProduct/Basic.lean b/Mathlib/NumberTheory/EulerProduct/Basic.lean index ea3a17a21c0e8..40aeee76afd65 100644 --- a/Mathlib/NumberTheory/EulerProduct/Basic.lean +++ b/Mathlib/NumberTheory/EulerProduct/Basic.lean @@ -187,7 +187,7 @@ theorem eulerProduct_completely_multiplicative {f : ℕ →*₀ F} (hsum : Summa simp_rw [map_pow] refine (tsum_geometric_of_norm_lt_1 <| summable_geometric_iff_norm_lt_1.mp ?_).symm refine Summable.of_norm ?_ - convert hsum.comp_injective <| pow_right_injective (prime_of_mem_primesBelow hN).one_lt + convert hsum.comp_injective <| Nat.pow_right_injective (prime_of_mem_primesBelow hN).one_lt simp only [norm_pow, Function.comp_apply, map_pow] end CompletelyMultiplicative diff --git a/Mathlib/NumberTheory/FLT/Four.lean b/Mathlib/NumberTheory/FLT/Four.lean index dcc656362a681..f14ef036a5507 100644 --- a/Mathlib/NumberTheory/FLT/Four.lean +++ b/Mathlib/NumberTheory/FLT/Four.lean @@ -101,7 +101,7 @@ theorem coprime_of_minimal {a b c : ℤ} (h : Minimal a b c) : IsCoprime a b := (Fermat42.mul (Int.coe_nat_ne_zero.mpr (Nat.Prime.ne_zero hp))).mpr h.1 apply Nat.le_lt_asymm (h.2 _ _ _ hf) rw [Int.natAbs_mul, lt_mul_iff_one_lt_left, Int.natAbs_pow, Int.natAbs_ofNat] - · exact Nat.one_lt_pow _ _ zero_lt_two (Nat.Prime.one_lt hp) + · exact Nat.one_lt_pow _ _ two_ne_zero (Nat.Prime.one_lt hp) · exact Nat.pos_of_ne_zero (Int.natAbs_ne_zero.2 (ne_zero hf)) #align fermat_42.coprime_of_minimal Fermat42.coprime_of_minimal diff --git a/Mathlib/NumberTheory/FermatPsp.lean b/Mathlib/NumberTheory/FermatPsp.lean index b85301cd8da69..7a2db88a60b5d 100644 --- a/Mathlib/NumberTheory/FermatPsp.lean +++ b/Mathlib/NumberTheory/FermatPsp.lean @@ -133,14 +133,11 @@ theorem fermatPsp_base_one {n : ℕ} (h₁ : 1 < n) (h₂ : ¬n.Prime) : FermatP -- pseudoprimes section HelperLemmas -private theorem pow_gt_exponent {a : ℕ} (b : ℕ) (h : 2 ≤ a) : b < a ^ b := - lt_of_lt_of_le (Nat.lt_two_pow b) <| Nat.pow_le_pow_of_le_left h _ - private theorem a_id_helper {a b : ℕ} (ha : 2 ≤ a) (hb : 2 ≤ b) : 2 ≤ (a ^ b - 1) / (a - 1) := by change 1 < _ have h₁ : a - 1 ∣ a ^ b - 1 := by simpa only [one_pow] using nat_sub_dvd_pow_sub_pow a 1 b rw [Nat.lt_div_iff_mul_lt h₁, mul_one, tsub_lt_tsub_iff_right (Nat.le_of_succ_le ha)] - exact self_lt_pow (Nat.lt_of_succ_le ha) hb + exact lt_self_pow (Nat.lt_of_succ_le ha) hb private theorem b_id_helper {a b : ℕ} (ha : 2 ≤ a) (hb : 2 < b) : 2 ≤ (a ^ b + 1) / (a + 1) := by rw [Nat.le_div_iff_mul_le (Nat.zero_lt_succ _)] @@ -148,7 +145,7 @@ private theorem b_id_helper {a b : ℕ} (ha : 2 ≤ a) (hb : 2 < b) : 2 ≤ (a ^ calc 2 * a + 1 ≤ a ^ 2 * a := by nlinarith _ = a ^ 3 := by rw [pow_succ a 2] - _ ≤ a ^ b := pow_le_pow (Nat.le_of_succ_le ha) hb + _ ≤ a ^ b := pow_le_pow_right (Nat.le_of_succ_le ha) hb private theorem AB_id_helper (b p : ℕ) (_ : 2 ≤ b) (hp : Odd p) : (b ^ p - 1) / (b - 1) * ((b ^ p + 1) / (b + 1)) = (b ^ (2 * p) - 1) / (b ^ 2 - 1) := by @@ -331,7 +328,7 @@ private theorem psp_from_prime_gt_p {b : ℕ} (b_ge_two : 2 ≤ b) {p : ℕ} (p_ have : 2 ≤ 2 * p - 2 := le_tsub_of_add_le_left (show 4 ≤ 2 * p by linarith) have : 2 + p ≤ 2 * p := by linarith have : p ≤ 2 * p - 2 := le_tsub_of_add_le_left this - exact Nat.lt_of_le_of_lt this (pow_gt_exponent _ b_ge_two) + exact this.trans_lt (lt_pow_self b_ge_two _) /-- For all positive bases, there exist infinite **Fermat pseudoprimes** to that base. Given in this form: for all numbers `b ≥ 1` and `m`, there exists a pseudoprime `n` to base `b` such @@ -350,7 +347,7 @@ theorem exists_infinite_pseudoprimes {b : ℕ} (h : 1 ≤ b) (m : ℕ) : cases' h with p hp cases' hp with hp₁ hp₂ have h₁ : 0 < b := pos_of_gt (Nat.succ_le_iff.mp b_ge_two) - have h₂ : 4 ≤ b ^ 2 := pow_le_pow_of_le_left' b_ge_two 2 + have h₂ : 4 ≤ b ^ 2 := pow_le_pow_left' b_ge_two 2 have h₃ : 0 < b ^ 2 - 1 := tsub_pos_of_lt (gt_of_ge_of_gt h₂ (by norm_num)) have h₄ : 0 < b * (b ^ 2 - 1) := mul_pos h₁ h₃ have h₅ : b * (b ^ 2 - 1) < p := by linarith diff --git a/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean b/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean index 5669975897223..90e07877c06d7 100644 --- a/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean +++ b/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean @@ -155,7 +155,7 @@ theorem aux_calc (n : ℕ) {m : ℝ} (hm : 2 ≤ m) : any_goals exact pow_pos (zero_lt_two.trans_le hm) _ -- `2 ≤ m ^ n!` is a consequence of monotonicity of exponentiation at `2 ≤ m`. exact _root_.trans (_root_.trans hm (pow_one _).symm.le) - (pow_mono (one_le_two.trans hm) n.factorial_pos) + (pow_right_mono (one_le_two.trans hm) n.factorial_pos) _ = 1 / (m ^ n !) ^ n := congr_arg (1 / ·) (pow_mul m n ! n) #align liouville_number.aux_calc LiouvilleNumber.aux_calc diff --git a/Mathlib/NumberTheory/LucasLehmer.lean b/Mathlib/NumberTheory/LucasLehmer.lean index 0d162b815dea4..23d293c6403cf 100644 --- a/Mathlib/NumberTheory/LucasLehmer.lean +++ b/Mathlib/NumberTheory/LucasLehmer.lean @@ -53,7 +53,7 @@ theorem mersenne_pos {p : ℕ} (h : 0 < p) : 0 < mersenne p := by theorem one_lt_mersenne {p : ℕ} (hp : 1 < p) : 1 < mersenne p := lt_tsub_iff_right.2 <| calc 1 + 1 = 2 ^ 1 := by rw [one_add_one_eq_two, pow_one] - _ < 2 ^ p := Nat.pow_lt_pow_of_lt_right one_lt_two hp + _ < 2 ^ p := pow_lt_pow_right one_lt_two hp @[simp] theorem succ_mersenne (k : ℕ) : mersenne k + 1 = 2 ^ k := by @@ -94,27 +94,27 @@ def sMod (p : ℕ) : ℕ → ℤ | i + 1 => (sMod p i ^ 2 - 2) % (2 ^ p - 1) #align lucas_lehmer.s_mod LucasLehmer.sMod -theorem mersenne_int_pos {p : ℕ} (hp : 0 < p) : (0 : ℤ) < 2 ^ p - 1 := +theorem mersenne_int_pos {p : ℕ} (hp : p ≠ 0) : (0 : ℤ) < 2 ^ p - 1 := sub_pos.2 <| mod_cast Nat.one_lt_two_pow p hp -theorem mersenne_int_ne_zero (p : ℕ) (w : 0 < p) : (2 ^ p - 1 : ℤ) ≠ 0 := - (mersenne_int_pos w).ne' +theorem mersenne_int_ne_zero (p : ℕ) (hp : p ≠ 0) : (2 ^ p - 1 : ℤ) ≠ 0 := + (mersenne_int_pos hp).ne' #align lucas_lehmer.mersenne_int_ne_zero LucasLehmer.mersenne_int_ne_zero -theorem sMod_nonneg (p : ℕ) (w : 0 < p) (i : ℕ) : 0 ≤ sMod p i := by +theorem sMod_nonneg (p : ℕ) (hp : p ≠ 0) (i : ℕ) : 0 ≤ sMod p i := by cases i <;> dsimp [sMod] · exact sup_eq_right.mp rfl · apply Int.emod_nonneg - exact mersenne_int_ne_zero p w + exact mersenne_int_ne_zero p hp #align lucas_lehmer.s_mod_nonneg LucasLehmer.sMod_nonneg theorem sMod_mod (p i : ℕ) : sMod p i % (2 ^ p - 1) = sMod p i := by cases i <;> simp [sMod] #align lucas_lehmer.s_mod_mod LucasLehmer.sMod_mod -theorem sMod_lt (p : ℕ) (w : 0 < p) (i : ℕ) : sMod p i < 2 ^ p - 1 := by +theorem sMod_lt (p : ℕ) (hp : p ≠ 0) (i : ℕ) : sMod p i < 2 ^ p - 1 := by rw [← sMod_mod] - refine (Int.emod_lt _ (mersenne_int_ne_zero p w)).trans_eq ?_ - exact abs_of_nonneg (mersenne_int_pos w).le + refine (Int.emod_lt _ (mersenne_int_ne_zero p hp)).trans_eq ?_ + exact abs_of_nonneg (mersenne_int_pos hp).le #align lucas_lehmer.s_mod_lt LucasLehmer.sMod_lt theorem sZMod_eq_s (p' : ℕ) (i : ℕ) : sZMod (p' + 2) i = (s i : ZMod (2 ^ (p' + 2) - 1)) := by @@ -155,8 +155,8 @@ theorem residue_eq_zero_iff_sMod_eq_zero (p : ℕ) (w : 1 < p) : simp only [ge_iff_le, ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, pow_pos, cast_pred, cast_pow, cast_ofNat] at h apply Int.eq_zero_of_dvd_of_nonneg_of_lt _ _ h <;> clear h - · apply sMod_nonneg _ (Nat.lt_of_succ_lt w) - · exact sMod_lt _ (Nat.lt_of_succ_lt w) (p - 2) + · exact sMod_nonneg _ (by positivity) _ + · exact sMod_lt _ (by positivity) _ · intro h rw [h] simp diff --git a/Mathlib/NumberTheory/Multiplicity.lean b/Mathlib/NumberTheory/Multiplicity.lean index 022dc93070d8c..97ce4daa73e39 100644 --- a/Mathlib/NumberTheory/Multiplicity.lean +++ b/Mathlib/NumberTheory/Multiplicity.lean @@ -228,13 +228,13 @@ theorem Nat.pow_sub_pow {x y : ℕ} (hxy : p ∣ x - y) (hx : ¬p ∣ x) (n : multiplicity p (x ^ n - y ^ n) = multiplicity p (x - y) + multiplicity p n := by obtain hyx | hyx := le_total y x · iterate 2 rw [← Int.coe_nat_multiplicity] - rw [Int.ofNat_sub (Nat.pow_le_pow_of_le_left hyx n)] + rw [Int.ofNat_sub (Nat.pow_le_pow_left hyx n)] rw [← Int.coe_nat_dvd] at hxy hx rw [Int.coe_nat_sub hyx] at * push_cast at * exact Int.pow_sub_pow hp hp1 hxy hx n · simp only [Nat.sub_eq_zero_iff_le.mpr hyx, - Nat.sub_eq_zero_iff_le.mpr (Nat.pow_le_pow_of_le_left hyx n), multiplicity.zero, + Nat.sub_eq_zero_iff_le.mpr (Nat.pow_le_pow_left hyx n), multiplicity.zero, PartENat.top_add] #align multiplicity.nat.pow_sub_pow multiplicity.Nat.pow_sub_pow @@ -362,7 +362,7 @@ theorem Nat.two_pow_sub_pow {x y : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 ∣ x) {n multiplicity 2 (x + y) + multiplicity 2 (x - y) + multiplicity 2 n := by obtain hyx | hyx := le_total y x · iterate 3 rw [← multiplicity.Int.coe_nat_multiplicity] - simp only [Int.ofNat_sub hyx, Int.ofNat_sub (pow_le_pow_of_le_left' hyx _), Int.ofNat_add, + simp only [Int.ofNat_sub hyx, Int.ofNat_sub (pow_le_pow_left' hyx _), Int.ofNat_add, Int.coe_nat_pow] rw [← Int.coe_nat_dvd] at hx rw [← Int.coe_nat_dvd, Int.ofNat_sub hyx] at hxy @@ -370,7 +370,7 @@ theorem Nat.two_pow_sub_pow {x y : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 ∣ x) {n rw [← multiplicity.Int.coe_nat_multiplicity] rfl · simp only [Nat.sub_eq_zero_iff_le.mpr hyx, - Nat.sub_eq_zero_iff_le.mpr (pow_le_pow_of_le_left' hyx n), multiplicity.zero, + Nat.sub_eq_zero_iff_le.mpr (pow_le_pow_left' hyx n), multiplicity.zero, PartENat.top_add, PartENat.add_top] #align nat.two_pow_sub_pow Nat.two_pow_sub_pow @@ -378,29 +378,29 @@ namespace padicValNat variable {x y : ℕ} -theorem pow_two_sub_pow (hyx : y < x) (hxy : 2 ∣ x - y) (hx : ¬2 ∣ x) {n : ℕ} (hn : 0 < n) +theorem pow_two_sub_pow (hyx : y < x) (hxy : 2 ∣ x - y) (hx : ¬2 ∣ x) {n : ℕ} (hn : n ≠ 0) (hneven : Even n) : padicValNat 2 (x ^ n - y ^ n) + 1 = padicValNat 2 (x + y) + padicValNat 2 (x - y) + padicValNat 2 n := by simp only [← PartENat.natCast_inj, Nat.cast_add] iterate 4 rw [padicValNat_def, PartENat.natCast_get] · convert Nat.two_pow_sub_pow hxy hx hneven using 2 - · exact hn + · exact hn.bot_lt · exact Nat.sub_pos_of_lt hyx · linarith - · simp only [tsub_pos_iff_lt, pow_lt_pow_of_lt_left hyx (@zero_le' _ y _) hn] + · simp only [tsub_pos_iff_lt, pow_lt_pow_left hyx zero_le' hn] #align padic_val_nat.pow_two_sub_pow padicValNat.pow_two_sub_pow variable {p : ℕ} [hp : Fact p.Prime] (hp1 : Odd p) -theorem pow_sub_pow (hyx : y < x) (hxy : p ∣ x - y) (hx : ¬p ∣ x) {n : ℕ} (hn : 0 < n) : +theorem pow_sub_pow (hyx : y < x) (hxy : p ∣ x - y) (hx : ¬p ∣ x) {n : ℕ} (hn : n ≠ 0) : padicValNat p (x ^ n - y ^ n) = padicValNat p (x - y) + padicValNat p n := by rw [← PartENat.natCast_inj, Nat.cast_add] iterate 3 rw [padicValNat_def, PartENat.natCast_get] · exact multiplicity.Nat.pow_sub_pow hp.out hp1 hxy hx n - · exact hn + · exact hn.bot_lt · exact Nat.sub_pos_of_lt hyx - · exact Nat.sub_pos_of_lt (Nat.pow_lt_pow_of_lt_left hyx hn) + · exact Nat.sub_pos_of_lt (Nat.pow_lt_pow_left hyx hn) #align padic_val_nat.pow_sub_pow padicValNat.pow_sub_pow theorem pow_add_pow (hxy : p ∣ x + y) (hx : ¬p ∣ x) {n : ℕ} (hn : Odd n) : diff --git a/Mathlib/NumberTheory/NumberField/Discriminant.lean b/Mathlib/NumberTheory/NumberField/Discriminant.lean index cd8f2f3b5d52b..f7ab06d0e7103 100644 --- a/Mathlib/NumberTheory/NumberField/Discriminant.lean +++ b/Mathlib/NumberTheory/NumberField/Discriminant.lean @@ -167,7 +167,7 @@ theorem abs_discr_ge (h : 1 < finrank ℚ K) : suffices ∀ n, 2 ≤ n → (4 / 9 : ℝ) * (3 * π / 4) ^ n ≤ a n by refine le_trans (this (finrank ℚ K) h) ?_ refine div_le_div_of_le_left (by positivity) (by positivity) ?_ - refine mul_le_mul_of_nonneg_right (pow_le_pow ?_ ?_) (by positivity) + refine mul_le_mul_of_nonneg_right (pow_le_pow_right ?_ ?_) (by positivity) · rw [_root_.le_div_iff Real.pi_pos, one_mul] exact Real.pi_le_four · rw [← card_add_two_mul_card_eq_rank, mul_comm] @@ -197,7 +197,7 @@ theorem discr_gt_one (h : 1 < finrank ℚ K) : 2 < |discr K| := by exact Real.pi_gt_three refine Int.cast_lt.mp <| lt_of_lt_of_le ?_ (abs_discr_ge h) rw [← _root_.div_lt_iff' (by positivity), Int.int_cast_ofNat] - refine lt_of_lt_of_le ?_ (pow_le_pow (n := 2) h₁ h) + refine lt_of_lt_of_le ?_ (pow_le_pow_right (n := 2) h₁ h) rw [div_pow, _root_.lt_div_iff (by norm_num), mul_pow] norm_num rw [ ← _root_.div_lt_iff' (by positivity), show (72:ℝ) / 9 = 8 by norm_num] diff --git a/Mathlib/NumberTheory/NumberField/Units.lean b/Mathlib/NumberTheory/NumberField/Units.lean index afa71267c9089..e60329ec1eeb2 100644 --- a/Mathlib/NumberTheory/NumberField/Units.lean +++ b/Mathlib/NumberTheory/NumberField/Units.lean @@ -334,7 +334,7 @@ theorem seq_next {x : 𝓞 K} (hx : x ≠ 0) : _ ≤ ∏ w : InfinitePlace K, (g w : ℝ) ^ mult w := by refine prod_le_prod ?_ ?_ · exact fun _ _ => pow_nonneg (by positivity) _ - · exact fun w _ => pow_le_pow_of_le_left (by positivity) (le_of_lt (h_yle w)) (mult w) + · exact fun w _ => pow_le_pow_left (by positivity) (le_of_lt (h_yle w)) (mult w) _ ≤ (B : ℝ) := by simp_rw [← NNReal.coe_pow, ← NNReal.coe_prod] exact le_of_eq (congr_arg toReal h_gprod) diff --git a/Mathlib/NumberTheory/Padics/Hensel.lean b/Mathlib/NumberTheory/Padics/Hensel.lean index bb4b424e11a41..7cb36d60c312d 100644 --- a/Mathlib/NumberTheory/Padics/Hensel.lean +++ b/Mathlib/NumberTheory/Padics/Hensel.lean @@ -279,7 +279,7 @@ private theorem T_pos : T > 0 := by private theorem newton_seq_succ_dist_weak (n : ℕ) : ‖newton_seq (n + 2) - newton_seq (n + 1)‖ < ‖F.eval a‖ / ‖F.derivative.eval a‖ := have : 2 ≤ 2 ^ (n + 1) := by - have := pow_le_pow (by norm_num : 1 ≤ 2) (Nat.le_add_left _ _ : 1 ≤ n + 1) + have := pow_le_pow_right (by norm_num : 1 ≤ 2) (Nat.le_add_left _ _ : 1 ≤ n + 1) simpa using this calc ‖newton_seq (n + 2) - newton_seq (n + 1)‖ ≤ ‖F.derivative.eval a‖ * T ^ 2 ^ (n + 1) := @@ -288,7 +288,7 @@ private theorem newton_seq_succ_dist_weak (n : ℕ) : (mul_le_mul_of_nonneg_left (pow_le_pow_of_le_one (norm_nonneg _) (le_of_lt (T_lt_one hnorm)) this) (norm_nonneg _)) _ < ‖F.derivative.eval a‖ * T ^ 1 := - (mul_lt_mul_of_pos_left (pow_lt_pow_of_lt_one (T_pos hnorm hnsol) + (mul_lt_mul_of_pos_left (pow_lt_pow_right_of_lt_one (T_pos hnorm hnsol) (T_lt_one hnorm) (by norm_num)) (deriv_norm_pos hnorm)) _ = ‖F.eval a‖ / ‖F.derivative.eval a‖ := by rw [T_gen, sq, pow_one, norm_div, ← mul_div_assoc, PadicInt.padic_norm_e_of_padicInt, @@ -301,7 +301,7 @@ private theorem newton_seq_dist_aux (n : ℕ) : | 0 => by simp [T_pow_nonneg, mul_nonneg] | k + 1 => have : 2 ^ n ≤ 2 ^ (n + k) := by - apply pow_le_pow + apply pow_le_pow_right norm_num apply Nat.le_add_right calc diff --git a/Mathlib/NumberTheory/Padics/PadicIntegers.lean b/Mathlib/NumberTheory/Padics/PadicIntegers.lean index 93deff94a45b4..55d1d44380bdb 100644 --- a/Mathlib/NumberTheory/Padics/PadicIntegers.lean +++ b/Mathlib/NumberTheory/Padics/PadicIntegers.lean @@ -520,7 +520,7 @@ theorem norm_le_pow_iff_le_valuation (x : ℤ_[p]) (hx : x ≠ 0) (n : ℕ) : refine pow_pos ?_ m exact mod_cast hp.1.pos rw [inv_le_inv (aux _) (aux _)] - have : p ^ n ≤ p ^ k ↔ n ≤ k := (pow_strictMono_right hp.1.one_lt).le_iff_le + have : p ^ n ≤ p ^ k ↔ n ≤ k := (pow_right_strictMono hp.1.one_lt).le_iff_le rw [← this] norm_cast #align padic_int.norm_le_pow_iff_le_valuation PadicInt.norm_le_pow_iff_le_valuation diff --git a/Mathlib/NumberTheory/Padics/PadicVal.lean b/Mathlib/NumberTheory/Padics/PadicVal.lean index f953bec7900da..30ff28630323b 100644 --- a/Mathlib/NumberTheory/Padics/PadicVal.lean +++ b/Mathlib/NumberTheory/Padics/PadicVal.lean @@ -640,7 +640,7 @@ theorem range_pow_padicValNat_subset_divisors' {n : ℕ} [hp : Fact p.Prime] : obtain ⟨k, hk, rfl⟩ := ht rw [Finset.mem_erase, Nat.mem_divisors] refine' ⟨_, (pow_dvd_pow p <| succ_le_iff.2 hk).trans pow_padicValNat_dvd, hn⟩ - exact (Nat.one_lt_pow _ _ k.succ_pos hp.out.one_lt).ne' + exact (Nat.one_lt_pow _ _ k.succ_ne_zero hp.out.one_lt).ne' #align range_pow_padic_val_nat_subset_divisors' range_pow_padicValNat_subset_divisors' /-- The `p`-adic valuation of `(p * n)!` is `n` more than that of `n!`. -/ diff --git a/Mathlib/NumberTheory/Padics/RingHoms.lean b/Mathlib/NumberTheory/Padics/RingHoms.lean index 3991537649c74..2caefc0436765 100644 --- a/Mathlib/NumberTheory/Padics/RingHoms.lean +++ b/Mathlib/NumberTheory/Padics/RingHoms.lean @@ -310,7 +310,7 @@ theorem appr_lt (x : ℤ_[p]) (n : ℕ) : x.appr n < p ^ n := by induction' n with n ih generalizing x · simp only [appr, zero_eq, _root_.pow_zero, zero_lt_one] simp only [appr, map_natCast, ZMod.nat_cast_self, RingHom.map_pow, Int.natAbs, RingHom.map_mul] - have hp : p ^ n < p ^ (n + 1) := by apply pow_lt_pow hp_prime.1.one_lt (lt_add_one n) + have hp : p ^ n < p ^ (n + 1) := by apply pow_lt_pow_right hp_prime.1.one_lt (lt_add_one n) split_ifs with h · apply lt_trans (ih _) hp · calc diff --git a/Mathlib/NumberTheory/PellMatiyasevic.lean b/Mathlib/NumberTheory/PellMatiyasevic.lean index 1215ab257c134..61f8b6204c7d1 100644 --- a/Mathlib/NumberTheory/PellMatiyasevic.lean +++ b/Mathlib/NumberTheory/PellMatiyasevic.lean @@ -965,7 +965,7 @@ theorem eq_pow_of_pell {m n k} : refine' eq_pow_of_pell_lem hn.ne' hk.ne' _ calc n ^ k ≤ n ^ w := Nat.pow_le_pow_of_le_right hn kw - _ < (w + 1) ^ w := (Nat.pow_lt_pow_of_lt_left (Nat.lt_succ_of_le nw) wpos) + _ < (w + 1) ^ w := (Nat.pow_lt_pow_left (Nat.lt_succ_of_le nw) wpos.ne') _ ≤ a := xn_ge_a_pow w1 w lift (2 * a * n - n * n - 1 : ℤ) to ℕ using (Nat.cast_nonneg _).trans nt.le with t te have tm : x ≡ y * (a - n) + n ^ k [MOD t] := by @@ -995,7 +995,7 @@ theorem eq_pow_of_pell {m n k} : have hnka : n ^ k < xn hw1 j calc n ^ k ≤ n ^ j := Nat.pow_le_pow_of_le_right hn0 (le_trans kw wj) - _ < (w + 1) ^ j := (Nat.pow_lt_pow_of_lt_left (Nat.lt_succ_of_le nw) hj0) + _ < (w + 1) ^ j := (Nat.pow_lt_pow_left (Nat.lt_succ_of_le nw) hj0.ne') _ ≤ xn hw1 j := xn_ge_a_pow hw1 j have nt : (↑(n ^ k) : ℤ) < 2 * xn hw1 j * n - n * n - 1 := eq_pow_of_pell_lem hn0.ne' hk0.ne' hnka diff --git a/Mathlib/NumberTheory/RamificationInertia.lean b/Mathlib/NumberTheory/RamificationInertia.lean index 07c91a0fa56c1..3f5f11f09d59b 100644 --- a/Mathlib/NumberTheory/RamificationInertia.lean +++ b/Mathlib/NumberTheory/RamificationInertia.lean @@ -88,7 +88,7 @@ theorem ramificationIdx_spec {n : ℕ} (hle : map f p ≤ P ^ n) (hgt : ¬map f have : Q n := by intro k hk refine le_of_not_lt fun hnk => ?_ - exact hgt (hk.trans (Ideal.pow_le_pow hnk)) + exact hgt (hk.trans (Ideal.pow_le_pow_right hnk)) rw [ramificationIdx_eq_find ⟨n, this⟩] refine le_antisymm (Nat.find_min' _ this) (le_of_not_gt fun h : Nat.find _ < n => ?_) obtain this' := Nat.find_spec ⟨n, this⟩ @@ -101,7 +101,7 @@ theorem ramificationIdx_lt {n : ℕ} (hgt : ¬map f p ≤ P ^ n) : ramificationI · rw [Nat.lt_succ_iff] have : ∀ k, map f p ≤ P ^ k → k ≤ n := by refine fun k hk => le_of_not_lt fun hnk => ?_ - exact hgt (hk.trans (Ideal.pow_le_pow hnk)) + exact hgt (hk.trans (Ideal.pow_le_pow_right hnk)) rw [ramificationIdx_eq_find ⟨n, this⟩] exact Nat.find_min' ⟨n, this⟩ this #align ideal.ramification_idx_lt Ideal.ramificationIdx_lt @@ -486,7 +486,7 @@ theorem Quotient.algebraMap_quotient_of_ramificationIdx_neZero (x : R) : def powQuotSuccInclusion (i : ℕ) : Ideal.map (Ideal.Quotient.mk (P ^ e)) (P ^ (i + 1)) →ₗ[R ⧸ p] Ideal.map (Ideal.Quotient.mk (P ^ e)) (P ^ i) where - toFun x := ⟨x, Ideal.map_mono (Ideal.pow_le_pow i.le_succ) x.2⟩ + toFun x := ⟨x, Ideal.map_mono (Ideal.pow_le_pow_right i.le_succ) x.2⟩ map_add' _ _ := rfl map_smul' _ _ := rfl #align ideal.pow_quot_succ_inclusion Ideal.powQuotSuccInclusion @@ -553,7 +553,7 @@ theorem quotientToQuotientRangePowQuotSucc_injective [IsDomain S] [IsDedekindDom Function.Injective (quotientToQuotientRangePowQuotSucc f p P a_mem) := fun x => Quotient.inductionOn' x fun x y => Quotient.inductionOn' y fun y h => by - have Pe_le_Pi1 : P ^ e ≤ P ^ (i + 1) := Ideal.pow_le_pow hi + have Pe_le_Pi1 : P ^ e ≤ P ^ (i + 1) := Ideal.pow_le_pow_right hi simp only [Submodule.Quotient.mk''_eq_mk, quotientToQuotientRangePowQuotSucc_mk, Submodule.Quotient.eq, LinearMap.mem_range, Subtype.ext_iff, Subtype.coe_mk, Submodule.coe_sub] at h ⊢ @@ -573,7 +573,7 @@ theorem quotientToQuotientRangePowQuotSucc_surjective [IsDomain S] [IsDedekindDo (a_not_mem : a ∉ P ^ (i + 1)) : Function.Surjective (quotientToQuotientRangePowQuotSucc f p P a_mem) := by rintro ⟨⟨⟨x⟩, hx⟩⟩ - have Pe_le_Pi : P ^ e ≤ P ^ i := Ideal.pow_le_pow hi.le + have Pe_le_Pi : P ^ e ≤ P ^ i := Ideal.pow_le_pow_right hi.le rw [Submodule.Quotient.quot_mk_eq_mk, Ideal.Quotient.mk_eq_mk, Ideal.mem_quotient_iff_mem_sup, sup_eq_left.mpr Pe_le_Pi] at hx suffices hx' : x ∈ Ideal.span {a} ⊔ P ^ (i + 1) @@ -606,7 +606,7 @@ noncomputable def quotientRangePowQuotSuccInclusionEquiv [IsDomain S] [IsDedekin ≃ₗ[R ⧸ p] S ⧸ P := by choose a a_mem a_not_mem using SetLike.exists_of_lt - (Ideal.strictAnti_pow P hP (Ideal.IsPrime.ne_top inferInstance) (le_refl i.succ)) + (Ideal.pow_right_strictAnti P hP (Ideal.IsPrime.ne_top inferInstance) (le_refl i.succ)) refine' (LinearEquiv.ofBijective _ ⟨_, _⟩).symm · exact quotientToQuotientRangePowQuotSucc f p P a_mem · exact quotientToQuotientRangePowQuotSucc_injective f p P hi a_mem a_not_mem diff --git a/Mathlib/NumberTheory/SumFourSquares.lean b/Mathlib/NumberTheory/SumFourSquares.lean index 442a3ed8f7aad..1dc0944b7b3c9 100644 --- a/Mathlib/NumberTheory/SumFourSquares.lean +++ b/Mathlib/NumberTheory/SumFourSquares.lean @@ -71,7 +71,7 @@ theorem lt_of_sum_four_squares_eq_mul {a b c d k m : ℕ} 2 ^ 2 * (k * ↑m) = ∑ i : Fin 4, (2 * ![a, b, c, d] i) ^ 2 := by simp [← h, Fin.sum_univ_succ, mul_add, mul_pow, add_assoc] _ < ∑ _i : Fin 4, m ^ 2 := Finset.sum_lt_sum_of_nonempty Finset.univ_nonempty fun i _ ↦ by - refine pow_lt_pow_of_lt_left ?_ (zero_le _) two_pos + refine pow_lt_pow_left ?_ (zero_le _) two_ne_zero fin_cases i <;> assumption _ = 2 ^ 2 * (m * m) := by simp; ring diff --git a/Mathlib/Order/Filter/Archimedean.lean b/Mathlib/Order/Filter/Archimedean.lean index 7039000f2e27a..2a77bbd6d33c2 100644 --- a/Mathlib/Order/Filter/Archimedean.lean +++ b/Mathlib/Order/Filter/Archimedean.lean @@ -226,7 +226,7 @@ theorem Tendsto.atTop_nsmul_const {f : α → ℕ} (hr : 0 < r) (hf : Tendsto f Tendsto (fun x => f x • r) l atTop := by refine' tendsto_atTop.mpr fun s => _ obtain ⟨n : ℕ, hn : s ≤ n • r⟩ := Archimedean.arch s hr - exact (tendsto_atTop.mp hf n).mono fun a ha => hn.trans (nsmul_le_nsmul hr.le ha) + exact (tendsto_atTop.mp hf n).mono fun a ha => hn.trans (nsmul_le_nsmul_left hr.le ha) #align filter.tendsto.at_top_nsmul_const Filter.Tendsto.atTop_nsmul_const end LinearOrderedCancelAddCommMonoid diff --git a/Mathlib/Order/Filter/AtTopBot.lean b/Mathlib/Order/Filter/AtTopBot.lean index 85cad5e9e9889..ed455c726dda7 100644 --- a/Mathlib/Order/Filter/AtTopBot.lean +++ b/Mathlib/Order/Filter/AtTopBot.lean @@ -721,7 +721,7 @@ theorem Tendsto.nsmul_atTop (hf : Tendsto f l atTop) {n : ℕ} (hn : 0 < n) : calc y ≤ f x := hy _ = 1 • f x := (one_nsmul _).symm - _ ≤ n • f x := nsmul_le_nsmul h₀ hn + _ ≤ n • f x := nsmul_le_nsmul_left h₀ hn #align filter.tendsto.nsmul_at_top Filter.Tendsto.nsmul_atTop theorem Tendsto.nsmul_atBot (hf : Tendsto f l atBot) {n : ℕ} (hn : 0 < n) : diff --git a/Mathlib/Probability/StrongLaw.lean b/Mathlib/Probability/StrongLaw.lean index 2cd01ce9b2b7b..ef94f9d48f0e0 100644 --- a/Mathlib/Probability/StrongLaw.lean +++ b/Mathlib/Probability/StrongLaw.lean @@ -431,7 +431,7 @@ theorem strong_law_aux1 {c : ℝ} (c_one : 1 < c) {ε : ℝ} (εpos : 0 < ε) : set Y := fun n : ℕ => truncation (X n) n set S := fun n => ∑ i in range n, Y i with hS let u : ℕ → ℕ := fun n => ⌊c ^ n⌋₊ - have u_mono : Monotone u := fun i j hij => Nat.floor_mono (pow_le_pow c_one.le hij) + have u_mono : Monotone u := fun i j hij => Nat.floor_mono (pow_le_pow_right c_one.le hij) have I1 : ∀ K, ∑ j in range K, ((j : ℝ) ^ 2)⁻¹ * Var[Y j] ≤ 2 * 𝔼[X 0] := by intro K calc diff --git a/Mathlib/RingTheory/Artinian.lean b/Mathlib/RingTheory/Artinian.lean index f4bc31b001c3d..45ecbf69526b7 100644 --- a/Mathlib/RingTheory/Artinian.lean +++ b/Mathlib/RingTheory/Artinian.lean @@ -427,7 +427,7 @@ variable {R : Type*} [CommRing R] [IsArtinianRing R] theorem isNilpotent_jacobson_bot : IsNilpotent (Ideal.jacobson (⊥ : Ideal R)) := by let Jac := Ideal.jacobson (⊥ : Ideal R) - let f : ℕ →o (Ideal R)ᵒᵈ := ⟨fun n => Jac ^ n, fun _ _ h => Ideal.pow_le_pow h⟩ + let f : ℕ →o (Ideal R)ᵒᵈ := ⟨fun n => Jac ^ n, fun _ _ h => Ideal.pow_le_pow_right h⟩ obtain ⟨n, hn⟩ : ∃ n, ∀ m, n ≤ m → Jac ^ n = Jac ^ m := IsArtinian.monotone_stabilizes f refine' ⟨n, _⟩ let J : Ideal R := annihilator (Jac ^ n) diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 3a57a5a969bc0..f17a8d550da72 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -720,22 +720,22 @@ theorem Ideal.isPrime_iff_bot_or_prime {P : Ideal A} : IsPrime P ↔ P = ⊥ ∨ hp.elim (fun h => h.symm ▸ Ideal.bot_prime) Ideal.isPrime_of_prime⟩ #align ideal.is_prime_iff_bot_or_prime Ideal.isPrime_iff_bot_or_prime -theorem Ideal.strictAnti_pow (I : Ideal A) (hI0 : I ≠ ⊥) (hI1 : I ≠ ⊤) : +theorem Ideal.pow_right_strictAnti (I : Ideal A) (hI0 : I ≠ ⊥) (hI1 : I ≠ ⊤) : StrictAnti (I ^ · : ℕ → Ideal A) := strictAnti_nat_of_succ_lt fun e => Ideal.dvdNotUnit_iff_lt.mp ⟨pow_ne_zero _ hI0, I, mt isUnit_iff.mp hI1, pow_succ' I e⟩ -#align ideal.strict_anti_pow Ideal.strictAnti_pow +#align ideal.strict_anti_pow Ideal.pow_right_strictAnti theorem Ideal.pow_lt_self (I : Ideal A) (hI0 : I ≠ ⊥) (hI1 : I ≠ ⊤) (e : ℕ) (he : 2 ≤ e) : I ^ e < I := by - convert I.strictAnti_pow hI0 hI1 he + convert I.pow_right_strictAnti hI0 hI1 he dsimp only rw [pow_one] #align ideal.pow_lt_self Ideal.pow_lt_self theorem Ideal.exists_mem_pow_not_mem_pow_succ (I : Ideal A) (hI0 : I ≠ ⊥) (hI1 : I ≠ ⊤) (e : ℕ) : ∃ x ∈ I ^ e, x ∉ I ^ (e + 1) := - SetLike.exists_of_lt (I.strictAnti_pow hI0 hI1 e.lt_succ_self) + SetLike.exists_of_lt (I.pow_right_strictAnti hI0 hI1 e.lt_succ_self) #align ideal.exists_mem_pow_not_mem_pow_succ Ideal.exists_mem_pow_not_mem_pow_succ open UniqueFactorizationMonoid @@ -758,7 +758,7 @@ theorem Ideal.eq_prime_pow_of_succ_lt_of_le {P I : Ideal A} [P_prime : P.IsPrime theorem Ideal.pow_succ_lt_pow {P : Ideal A} [P_prime : P.IsPrime] (hP : P ≠ ⊥) (i : ℕ) : P ^ (i + 1) < P ^ i := - lt_of_le_of_ne (Ideal.pow_le_pow (Nat.le_succ _)) + lt_of_le_of_ne (Ideal.pow_le_pow_right (Nat.le_succ _)) (mt (pow_eq_pow_iff hP (mt Ideal.isUnit_iff.mp P_prime.ne_top)).mp i.succ_ne_self) #align ideal.pow_succ_lt_pow Ideal.pow_succ_lt_pow diff --git a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean index 3bb772cd9389a..b12a797640f6d 100644 --- a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean +++ b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean @@ -81,7 +81,7 @@ theorem exists_maximalIdeal_pow_eq_of_principal [IsNoetherianRing R] [LocalRing by_cases hs₃ : s = 0; · rw [hs₃]; exact zero_mem _ obtain ⟨n, u, rfl⟩ := H' s hs₃ (le_maximalIdeal hI' hs₁) rw [mul_comm, Ideal.unit_mul_mem_iff_mem _ u.isUnit] at hs₁ ⊢ - apply Ideal.pow_le_pow (Nat.find_min' this hs₁) + apply Ideal.pow_le_pow_right (Nat.find_min' this hs₁) apply Ideal.pow_mem_pow exact (H _).mpr (dvd_refl _) · rw [hx, Ideal.span_singleton_pow, Ideal.span_le, Set.singleton_subset_iff] @@ -246,7 +246,7 @@ theorem DiscreteValuationRing.TFAE [IsNoetherianRing R] [LocalRing R] [IsDomain obtain ⟨n, rfl⟩ := H I hI obtain ⟨m, rfl⟩ := H J hJ cases' le_total m n with h' h' - · left; exact Ideal.pow_le_pow h' - · right; exact Ideal.pow_le_pow h' + · left; exact Ideal.pow_le_pow_right h' + · right; exact Ideal.pow_le_pow_right h' tfae_finish #align discrete_valuation_ring.tfae DiscreteValuationRing.TFAE diff --git a/Mathlib/RingTheory/Etale.lean b/Mathlib/RingTheory/Etale.lean index a1e42956e7aa9..d6ba0d8dbd727 100644 --- a/Mathlib/RingTheory/Etale.lean +++ b/Mathlib/RingTheory/Etale.lean @@ -338,7 +338,7 @@ theorem FormallySmooth.of_split [FormallySmooth R P] (g : A →ₐ[R] P ⧸ (Rin have : _ = i (f x) := (FormallySmooth.mk_lift I ⟨2, hI⟩ (i.comp f) x : _) rwa [hx, map_zero, ← Ideal.Quotient.mk_eq_mk, Submodule.Quotient.mk_eq_zero] at this intro x hx - have := (Ideal.pow_mono this 2).trans (Ideal.le_comap_pow _ 2) hx + have := (Ideal.pow_right_mono this 2).trans (Ideal.le_comap_pow _ 2) hx rwa [hI] at this have : i.comp f.kerSquareLift = (Ideal.Quotient.mkₐ R _).comp l := by apply AlgHom.coe_ringHom_injective diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index fa2d1ece3dfb4..cc448dc748335 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -527,9 +527,9 @@ theorem exists_radical_pow_le_of_fg {R : Type*} [CommSemiring R] (I : Ideal R) ( rw [← Ideal.add_eq_sup, add_pow, Ideal.sum_eq_sup, Finset.sup_le_iff] refine' fun i _ => Ideal.mul_le_right.trans _ obtain h | h := le_or_lt n i - · apply Ideal.mul_le_right.trans ((Ideal.pow_le_pow h).trans hn) + · apply Ideal.mul_le_right.trans ((Ideal.pow_le_pow_right h).trans hn) · apply Ideal.mul_le_left.trans - refine' (Ideal.pow_le_pow _).trans hm + refine' (Ideal.pow_le_pow_right _).trans hm rw [add_comm, Nat.add_sub_assoc h.le] apply Nat.le_add_right #align ideal.exists_radical_pow_le_of_fg Ideal.exists_radical_pow_le_of_fg diff --git a/Mathlib/RingTheory/Henselian.lean b/Mathlib/RingTheory/Henselian.lean index 203d6bd8676cd..b3f04b7021ba1 100644 --- a/Mathlib/RingTheory/Henselian.lean +++ b/Mathlib/RingTheory/Henselian.lean @@ -227,7 +227,7 @@ instance (priority := 100) IsAdicComplete.henselianRing (R : Type*) [CommRing R] simp only [Finset.mem_Ico] rintro i ⟨h2i, _⟩ have aux : n + 2 ≤ i * (n + 1) := by trans 2 * (n + 1) <;> nlinarith only [h2i] - refine' Ideal.mul_mem_left _ _ (Ideal.pow_le_pow aux _) + refine' Ideal.mul_mem_left _ _ (Ideal.pow_le_pow_right aux _) rw [pow_mul'] refine' Ideal.pow_mem_pow ((Ideal.neg_mem_iff _).2 <| Ideal.mul_mem_right _ _ ih) _ -- we are now in the position to show that `c : ℕ → R` is a Cauchy sequence @@ -242,7 +242,7 @@ instance (priority := 100) IsAdicComplete.henselianRing (R : Type*) [CommRing R] refine' ih.add _ symm rw [SModEq.zero, Ideal.neg_mem_iff] - refine' Ideal.mul_mem_right _ _ (Ideal.pow_le_pow _ (hfcI _)) + refine' Ideal.mul_mem_right _ _ (Ideal.pow_le_pow_right _ (hfcI _)) rw [add_assoc] exact le_self_add -- hence the sequence converges to some limit point `a`, which is the `a` we are looking for @@ -255,7 +255,7 @@ instance (priority := 100) IsAdicComplete.henselianRing (R : Type*) [CommRing R] rw [← Ideal.one_eq_top, Ideal.smul_eq_mul, mul_one] at ha ⊢ refine' (ha.symm.eval f).trans _ rw [SModEq.zero] - exact Ideal.pow_le_pow le_self_add (hfcI _) + exact Ideal.pow_le_pow_right le_self_add (hfcI _) · show a - a₀ ∈ I specialize ha 1 rw [hc, pow_one, ← Ideal.one_eq_top, Ideal.smul_eq_mul, mul_one, sub_eq_add_neg] at ha diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 04ec2ffbb4116..17e7d6ced29fa 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -790,24 +790,24 @@ theorem sup_mul : (I ⊔ J) * K = I * K ⊔ J * K := variable {I J K} -theorem pow_le_pow {m n : ℕ} (h : m ≤ n) : I ^ n ≤ I ^ m := by +theorem pow_le_pow_right {m n : ℕ} (h : m ≤ n) : I ^ n ≤ I ^ m := by cases' Nat.exists_eq_add_of_le h with k hk rw [hk, pow_add] exact le_trans mul_le_inf inf_le_left -#align ideal.pow_le_pow Ideal.pow_le_pow +#align ideal.pow_le_pow_right Ideal.pow_le_pow_right theorem pow_le_self {n : ℕ} (hn : n ≠ 0) : I ^ n ≤ I := calc - I ^ n ≤ I ^ 1 := pow_le_pow (Nat.pos_of_ne_zero hn) + I ^ n ≤ I ^ 1 := pow_le_pow_right (Nat.pos_of_ne_zero hn) _ = I := pow_one _ #align ideal.pow_le_self Ideal.pow_le_self -theorem pow_mono {I J : Ideal R} (e : I ≤ J) (n : ℕ) : I ^ n ≤ J ^ n := by +theorem pow_right_mono {I J : Ideal R} (e : I ≤ J) (n : ℕ) : I ^ n ≤ J ^ n := by induction' n with _ hn · rw [pow_zero, pow_zero] · rw [pow_succ, pow_succ] exact Ideal.mul_mono e hn -#align ideal.pow_mono Ideal.pow_mono +#align ideal.pow_right_mono Ideal.pow_right_mono theorem mul_eq_bot {R : Type*} [CommSemiring R] [NoZeroDivisors R] {I J : Ideal R} : I * J = ⊥ ↔ I = ⊥ ∨ J = ⊥ := diff --git a/Mathlib/RingTheory/LittleWedderburn.lean b/Mathlib/RingTheory/LittleWedderburn.lean index 18a29f8e752a8..ab7138df571cc 100644 --- a/Mathlib/RingTheory/LittleWedderburn.lean +++ b/Mathlib/RingTheory/LittleWedderburn.lean @@ -128,7 +128,7 @@ private theorem center_eq_top [Finite D] (hD : InductionHyp D) : Subring.center rw [← aux, ← aux, ← eval_mul] refine (evalRingHom ↑q).map_dvd (X_pow_sub_one_mul_cyclotomic_dvd_X_pow_sub_one_of_dvd ℤ ?_) refine Nat.mem_properDivisors.mpr ⟨⟨_, (finrank_mul_finrank Z Zx D).symm⟩, ?_⟩ - rw [← (Nat.pow_right_strictMono hq).lt_iff_lt, ← card_D, ← card_Zx] + rw [← pow_lt_pow_iff_right hq, ← card_D, ← card_Zx] obtain ⟨b, -, hb⟩ := SetLike.exists_of_lt hZx.lt_top refine card_lt_of_injective_of_not_mem _ Subtype.val_injective (?_ : b ∉ _) rintro ⟨b, rfl⟩ diff --git a/Mathlib/RingTheory/Perfection.lean b/Mathlib/RingTheory/Perfection.lean index 7cf7b3a8d2d53..c436dda16be99 100644 --- a/Mathlib/RingTheory/Perfection.lean +++ b/Mathlib/RingTheory/Perfection.lean @@ -600,8 +600,8 @@ theorem valAux_add (f g : PreTilt K v O hv p) : rw [valAux_eq hm, valAux_eq hn, valAux_eq hk, RingHom.map_add] cases' le_max_iff.1 (ModP.preVal_add (coeff _ _ (max (max m n) k) f) (coeff _ _ (max (max m n) k) g)) with h h - · exact le_max_of_le_left (pow_le_pow_of_le_left' h _) - · exact le_max_of_le_right (pow_le_pow_of_le_left' h _) + · exact le_max_of_le_left (pow_le_pow_left' h _) + · exact le_max_of_le_right (pow_le_pow_left' h _) #align pre_tilt.val_aux_add PreTilt.valAux_add variable (K v O hv p) diff --git a/Mathlib/RingTheory/Polynomial/Basic.lean b/Mathlib/RingTheory/Polynomial/Basic.lean index cc630abf36974..5b210a31edb35 100644 --- a/Mathlib/RingTheory/Polynomial/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Basic.lean @@ -305,7 +305,7 @@ theorem Monic.geom_sum {P : R[X]} (hP : P.Monic) (hdeg : 0 < P.natDegree) {n : · simp only [Finset.mem_range, degree_eq_natDegree (hP.pow _).ne_zero] simp only [Nat.cast_lt, hP.natDegree_pow] intro k - exact nsmul_lt_nsmul hdeg + exact nsmul_lt_nsmul_left hdeg · rw [bot_lt_iff_ne_bot, Ne.def, degree_eq_bot] exact (hP.pow _).ne_zero #align polynomial.monic.geom_sum Polynomial.Monic.geom_sum @@ -698,7 +698,7 @@ theorem _root_.Polynomial.coeff_prod_mem_ideal_pow_tsub {ι : Type*} (s : Finset apply sum_mem rintro ⟨i, j⟩ e obtain rfl : i + j = k := mem_antidiagonal.mp e - apply Ideal.pow_le_pow add_tsub_add_le_tsub_add_tsub + apply Ideal.pow_le_pow_right add_tsub_add_le_tsub_add_tsub rw [pow_add] exact Ideal.mul_mem_mul (h _ (Finset.mem_insert.mpr <| Or.inl rfl) _) diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean index f6b4eaa205b7c..1f76d7e29433f 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean @@ -175,7 +175,7 @@ theorem isRoot_cyclotomic_prime_pow_mul_iff_of_charP {m k p : ℕ} {R : Type*} [ rw [cyclotomic_mul_prime_pow_eq R (NeZero.not_char_dvd R p m) hk, IsRoot.def, eval_pow, h, zero_pow] simp only [tsub_pos_iff_lt] - apply pow_strictMono_right hp.out.one_lt (Nat.pred_lt hk.ne') + apply pow_right_strictMono hp.out.one_lt (Nat.pred_lt hk.ne') #align polynomial.is_root_cyclotomic_prime_pow_mul_iff_of_char_p Polynomial.isRoot_cyclotomic_prime_pow_mul_iff_of_charP end CharP diff --git a/Mathlib/RingTheory/QuotientNilpotent.lean b/Mathlib/RingTheory/QuotientNilpotent.lean index 3d1e9248e9155..437e6dc96931b 100644 --- a/Mathlib/RingTheory/QuotientNilpotent.lean +++ b/Mathlib/RingTheory/QuotientNilpotent.lean @@ -46,7 +46,7 @@ theorem Ideal.IsNilpotent.induction_on (hI : IsNilpotent I) apply h₂ (I ^ 2) _ (Ideal.pow_le_self two_ne_zero) · apply H n.succ _ (I ^ 2) · rw [← pow_mul, eq_bot_iff, ← hI, Nat.succ_eq_add_one, Nat.succ_eq_add_one] - apply Ideal.pow_le_pow (by linarith) + apply Ideal.pow_le_pow_right (by linarith) · exact n.succ.lt_succ_self · apply h₁ rw [← Ideal.map_pow, Ideal.map_quotient_self] diff --git a/Mathlib/RingTheory/Valuation/Integral.lean b/Mathlib/RingTheory/Valuation/Integral.lean index e0aef90c67948..e8b7395cf51fa 100644 --- a/Mathlib/RingTheory/Valuation/Integral.lean +++ b/Mathlib/RingTheory/Valuation/Integral.lean @@ -41,8 +41,8 @@ theorem mem_of_integral {x : R} (hx : IsIntegral O x) : x ∈ v.integer := rw [eval₂_mul, eval₂_pow, eval₂_C, eval₂_X, v.map_mul, v.map_pow, ← one_mul (v x ^ p.natDegree)] cases' (hv.2 <| p.coeff i).lt_or_eq with hvpi hvpi - · exact mul_lt_mul₀ hvpi (pow_lt_pow₀ hvx <| Finset.mem_range.1 hi) - · erw [hvpi]; rw [one_mul, one_mul]; exact pow_lt_pow₀ hvx (Finset.mem_range.1 hi) + · exact mul_lt_mul₀ hvpi (pow_lt_pow_right₀ hvx <| Finset.mem_range.1 hi) + · erw [hvpi]; rw [one_mul, one_mul]; exact pow_lt_pow_right₀ hvx (Finset.mem_range.1 hi) #align valuation.integers.mem_of_integral Valuation.Integers.mem_of_integral protected theorem integralClosure : integralClosure O R = ⊥ := diff --git a/Mathlib/RingTheory/WittVector/Frobenius.lean b/Mathlib/RingTheory/WittVector/Frobenius.lean index f7c15d5f29db0..3d0f384daa5ef 100644 --- a/Mathlib/RingTheory/WittVector/Frobenius.lean +++ b/Mathlib/RingTheory/WittVector/Frobenius.lean @@ -138,7 +138,7 @@ theorem map_frobeniusPoly.key₂ {n i j : ℕ} (hi : i ≤ n) (hj : j < p ^ (n - add_assoc, tsub_right_comm, add_comm i, tsub_add_cancel_of_le (le_tsub_of_add_le_right ((le_tsub_iff_left hi).mp h₁))] have hle : p ^ m ≤ j + 1 := h ▸ Nat.le_of_dvd j.succ_pos (multiplicity.pow_multiplicity_dvd _) - exact ⟨(pow_le_pow_iff hp.1.one_lt).1 (hle.trans hj), + exact ⟨(pow_le_pow_iff_right hp.1.one_lt).1 (hle.trans hj), Nat.le_of_lt_succ ((Nat.lt_pow_self hp.1.one_lt m).trans_le hle)⟩ #align witt_vector.map_frobenius_poly.key₂ WittVector.map_frobeniusPoly.key₂ diff --git a/Mathlib/Tactic/GCongr.lean b/Mathlib/Tactic/GCongr.lean index 0e4a2cf7a58c9..00eb904655a0a 100644 --- a/Mathlib/Tactic/GCongr.lean +++ b/Mathlib/Tactic/GCongr.lean @@ -102,8 +102,8 @@ attribute [gcongr] /-! # ≤, ^ -/ attribute [gcongr] - pow_le_pow pow_le_pow' zpow_le_zpow zpow_le_of_le -- ff ^ tt - pow_le_pow_of_le_left pow_le_pow_of_le_left' zpow_le_zpow' -- tt ^ ff + pow_le_pow_right pow_le_pow_right' zpow_le_zpow zpow_le_of_le -- ff ^ tt + pow_le_pow_left pow_le_pow_left' zpow_le_zpow' -- tt ^ ff /-! # <, ^ -/ @@ -112,8 +112,8 @@ theorem zpow_lt_of_lt [LinearOrderedSemifield α] {a : α} {m n : ℤ} (hx : 1 < zpow_strictMono hx h attribute [gcongr] - pow_lt_pow pow_lt_pow' zpow_lt_zpow zpow_lt_of_lt -- ff ^ tt - pow_lt_pow_of_lt_left zpow_lt_zpow' -- tt ^ ff + pow_lt_pow_right pow_lt_pow_right' zpow_lt_zpow zpow_lt_of_lt -- ff ^ tt + pow_lt_pow_left zpow_lt_zpow' -- tt ^ ff /-! # coercions -/ diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Order.lean b/Mathlib/Topology/Algebra/InfiniteSum/Order.lean index 53dcb7c6685f3..cee7485e5e9d8 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Order.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Order.lean @@ -267,7 +267,7 @@ theorem Finite.of_summable_const [LinearOrderedAddCommGroup α] [TopologicalSpac simpa using sum_le_hasSum s (fun a _ => hb.le) hf.hasSum obtain ⟨n, hn⟩ := Archimedean.arch (∑' _ : ι, b) hb have : ∀ s : Finset ι, s.card ≤ n := fun s => by - simpa [nsmul_le_nsmul_iff hb] using (H s).trans hn + simpa [nsmul_le_nsmul_iff_left hb] using (H s).trans hn have : Fintype ι := fintypeOfFinsetCardLe n this infer_instance diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/AdicTopology.lean b/Mathlib/Topology/Algebra/Nonarchimedean/AdicTopology.lean index df8353733e861..af02d73ea693a 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/AdicTopology.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/AdicTopology.lean @@ -57,7 +57,7 @@ theorem adic_basis (I : Ideal R) : SubmodulesRingBasis fun n : ℕ => (I ^ n • suffices ∀ i j : ℕ, ∃ k, I ^ k ≤ I ^ i ∧ I ^ k ≤ I ^ j by simpa only [smul_eq_mul, mul_top, Algebra.id.map_eq_id, map_id, le_inf_iff] using this intro i j - exact ⟨max i j, pow_le_pow (le_max_left i j), pow_le_pow (le_max_right i j)⟩ + exact ⟨max i j, pow_le_pow_right (le_max_left i j), pow_le_pow_right (le_max_right i j)⟩ leftMul := by suffices ∀ (a : R) (i : ℕ), ∃ j : ℕ, a • I ^ j ≤ I ^ i by simpa only [smul_top_eq_map, Algebra.id.map_eq_id, map_id] using this @@ -119,8 +119,8 @@ theorem adic_module_basis : { inter := fun i j => ⟨max i j, le_inf_iff.mpr - ⟨smul_mono_left <| pow_le_pow (le_max_left i j), - smul_mono_left <| pow_le_pow (le_max_right i j)⟩⟩ + ⟨smul_mono_left <| pow_le_pow_right (le_max_left i j), + smul_mono_left <| pow_le_pow_right (le_max_right i j)⟩⟩ smul := fun m i => ⟨(I ^ i • ⊤ : Ideal R), ⟨i, by simp⟩, fun a a_in => by replace a_in : a ∈ I ^ i := by simpa [(I ^ i).mul_top] using a_in @@ -201,7 +201,7 @@ theorem is_ideal_adic_pow {J : Ideal R} (h : IsAdic J) {n : ℕ} (hn : 0 < n) : · exfalso exact Nat.not_succ_le_zero 0 hn rw [← pow_mul, Nat.succ_mul] - apply Ideal.pow_le_pow + apply Ideal.pow_le_pow_right apply Nat.le_add_left #align is_ideal_adic_pow is_ideal_adic_pow diff --git a/Mathlib/Topology/EMetricSpace/Paracompact.lean b/Mathlib/Topology/EMetricSpace/Paracompact.lean index ba1e0e2ac41ea..a5228884ea43b 100644 --- a/Mathlib/Topology/EMetricSpace/Paracompact.lean +++ b/Mathlib/Topology/EMetricSpace/Paracompact.lean @@ -43,7 +43,7 @@ instance (priority := 100) instParacompactSpace [PseudoEMetricSpace α] : Paraco have pow_pos : ∀ k : ℕ, (0 : ℝ≥0∞) < 2⁻¹ ^ k := fun k => ENNReal.pow_pos (ENNReal.inv_pos.2 ENNReal.two_ne_top) _ have hpow_le : ∀ {m n : ℕ}, m ≤ n → (2⁻¹ : ℝ≥0∞) ^ n ≤ 2⁻¹ ^ m := @fun m n h => - pow_le_pow_of_le_one' (ENNReal.inv_le_one.2 ENNReal.one_lt_two.le) h + pow_le_pow_right_of_le_one' (ENNReal.inv_le_one.2 ENNReal.one_lt_two.le) h have h2pow : ∀ n : ℕ, 2 * (2⁻¹ : ℝ≥0∞) ^ (n + 1) = 2⁻¹ ^ n := fun n => by simp [pow_succ, ← mul_assoc, ENNReal.mul_inv_cancel two_ne_zero two_ne_top] -- Consider an open covering `S : Set (Set α)` diff --git a/Mathlib/Topology/Instances/NNReal.lean b/Mathlib/Topology/Instances/NNReal.lean index b8cbdac0d0802..8bd81f84d22a7 100644 --- a/Mathlib/Topology/Instances/NNReal.lean +++ b/Mathlib/Topology/Instances/NNReal.lean @@ -256,7 +256,7 @@ nonrec theorem tendsto_tsum_compl_atTop_zero {α : Type*} (f : α → ℝ≥0) : /-- `x ↦ x ^ n` as an order isomorphism of `ℝ≥0`. -/ def powOrderIso (n : ℕ) (hn : n ≠ 0) : ℝ≥0 ≃o ℝ≥0 := StrictMono.orderIsoOfSurjective (fun x ↦ x ^ n) (fun x y h => - strictMonoOn_pow hn.bot_lt (zero_le x) (zero_le y) h) <| + pow_left_strictMonoOn hn (zero_le x) (zero_le y) h) <| (continuous_id.pow _).surjective (tendsto_pow_atTop hn) <| by simpa [OrderBot.atBot_eq, pos_iff_ne_zero] #align nnreal.pow_order_iso NNReal.powOrderIso diff --git a/Mathlib/Topology/MetricSpace/HausdorffDistance.lean b/Mathlib/Topology/MetricSpace/HausdorffDistance.lean index e932af2bae0aa..52960eda285c9 100644 --- a/Mathlib/Topology/MetricSpace/HausdorffDistance.lean +++ b/Mathlib/Topology/MetricSpace/HausdorffDistance.lean @@ -224,7 +224,7 @@ theorem _root_.IsOpen.exists_iUnion_isClosed {U : Set α} (hU : IsOpen U) : show Monotone F · intro m n hmn x hx simp only [mem_Ici, mem_preimage] at hx ⊢ - apply le_trans (pow_le_pow_of_le_one' a_lt_one.le hmn) hx + apply le_trans (pow_le_pow_right_of_le_one' a_lt_one.le hmn) hx #align is_open.exists_Union_is_closed IsOpen.exists_iUnion_isClosed theorem _root_.IsCompact.exists_infEdist_eq_edist (hs : IsCompact s) (hne : s.Nonempty) (x : α) : diff --git a/Mathlib/Topology/MetricSpace/PiNat.lean b/Mathlib/Topology/MetricSpace/PiNat.lean index 88af496faa80c..40c96261c1ec9 100644 --- a/Mathlib/Topology/MetricSpace/PiNat.lean +++ b/Mathlib/Topology/MetricSpace/PiNat.lean @@ -56,7 +56,7 @@ open Classical Topology Filter open TopologicalSpace Set Metric Filter Function -attribute [local simp] pow_le_pow_iff one_lt_two inv_le_inv zero_le_two zero_lt_two +attribute [local simp] pow_le_pow_iff_right one_lt_two inv_le_inv zero_le_two zero_lt_two variable {E : ℕ → Type*} @@ -295,7 +295,7 @@ theorem dist_triangle_nonarch (x y z : ∀ n, E n) : dist x z ≤ max (dist x y) rcases eq_or_ne y z with (rfl | hyz) · simp simp only [dist_eq_of_ne, hxz, hxy, hyz, inv_le_inv, one_div, inv_pow, zero_lt_two, Ne.def, - not_false_iff, le_max_iff, pow_le_pow_iff, one_lt_two, pow_pos, + not_false_iff, le_max_iff, pow_le_pow_iff_right, one_lt_two, pow_pos, min_le_iff.1 (min_firstDiff_le x y z hxz)] #align pi_nat.dist_triangle_nonarch PiNat.dist_triangle_nonarch @@ -328,7 +328,7 @@ theorem apply_eq_of_dist_lt {x y : ∀ n, E n} {n : ℕ} (h : dist x y < (1 / 2) rcases eq_or_ne x y with (rfl | hne) · rfl have : n < firstDiff x y := by - simpa [dist_eq_of_ne hne, inv_lt_inv, pow_lt_pow_iff, one_lt_two] using h + simpa [dist_eq_of_ne hne, inv_lt_inv, pow_lt_pow_iff_right, one_lt_two] using h exact apply_eq_of_lt_firstDiff (hi.trans_lt this) #align pi_nat.apply_eq_of_dist_lt PiNat.apply_eq_of_dist_lt diff --git a/Mathlib/Topology/Metrizable/Uniformity.lean b/Mathlib/Topology/Metrizable/Uniformity.lean index 787d9b2e19fc5..a92d51d8e47da 100644 --- a/Mathlib/Topology/Metrizable/Uniformity.lean +++ b/Mathlib/Topology/Metrizable/Uniformity.lean @@ -226,7 +226,7 @@ protected theorem UniformSpace.metrizable_uniformity (X : Type*) [UniformSpace X intro x y n dsimp only [] split_ifs with h - · rw [(strictAnti_pow hr.1 hr.2).le_iff_le, Nat.find_le_iff] + · rw [(pow_right_strictAnti hr.1 hr.2).le_iff_le, Nat.find_le_iff] exact ⟨fun ⟨m, hmn, hm⟩ hn => hm (hB.antitone hmn hn), fun h => ⟨n, le_rfl, h⟩⟩ · push_neg at h simp only [h, not_true, (pow_pos hr.1 _).not_le] diff --git a/Mathlib/Topology/UnitInterval.lean b/Mathlib/Topology/UnitInterval.lean index 531578c12b74d..44797fad16522 100644 --- a/Mathlib/Topology/UnitInterval.lean +++ b/Mathlib/Topology/UnitInterval.lean @@ -226,10 +226,10 @@ lemma addNSMul_eq_right [Archimedean α] (hδ : 0 < δ) : obtain ⟨m, hm⟩ := Archimedean.arch (b - a) hδ refine ⟨m, fun n hn ↦ ?_⟩ rw [addNSMul, coe_projIcc, add_comm, min_eq_left_iff.mpr, max_eq_right h] - exact sub_le_iff_le_add.mp (hm.trans <| nsmul_le_nsmul hδ.le hn) + exact sub_le_iff_le_add.mp (hm.trans <| nsmul_le_nsmul_left hδ.le hn) lemma monotone_addNSMul (hδ : 0 ≤ δ) : Monotone (addNSMul h δ) := - fun _ _ hnm ↦ monotone_projIcc h <| (add_le_add_iff_left _).mpr (nsmul_le_nsmul hδ hnm) + fun _ _ hnm ↦ monotone_projIcc h <| (add_le_add_iff_left _).mpr (nsmul_le_nsmul_left hδ hnm) lemma abs_sub_addNSMul_le (hδ : 0 ≤ δ) {t : Icc a b} (n : ℕ) (ht : t ∈ Icc (addNSMul h δ n) (addNSMul h δ (n+1))) : From b6e8469ddf5bcb441aa06b0ac8e5b67bf54e0080 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Mon, 18 Dec 2023 08:56:03 +0000 Subject: [PATCH 053/353] feat: add mulTSupport_mul/tsupport_add (#9060) From the hairer branch. --- Mathlib/Topology/Support.lean | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Mathlib/Topology/Support.lean b/Mathlib/Topology/Support.lean index 81b3234fa8e6a..238c5bc0e8d80 100644 --- a/Mathlib/Topology/Support.lean +++ b/Mathlib/Topology/Support.lean @@ -102,6 +102,13 @@ theorem tsupport_smul_subset_left {M α} [TopologicalSpace X] [Zero M] [Zero α] closure_mono <| support_smul_subset_left f g #align tsupport_smul_subset_left tsupport_smul_subset_left +@[to_additive] +theorem mulTSupport_mul [TopologicalSpace X] [Monoid α] {f g : X → α} : + (mulTSupport fun x ↦ f x * g x) ⊆ mulTSupport f ∪ mulTSupport g := + closure_minimal + ((mulSupport_mul f g).trans (union_subset_union (subset_mulTSupport _) (subset_mulTSupport _))) + (isClosed_closure.union isClosed_closure) + section variable [TopologicalSpace α] [TopologicalSpace α'] From 6fab96dd7d4c76e9cace76ad16f3f1e3e43f2557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Dvo=C5=99=C3=A1k?= Date: Mon, 18 Dec 2023 09:44:02 +0000 Subject: [PATCH 054/353] feat: OrderedCancelAddCommMonoidWithBounds is bad (#9072) --- Counterexamples.lean | 1 + .../OrderedCancelAddCommMonoidWithBounds.lean | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 Counterexamples/OrderedCancelAddCommMonoidWithBounds.lean diff --git a/Counterexamples.lean b/Counterexamples.lean index dd67bf15a550c..b637aee44f4c4 100644 --- a/Counterexamples.lean +++ b/Counterexamples.lean @@ -8,6 +8,7 @@ import Counterexamples.HomogeneousPrimeNotPrime import Counterexamples.LinearOrderWithPosMulPosEqZero import Counterexamples.MapFloor import Counterexamples.Monic_nonRegular +import Counterexamples.OrderedCancelAddCommMonoidWithBounds import Counterexamples.Phillips import Counterexamples.Pseudoelement import Counterexamples.QuadraticForm diff --git a/Counterexamples/OrderedCancelAddCommMonoidWithBounds.lean b/Counterexamples/OrderedCancelAddCommMonoidWithBounds.lean new file mode 100644 index 0000000000000..9fd427765bf90 --- /dev/null +++ b/Counterexamples/OrderedCancelAddCommMonoidWithBounds.lean @@ -0,0 +1,19 @@ +/- +Copyright (c) 2023 Martin Dvorak. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Martin Dvorak +-/ +import Mathlib.Algebra.Order.Monoid.Defs + +/-! +# Do not combine OrderedCancelAddCommMonoid with BoundedOrder + +This file shows that combining `OrderedCancelAddCommMonoid` with `BoundedOrder` is not a good idea, +as such a structure must be trivial (`⊥ = x = ⊤` for all `x`). +The same applies to any superclasses, e.g. combining `StrictOrderedSemiring` with `CompleteLattice`. +-/ + +example {α : Type*} [OrderedCancelAddCommMonoid α] [BoundedOrder α] [Nontrivial α] : False := + have top_pos := pos_of_lt_add_right (bot_le.trans_lt (add_lt_add_left bot_lt_top (⊥ : α))) + have top_add_top_lt_self := lt_add_of_le_of_pos (@le_top _ _ _ (⊤ + ⊤)) top_pos + top_add_top_lt_self.false From 9e9f25c5d364fa029d4366b22564c3f408ac5593 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Mon, 18 Dec 2023 10:03:02 +0000 Subject: [PATCH 055/353] chore: bump to nightly-2023-12-18 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 095b0ec449c07..05e3a626b95b7 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-17 +leanprover/lean4:nightly-2023-12-18 From 8eef7faf3a1c7c2ca7e2bf7369692e53ac542954 Mon Sep 17 00:00:00 2001 From: sgouezel Date: Mon, 18 Dec 2023 10:05:21 +0000 Subject: [PATCH 056/353] feat: demote the instance Fintype.ofIsEmpty to a def (#8816) Rationale: this instance creates (empty) data out of nothing, which may conflict with other data. If you have in the context `[Fintype i]` and case on whether `i` is empty or not, then this gave two non-defeq instances of `[Fintype i]` around. --- Archive/ZagierTwoSquares.lean | 2 +- .../Analysis/InnerProductSpace/TwoDim.lean | 2 +- Mathlib/Analysis/MeanInequalities.lean | 6 +++--- Mathlib/Data/Fintype/Basic.lean | 14 ++++++++----- Mathlib/Data/Fintype/Card.lean | 10 ++++------ Mathlib/Data/Fintype/CardEmbedding.lean | 1 - Mathlib/Data/Set/Finite.lean | 12 +++++------ Mathlib/LinearAlgebra/Orientation.lean | 8 ++------ .../Constructions/BorelSpace/Basic.lean | 2 +- Mathlib/MeasureTheory/Constructions/Pi.lean | 20 +++++++++---------- Mathlib/ModelTheory/Basic.lean | 2 +- Mathlib/SetTheory/Cardinal/Basic.lean | 1 + Mathlib/SetTheory/Cardinal/Cofinality.lean | 3 +-- Mathlib/SetTheory/Cardinal/Finite.lean | 3 +-- Mathlib/SetTheory/Game/Short.lean | 6 ++++-- 15 files changed, 44 insertions(+), 48 deletions(-) diff --git a/Archive/ZagierTwoSquares.lean b/Archive/ZagierTwoSquares.lean index 2b91f80fcb9e8..8b52d84d39431 100644 --- a/Archive/ZagierTwoSquares.lean +++ b/Archive/ZagierTwoSquares.lean @@ -195,5 +195,5 @@ theorem Nat.Prime.sq_add_sq' {p : ℕ} [h : Fact p.Prime] (hp : p % 4 = 1) : (Equiv.Perm.card_fixedPoints_modEq (p := 2) (n := 1) (complexInvo_sq k)) contrapose key rw [Set.not_nonempty_iff_eq_empty] at key - simp_rw [key, Fintype.card_of_isEmpty, card_fixedPoints_eq_one] + simp_rw [key, Fintype.card_eq_zero, card_fixedPoints_eq_one] decide diff --git a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean index d1a8ee6492fe2..32a3c36a44303 100644 --- a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean +++ b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean @@ -448,7 +448,7 @@ theorem nonneg_inner_and_areaForm_eq_zero_iff_sameRay (x y : E) : suffices ↑0 ≤ a * ‖x‖ ^ 2 ∧ b * ‖x‖ ^ 2 = 0 → SameRay ℝ x (a • x + b • J x) by rw [← (o.basisRightAngleRotation x hx).sum_repr y] simp only [Fin.sum_univ_succ, coe_basisRightAngleRotation, Matrix.cons_val_zero, - Fin.succ_zero_eq_one', Fintype.univ_of_isEmpty, Finset.sum_empty, areaForm_apply_self, + Fin.succ_zero_eq_one', Finset.univ_eq_empty, Finset.sum_empty, areaForm_apply_self, map_smul, map_add, real_inner_smul_right, inner_add_right, Matrix.cons_val_one, Matrix.head_cons, Algebra.id.smul_eq_mul, areaForm_rightAngleRotation_right, mul_zero, add_zero, zero_add, neg_zero, inner_rightAngleRotation_right, diff --git a/Mathlib/Analysis/MeanInequalities.lean b/Mathlib/Analysis/MeanInequalities.lean index e442b2c0557bc..7310ec13f143f 100644 --- a/Mathlib/Analysis/MeanInequalities.lean +++ b/Mathlib/Analysis/MeanInequalities.lean @@ -200,7 +200,7 @@ for two `NNReal` numbers. -/ theorem geom_mean_le_arith_mean2_weighted (w₁ w₂ p₁ p₂ : ℝ≥0) : w₁ + w₂ = 1 → p₁ ^ (w₁ : ℝ) * p₂ ^ (w₂ : ℝ) ≤ w₁ * p₁ + w₂ * p₂ := by simpa only [Fin.prod_univ_succ, Fin.sum_univ_succ, Finset.prod_empty, Finset.sum_empty, - Fintype.univ_of_isEmpty, Fin.cons_succ, Fin.cons_zero, add_zero, mul_one] using + Finset.univ_eq_empty, Fin.cons_succ, Fin.cons_zero, add_zero, mul_one] using geom_mean_le_arith_mean_weighted univ ![w₁, w₂] ![p₁, p₂] #align nnreal.geom_mean_le_arith_mean2_weighted NNReal.geom_mean_le_arith_mean2_weighted @@ -208,7 +208,7 @@ theorem geom_mean_le_arith_mean3_weighted (w₁ w₂ w₃ p₁ p₂ p₃ : ℝ w₁ + w₂ + w₃ = 1 → p₁ ^ (w₁ : ℝ) * p₂ ^ (w₂ : ℝ) * p₃ ^ (w₃ : ℝ) ≤ w₁ * p₁ + w₂ * p₂ + w₃ * p₃ := by simpa only [Fin.prod_univ_succ, Fin.sum_univ_succ, Finset.prod_empty, Finset.sum_empty, - Fintype.univ_of_isEmpty, Fin.cons_succ, Fin.cons_zero, add_zero, mul_one, ← add_assoc, + Finset.univ_eq_empty, Fin.cons_succ, Fin.cons_zero, add_zero, mul_one, ← add_assoc, mul_assoc] using geom_mean_le_arith_mean_weighted univ ![w₁, w₂, w₃] ![p₁, p₂, p₃] #align nnreal.geom_mean_le_arith_mean3_weighted NNReal.geom_mean_le_arith_mean3_weighted @@ -217,7 +217,7 @@ theorem geom_mean_le_arith_mean4_weighted (w₁ w₂ w₃ w₄ p₁ p₂ p₃ p p₁ ^ (w₁ : ℝ) * p₂ ^ (w₂ : ℝ) * p₃ ^ (w₃ : ℝ) * p₄ ^ (w₄ : ℝ) ≤ w₁ * p₁ + w₂ * p₂ + w₃ * p₃ + w₄ * p₄ := by simpa only [Fin.prod_univ_succ, Fin.sum_univ_succ, Finset.prod_empty, Finset.sum_empty, - Fintype.univ_of_isEmpty, Fin.cons_succ, Fin.cons_zero, add_zero, mul_one, ← add_assoc, + Finset.univ_eq_empty, Fin.cons_succ, Fin.cons_zero, add_zero, mul_one, ← add_assoc, mul_assoc] using geom_mean_le_arith_mean_weighted univ ![w₁, w₂, w₃, w₄] ![p₁, p₂, p₃, p₄] #align nnreal.geom_mean_le_arith_mean4_weighted NNReal.geom_mean_le_arith_mean4_weighted diff --git a/Mathlib/Data/Fintype/Basic.lean b/Mathlib/Data/Fintype/Basic.lean index 9c075e7a1c66c..e2b0a9d38c4d7 100644 --- a/Mathlib/Data/Fintype/Basic.lean +++ b/Mathlib/Data/Fintype/Basic.lean @@ -596,19 +596,22 @@ theorem univ_ofSubsingleton (a : α) [Subsingleton α] : @univ _ (ofSubsingleton rfl #align fintype.univ_of_subsingleton Fintype.univ_ofSubsingleton --- see Note [lower instance priority] -instance (priority := 100) ofIsEmpty [IsEmpty α] : Fintype α := +/-- An empty type is a fintype. Not registered as an instance, to make sure that there aren't two +conflicting `Fintype ι` instances around when casing over whether a fintype `ι` is empty or not. -/ +def ofIsEmpty [IsEmpty α] : Fintype α := ⟨∅, isEmptyElim⟩ #align fintype.of_is_empty Fintype.ofIsEmpty --- no-lint since while `Finset.univ_eq_empty` can prove this, it isn't applicable for `dsimp`. /-- Note: this lemma is specifically about `Fintype.of_isEmpty`. For a statement about arbitrary `Fintype` instances, use `Finset.univ_eq_empty`. -/ -@[simp, nolint simpNF] -theorem univ_of_isEmpty [IsEmpty α] : @univ α _ = ∅ := +@[simp] +theorem univ_of_isEmpty [IsEmpty α] : @univ α Fintype.ofIsEmpty = ∅ := rfl #align fintype.univ_of_is_empty Fintype.univ_of_isEmpty +instance : Fintype Empty := Fintype.ofIsEmpty +instance : Fintype PEmpty := Fintype.ofIsEmpty + end Fintype namespace Set @@ -757,6 +760,7 @@ theorem toFinset_univ [Fintype α] [Fintype (Set.univ : Set α)] : @[simp] theorem toFinset_eq_empty [Fintype s] : s.toFinset = ∅ ↔ s = ∅ := by + let A : Fintype (∅ : Set α) := Fintype.ofIsEmpty rw [← toFinset_empty, toFinset_inj] #align set.to_finset_eq_empty Set.toFinset_eq_empty diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index 648642ea6cb76..69e9fecfd4d40 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -222,10 +222,10 @@ theorem card_unique [Unique α] [h : Fintype α] : Fintype.card α = 1 := Subsingleton.elim (ofSubsingleton default) h ▸ card_ofSubsingleton _ #align fintype.card_unique Fintype.card_unique -/-- Note: this lemma is specifically about `Fintype.of_is_empty`. For a statement about -arbitrary `Fintype` instances, use `Fintype.card_eq_zero_iff`. -/ +/-- Note: this lemma is specifically about `Fintype.ofIsEmpty`. For a statement about +arbitrary `Fintype` instances, use `Fintype.card_eq_zero`. -/ @[simp] -theorem card_of_isEmpty [IsEmpty α] : Fintype.card α = 0 := +theorem card_of_isEmpty [IsEmpty α] : @Fintype.card α Fintype.ofIsEmpty = 0 := rfl #align fintype.card_of_is_empty Fintype.card_of_isEmpty @@ -356,12 +356,10 @@ theorem Fintype.card_subtype_eq' (y : α) [Fintype { x // y = x }] : Fintype.card_unique #align fintype.card_subtype_eq' Fintype.card_subtype_eq' -@[simp] theorem Fintype.card_empty : Fintype.card Empty = 0 := rfl #align fintype.card_empty Fintype.card_empty -@[simp] theorem Fintype.card_pempty : Fintype.card PEmpty = 0 := rfl #align fintype.card_pempty Fintype.card_pempty @@ -534,7 +532,7 @@ theorem card_eq_zero_iff : card α = 0 ↔ IsEmpty α := by rw [card, Finset.card_eq_zero, univ_eq_empty_iff] #align fintype.card_eq_zero_iff Fintype.card_eq_zero_iff -theorem card_eq_zero [IsEmpty α] : card α = 0 := +@[simp] theorem card_eq_zero [IsEmpty α] : card α = 0 := card_eq_zero_iff.2 ‹_› #align fintype.card_eq_zero Fintype.card_eq_zero diff --git a/Mathlib/Data/Fintype/CardEmbedding.lean b/Mathlib/Data/Fintype/CardEmbedding.lean index a2fb358165c70..5ddebd9f5afae 100644 --- a/Mathlib/Data/Fintype/CardEmbedding.lean +++ b/Mathlib/Data/Fintype/CardEmbedding.lean @@ -53,7 +53,6 @@ theorem card_embedding_eq {α β : Type*} [Fintype α] [Fintype β] [emb : Finty /- The cardinality of embeddings from an infinite type to a finite type is zero. This is a re-statement of the pigeonhole principle. -/ -@[simp] theorem card_embedding_eq_of_infinite {α β : Type*} [Infinite α] [Fintype β] [Fintype (α ↪ β)] : ‖α ↪ β‖ = 0 := card_eq_zero diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index d7ec3228f0c00..db3d3aaf1aaf2 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -286,11 +286,6 @@ protected theorem toFinset_compl [DecidableEq α] [Fintype α] (hs : s.Finite) ( simp #align set.finite.to_finset_compl Set.Finite.toFinset_compl --- porting note: was `@[simp]`, now `simp` can prove it -protected theorem toFinset_empty (h : (∅ : Set α).Finite) : h.toFinset = ∅ := - toFinite_toFinset _ -#align set.finite.to_finset_empty Set.Finite.toFinset_empty - protected theorem toFinset_univ [Fintype α] (h : (Set.univ : Set α).Finite) : h.toFinset = Finset.univ := by simp @@ -301,6 +296,10 @@ protected theorem toFinset_eq_empty {h : s.Finite} : h.toFinset = ∅ ↔ s = @toFinset_eq_empty _ _ h.fintype #align set.finite.to_finset_eq_empty Set.Finite.toFinset_eq_empty +protected theorem toFinset_empty (h : (∅ : Set α).Finite) : h.toFinset = ∅ := by + simp +#align set.finite.to_finset_empty Set.Finite.toFinset_empty + @[simp] protected theorem toFinset_eq_univ [Fintype α] {h : s.Finite} : h.toFinset = Finset.univ ↔ s = univ := @@ -1237,9 +1236,8 @@ theorem empty_card : Fintype.card (∅ : Set α) = 0 := rfl #align set.empty_card Set.empty_card -@[simp] theorem empty_card' {h : Fintype.{u} (∅ : Set α)} : @Fintype.card (∅ : Set α) h = 0 := - Eq.trans (by congr; exact Subsingleton.elim _ _) empty_card + by simp #align set.empty_card' Set.empty_card' theorem card_fintypeInsertOfNotMem {a : α} (s : Set α) [Fintype s] (h : a ∉ s) : diff --git a/Mathlib/LinearAlgebra/Orientation.lean b/Mathlib/LinearAlgebra/Orientation.lean index 3a2c45063f181..7caee38d5b01a 100644 --- a/Mathlib/LinearAlgebra/Orientation.lean +++ b/Mathlib/LinearAlgebra/Orientation.lean @@ -410,9 +410,7 @@ theorem map_eq_iff_det_pos (x : Orientation R M ι) (f : M ≃ₗ[R] M) (h : Fintype.card ι = finrank R M) : Orientation.map ι f x = x ↔ 0 < LinearMap.det (f : M →ₗ[R] M) := by cases isEmpty_or_nonempty ι - · have H : finrank R M = 0 := by - refine' h.symm.trans _ - convert @Fintype.card_of_isEmpty ι _ + · have H : finrank R M = 0 := h.symm.trans Fintype.card_eq_zero simp [LinearMap.det_eq_one_of_finrank_eq_zero H] rw [map_eq_det_inv_smul _ _ h, units_inv_smul, units_smul_eq_self_iff, LinearEquiv.coe_det] #align orientation.map_eq_iff_det_pos Orientation.map_eq_iff_det_pos @@ -424,9 +422,7 @@ theorem map_eq_neg_iff_det_neg (x : Orientation R M ι) (f : M ≃ₗ[R] M) (h : Fintype.card ι = finrank R M) : Orientation.map ι f x = -x ↔ LinearMap.det (f : M →ₗ[R] M) < 0 := by cases isEmpty_or_nonempty ι - · have H : finrank R M = 0 := by - refine' h.symm.trans _ - convert @Fintype.card_of_isEmpty ι _ + · have H : finrank R M = 0 := h.symm.trans Fintype.card_eq_zero simp [LinearMap.det_eq_one_of_finrank_eq_zero H, Module.Ray.ne_neg_self x] have H : 0 < finrank R M := by rw [← h] diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index 07b37c5bd9770..45958c43a77d1 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -1334,7 +1334,7 @@ theorem measurableSet_of_mem_nhdsWithin_Ioi {s : Set α} (h : ∀ x ∈ s, s ∈ lemma measurableSet_bddAbove_range {ι} [Countable ι] {f : ι → δ → α} (hf : ∀ i, Measurable (f i)) : MeasurableSet {b | BddAbove (range (fun i ↦ f i b))} := by rcases isEmpty_or_nonempty α with hα|hα - · have : ∀ b, range (fun i ↦ f i b) = ∅ := fun b ↦ Iff.mp toFinset_eq_empty rfl + · have : ∀ b, range (fun i ↦ f i b) = ∅ := fun b ↦ eq_empty_of_isEmpty _ simp [this] have A : ∀ (i : ι) (c : α), MeasurableSet {x | f i x ≤ c} := by intro i c diff --git a/Mathlib/MeasureTheory/Constructions/Pi.lean b/Mathlib/MeasureTheory/Constructions/Pi.lean index 291aa15ea12b8..6e6367e19080c 100644 --- a/Mathlib/MeasureTheory/Constructions/Pi.lean +++ b/Mathlib/MeasureTheory/Constructions/Pi.lean @@ -412,8 +412,9 @@ instance {α : ι → Type*} [∀ i, MeasureSpace (α i)] [∀ i, SigmaFinite (v SigmaFinite (volume : Measure (∀ i, α i)) := pi.sigmaFinite _ -theorem pi_of_empty {α : Type*} [IsEmpty α] {β : α → Type*} {m : ∀ a, MeasurableSpace (β a)} - (μ : ∀ a : α, Measure (β a)) (x : ∀ a, β a := isEmptyElim) : Measure.pi μ = dirac x := by +theorem pi_of_empty {α : Type*} [Fintype α] [IsEmpty α] {β : α → Type*} + {m : ∀ a, MeasurableSpace (β a)} (μ : ∀ a : α, Measure (β a)) (x : ∀ a, β a := isEmptyElim) : + Measure.pi μ = dirac x := by haveI : ∀ a, SigmaFinite (μ a) := isEmptyElim refine' pi_eq fun s _ => _ rw [Fintype.prod_empty, dirac_apply_of_mem] @@ -421,17 +422,16 @@ theorem pi_of_empty {α : Type*} [IsEmpty α] {β : α → Type*} {m : ∀ a, Me #align measure_theory.measure.pi_of_empty MeasureTheory.Measure.pi_of_empty @[simp] -theorem pi_empty_univ {α : Type*} {β : α → Type*} [IsEmpty α] {m : ∀ α, MeasurableSpace (β α)} - (μ : ∀ a : α, Measure (β a)) : Measure.pi μ (Set.univ) = 1 := by - rw [pi_of_empty, measure_univ] +theorem pi_empty_univ {α : Type*} [Fintype α] [IsEmpty α] {β : α → Type*} + {m : ∀ α, MeasurableSpace (β α)} (μ : ∀ a : α, Measure (β a)) : + Measure.pi μ (Set.univ) = 1 := by + rw [pi_of_empty, measure_univ] theorem pi_eval_preimage_null {i : ι} {s : Set (α i)} (hs : μ i s = 0) : Measure.pi μ (eval i ⁻¹' s) = 0 := by -- WLOG, `s` is measurable rcases exists_measurable_superset_of_null hs with ⟨t, hst, _, hμt⟩ - suffices : Measure.pi μ (eval i ⁻¹' t) = 0 - exact measure_mono_null (preimage_mono hst) this - clear! s + suffices Measure.pi μ (eval i ⁻¹' t) = 0 from measure_mono_null (preimage_mono hst) this -- Now rewrite it as `Set.pi`, and apply `pi_pi` rw [← univ_pi_update_univ, pi_pi] apply Finset.prod_eq_zero (Finset.mem_univ i) @@ -874,7 +874,7 @@ theorem volume_preserving_finTwoArrow (α : Type u) [MeasureSpace α] measurePreserving_finTwoArrow volume #align measure_theory.volume_preserving_fin_two_arrow MeasureTheory.volume_preserving_finTwoArrow -theorem measurePreserving_pi_empty {ι : Type u} {α : ι → Type v} [IsEmpty ι] +theorem measurePreserving_pi_empty {ι : Type u} {α : ι → Type v} [Fintype ι] [IsEmpty ι] {m : ∀ i, MeasurableSpace (α i)} (μ : ∀ i, Measure (α i)) : MeasurePreserving (MeasurableEquiv.ofUniqueOfUnique (∀ i, α i) Unit) (Measure.pi μ) (Measure.dirac ()) := by @@ -883,7 +883,7 @@ theorem measurePreserving_pi_empty {ι : Type u} {α : ι → Type v} [IsEmpty rw [Measure.pi_of_empty, Measure.map_dirac e.measurable] #align measure_theory.measure_preserving_pi_empty MeasureTheory.measurePreserving_pi_empty -theorem volume_preserving_pi_empty {ι : Type u} (α : ι → Type v) [IsEmpty ι] +theorem volume_preserving_pi_empty {ι : Type u} (α : ι → Type v) [Fintype ι] [IsEmpty ι] [∀ i, MeasureSpace (α i)] : MeasurePreserving (MeasurableEquiv.ofUniqueOfUnique (∀ i, α i) Unit) volume volume := measurePreserving_pi_empty fun _ => volume diff --git a/Mathlib/ModelTheory/Basic.lean b/Mathlib/ModelTheory/Basic.lean index bd65a19d64dd6..24b4de9f95466 100644 --- a/Mathlib/ModelTheory/Basic.lean +++ b/Mathlib/ModelTheory/Basic.lean @@ -96,7 +96,7 @@ theorem lift_mk {i : ℕ} : Cardinal.lift.{v,u} #(Sequence₂ a₀ a₁ a₂ i) = #(Sequence₂ (ULift.{v,u} a₀) (ULift.{v,u} a₁) (ULift.{v,u} a₂) i) := by rcases i with (_ | _ | _ | i) <;> - simp only [Sequence₂, mk_uLift, mk_fintype, Fintype.card_of_isEmpty, Nat.cast_zero, lift_zero] + simp only [Sequence₂, mk_uLift, mk_fintype, Nat.cast_zero, lift_zero, Fintype.card_pempty] #align first_order.sequence₂.lift_mk FirstOrder.Sequence₂.lift_mk @[simp] diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index 946dc432dad93..e5295e1cb16d4 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -379,6 +379,7 @@ instance : Zero Cardinal.{u} := instance : Inhabited Cardinal.{u} := ⟨0⟩ +@[simp] theorem mk_eq_zero (α : Type u) [IsEmpty α] : #α = 0 := (Equiv.equivOfIsEmpty α (ULift (Fin 0))).cardinal_eq #align cardinal.mk_eq_zero Cardinal.mk_eq_zero diff --git a/Mathlib/SetTheory/Cardinal/Cofinality.lean b/Mathlib/SetTheory/Cardinal/Cofinality.lean index 43a6de2953e97..b5b10eacecd20 100644 --- a/Mathlib/SetTheory/Cardinal/Cofinality.lean +++ b/Mathlib/SetTheory/Cardinal/Cofinality.lean @@ -923,8 +923,7 @@ theorem mk_bounded_subset {α : Type*} (h : ∀ x < #α, (2^x) < #α) {r : α theorem mk_subset_mk_lt_cof {α : Type*} (h : ∀ x < #α, (2^x) < #α) : #{ s : Set α // #s < cof (#α).ord } = #α := by rcases eq_or_ne #α 0 with (ha | ha) - · rw [ha] - simp [fun s => (Cardinal.zero_le s).not_lt] + · simp [ha] have h' : IsStrongLimit #α := ⟨ha, h⟩ rcases ord_eq α with ⟨r, wo, hr⟩ haveI := wo diff --git a/Mathlib/SetTheory/Cardinal/Finite.lean b/Mathlib/SetTheory/Cardinal/Finite.lean index 01af4796a066e..b3792c298db08 100644 --- a/Mathlib/SetTheory/Cardinal/Finite.lean +++ b/Mathlib/SetTheory/Cardinal/Finite.lean @@ -42,7 +42,6 @@ theorem card_eq_fintype_card [Fintype α] : Nat.card α = Fintype.card α := mk_toNat_eq_card #align nat.card_eq_fintype_card Nat.card_eq_fintype_card -lemma card_eq_zero_of_isEmpty [IsEmpty α] : Nat.card α = 0 := by simp [Nat.card] @[simp] lemma card_eq_zero_of_infinite [Infinite α] : Nat.card α = 0 := mk_toNat_of_infinite #align nat.card_eq_zero_of_infinite Nat.card_eq_zero_of_infinite @@ -117,7 +116,7 @@ theorem card_eq_two_iff' (x : α) : Nat.card α = 2 ↔ ∃! y, y ≠ x := toNat_eq_ofNat.trans (mk_eq_two_iff' x) #align nat.card_eq_two_iff' Nat.card_eq_two_iff' -theorem card_of_isEmpty [IsEmpty α] : Nat.card α = 0 := by simp +@[simp] theorem card_of_isEmpty [IsEmpty α] : Nat.card α = 0 := by simp [Nat.card] #align nat.card_of_is_empty Nat.card_of_isEmpty @[simp] diff --git a/Mathlib/SetTheory/Game/Short.lean b/Mathlib/SetTheory/Game/Short.lean index 353e43f87ddaa..b44cac9bc0f95 100644 --- a/Mathlib/SetTheory/Game/Short.lean +++ b/Mathlib/SetTheory/Game/Short.lean @@ -169,8 +169,10 @@ theorem short_birthday (x : PGame.{u}) : [Short x] → x.birthday < Ordinal.omeg #align pgame.short_birthday SetTheory.PGame.short_birthday /-- This leads to infinite loops if made into an instance. -/ -def Short.ofIsEmpty {l r xL xR} [IsEmpty l] [IsEmpty r] : Short (PGame.mk l r xL xR) := - Short.mk isEmptyElim isEmptyElim +def Short.ofIsEmpty {l r xL xR} [IsEmpty l] [IsEmpty r] : Short (PGame.mk l r xL xR) := by + have : Fintype l := Fintype.ofIsEmpty + have : Fintype r := Fintype.ofIsEmpty + exact Short.mk isEmptyElim isEmptyElim #align pgame.short.of_is_empty SetTheory.PGame.Short.ofIsEmpty instance short0 : Short 0 := From 302fdbb80c235204e331292512b168f3cc423fe8 Mon Sep 17 00:00:00 2001 From: Andrew Yang <36414270+erdOne@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:58:57 +0000 Subject: [PATCH 057/353] chore: Generalize results on `finrank` to rings. (#8912) A portion of results in `Mathlib/LinearAlgebra/FiniteDimensional.lean` were generalized to rings and moved to `Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean`. Most API lemmas for `FiniteDimensional` are kept but replaced with one lemma proofs. Definitions and niche lemmas are replaced by the generalized version completely. Co-authored-by: erd1 Co-authored-by: Andrew Yang --- .../InnerProductSpace/Projection.lean | 3 +- .../Analysis/InnerProductSpace/l2Space.lean | 3 +- Mathlib/LinearAlgebra/Dimension.lean | 63 ++- Mathlib/LinearAlgebra/Dual.lean | 2 +- .../Eigenspace/Triangularizable.lean | 2 +- Mathlib/LinearAlgebra/FiniteDimensional.lean | 384 ++------------ .../FreeModule/Finite/Basic.lean | 12 +- .../LinearAlgebra/FreeModule/Finite/Rank.lean | 500 +++++++++++++++++- .../Measure/Lebesgue/EqHaar.lean | 2 +- Mathlib/RingTheory/Finiteness.lean | 5 + Mathlib/Topology/Algebra/Module/Basic.lean | 3 + .../Algebra/Module/FiniteDimension.lean | 4 +- 12 files changed, 610 insertions(+), 373 deletions(-) diff --git a/Mathlib/Analysis/InnerProductSpace/Projection.lean b/Mathlib/Analysis/InnerProductSpace/Projection.lean index d5c66fa74ff05..fae9a45834782 100644 --- a/Mathlib/Analysis/InnerProductSpace/Projection.lean +++ b/Mathlib/Analysis/InnerProductSpace/Projection.lean @@ -1190,7 +1190,8 @@ theorem LinearIsometryEquiv.reflections_generate_dim_aux [FiniteDimensional ℝ · -- Base case: `n = 0`, the fixed subspace is the whole space, so `φ = id` refine' ⟨[], rfl.le, show φ = 1 from _⟩ have : ker (ContinuousLinearMap.id ℝ F - φ) = ⊤ := by - rwa [Nat.zero_eq, le_zero_iff, finrank_eq_zero, Submodule.orthogonal_eq_bot_iff] at hn + rwa [Nat.zero_eq, le_zero_iff, Submodule.finrank_eq_zero, + Submodule.orthogonal_eq_bot_iff] at hn symm ext x have := LinearMap.congr_fun (LinearMap.ker_eq_top.mp this) x diff --git a/Mathlib/Analysis/InnerProductSpace/l2Space.lean b/Mathlib/Analysis/InnerProductSpace/l2Space.lean index 32bae3a00162f..2b4a47b2e7dd9 100644 --- a/Mathlib/Analysis/InnerProductSpace/l2Space.lean +++ b/Mathlib/Analysis/InnerProductSpace/l2Space.lean @@ -584,7 +584,8 @@ theorem _root_.Orthonormal.exists_hilbertBasis_extension {s : Set E} ∃ (w : Set E) (b : HilbertBasis w 𝕜 E), s ⊆ w ∧ ⇑b = ((↑) : w → E) := let ⟨w, hws, hw_ortho, hw_max⟩ := exists_maximal_orthonormal hs ⟨w, HilbertBasis.mkOfOrthogonalEqBot hw_ortho - (by simpa [maximal_orthonormal_iff_orthogonalComplement_eq_bot hw_ortho] using hw_max), + (by simpa only [Subtype.range_coe_subtype, Set.setOf_mem_eq, + maximal_orthonormal_iff_orthogonalComplement_eq_bot hw_ortho] using hw_max), hws, HilbertBasis.coe_mkOfOrthogonalEqBot _ _⟩ #align orthonormal.exists_hilbert_basis_extension Orthonormal.exists_hilbertBasis_extension diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean index facbf8108c688..ce91bab259f73 100644 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ b/Mathlib/LinearAlgebra/Dimension.lean @@ -5,6 +5,7 @@ Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison -/ import Mathlib.Algebra.Module.BigOperators import Mathlib.LinearAlgebra.Basis.VectorSpace +import Mathlib.Algebra.Module.Torsion import Mathlib.LinearAlgebra.DFinsupp import Mathlib.LinearAlgebra.FreeModule.Basic import Mathlib.LinearAlgebra.InvariantBasisNumber @@ -78,7 +79,7 @@ noncomputable section universe u v v' v'' u₁' w w' -variable {K : Type u} {V V₁ V₂ V₃ : Type v} {V' V'₁ : Type v'} {V'' : Type v''} +variable {K R : Type u} {V V₁ V₂ V₃ : Type v} {V' V'₁ : Type v'} {V'' : Type v''} variable {ι : Type w} {ι' : Type w'} {η : Type u₁'} {φ : η → Type*} @@ -102,8 +103,6 @@ this is the same as the dimension of the space (i.e. the cardinality of any basi In particular this agrees with the usual notion of the dimension of a vector space. -The definition is marked as protected to avoid conflicts with `_root_.rank`, -the rank of a linear map. -/ protected irreducible_def Module.rank : Cardinal := ⨆ ι : { s : Set V // LinearIndependent K ((↑) : s → V) }, (#ι.1) @@ -113,7 +112,7 @@ end section -variable {R : Type u} [Ring R] +variable [Ring R] variable {M : Type v} [AddCommGroup M] [Module R M] @@ -471,7 +470,7 @@ variable {R : Type u} {M : Type v} variable [Ring R] [AddCommGroup M] [Module R M] -@[simp] +@[nontriviality, simp] theorem rank_subsingleton [Subsingleton R] : Module.rank R M = 1 := by haveI := Module.subsingleton R M have : Nonempty { s : Set M // LinearIndependent R ((↑) : s → M) } := @@ -513,7 +512,35 @@ theorem rank_zero_iff_forall_zero : Module.rank R M = 0 ↔ ∀ x : M, x = 0 := rw [← rank_top, this, rank_bot] #align rank_zero_iff_forall_zero rank_zero_iff_forall_zero -/-- See `rank_subsingleton` for the reason that `Nontrivial R` is needed. -/ +/-- See `rank_zero_iff` for a stronger version with `NoZeroSMulDivisor R M`. -/ +lemma rank_eq_zero_iff {R M} [Ring R] [AddCommGroup M] [Module R M] : + Module.rank R M = 0 ↔ ∀ x : M, ∃ a : R, a ≠ 0 ∧ a • x = 0 := by + nontriviality R + constructor + · contrapose! + rintro ⟨x, hx⟩ + rw [← Cardinal.one_le_iff_ne_zero] + have : LinearIndependent R (fun _ : Unit ↦ x) + · exact linearIndependent_iff.mpr (fun l hl ↦ Finsupp.unique_ext <| not_not.mp fun H ↦ + hx _ H ((Finsupp.total_unique _ _ _).symm.trans hl)) + simpa using cardinal_lift_le_rank_of_linearIndependent this + · intro h + rw [← le_zero_iff, Module.rank_def] + apply ciSup_le' + intro ⟨s, hs⟩ + rw [nonpos_iff_eq_zero, Cardinal.mk_eq_zero_iff, ← not_nonempty_iff] + rintro ⟨i : s⟩ + obtain ⟨a, ha, ha'⟩ := h i + apply ha + simpa using FunLike.congr_fun (linearIndependent_iff.mp hs (Finsupp.single i a) (by simpa)) i + +lemma rank_eq_zero_iff_isTorsion {R M} [CommRing R] [IsDomain R] [AddCommGroup M] [Module R M] : + Module.rank R M = 0 ↔ Module.IsTorsion R M := by + rw [Module.IsTorsion, rank_eq_zero_iff] + simp [mem_nonZeroDivisors_iff_ne_zero] + +/-- See `rank_subsingleton` for the reason that `Nontrivial R` is needed. +Also see `rank_eq_zero_iff` for the version without `NoZeroSMulDivisor R M`. -/ theorem rank_zero_iff : Module.rank R M = 0 ↔ Subsingleton M := rank_zero_iff_forall_zero.trans (subsingleton_iff_forall_eq 0).symm #align rank_zero_iff rank_zero_iff @@ -1071,9 +1098,9 @@ end Free section DivisionRing -variable [DivisionRing K] +variable [DivisionRing K] [Ring R] [StrongRankCondition R] -variable [AddCommGroup V] [Module K V] +variable [AddCommGroup V] [Module K V] [Module R V] variable [AddCommGroup V'] [Module K V'] @@ -1086,19 +1113,25 @@ theorem Basis.finite_ofVectorSpaceIndex_of_rank_lt_aleph0 (h : Module.rank K V < #align basis.finite_of_vector_space_index_of_rank_lt_aleph_0 Basis.finite_ofVectorSpaceIndex_of_rank_lt_aleph0 -- TODO how far can we generalise this? --- When `s` is finite, we could prove this for any ring satisfying the strong rank condition --- using `linearIndependent_le_span'` theorem rank_span_le (s : Set V) : Module.rank K (span K s) ≤ #s := by obtain ⟨b, hb, hsab, hlib⟩ := exists_linearIndependent K s convert Cardinal.mk_le_mk_of_subset hb rw [← hsab, rank_span_set hlib] #align rank_span_le rank_span_le -theorem rank_span_of_finset (s : Finset V) : Module.rank K (span K (↑s : Set V)) < ℵ₀ := - calc - Module.rank K (span K (↑s : Set V)) ≤ #(↑s : Set V) := rank_span_le (s : Set V) - _ = s.card := by rw [Finset.coe_sort_coe, Cardinal.mk_coe_finset] - _ < ℵ₀ := Cardinal.nat_lt_aleph0 _ +theorem rank_span_le_of_finite {s : Set V} (hs : s.Finite) : Module.rank R (span R s) ≤ #s := by + rw [Module.rank_def] + apply ciSup_le' + rintro ⟨t, ht⟩ + letI := hs.fintype + simpa [Cardinal.mk_image_eq Subtype.val_injective] using linearIndependent_le_span' _ + (ht.map (f := Submodule.subtype _) (by simp)).image s (fun x ↦ by aesop) + +theorem rank_span_finset_le (s : Finset V) : Module.rank R (span R (s : Set V)) ≤ s.card := by + simpa using rank_span_le_of_finite s.finite_toSet + +theorem rank_span_of_finset (s : Finset V) : Module.rank R (span R (s : Set V)) < ℵ₀ := + (rank_span_finset_le s).trans_lt (Cardinal.nat_lt_aleph0 _) #align rank_span_of_finset rank_span_of_finset theorem rank_quotient_add_rank (p : Submodule K V) : diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 3d7b2b16f3151..21caf4bfb3d3d 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -1586,7 +1586,7 @@ theorem dualMap_injective_iff {f : V₁ →ₗ[K] V₂} : rw [← range_eq_top, ← ker_eq_bot] intro h apply Submodule.eq_top_of_finrank_eq - rw [← finrank_eq_zero] at h + rw [← Submodule.finrank_eq_zero] at h rw [← add_zero (FiniteDimensional.finrank K <| LinearMap.range f), ← h, ← LinearMap.finrank_range_dualMap_eq_finrank_range, LinearMap.finrank_range_add_finrank_ker, Subspace.dual_finrank_eq] diff --git a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean index 8fcfe34337fcd..ae3280cadf923 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean @@ -68,7 +68,7 @@ theorem iSup_generalizedEigenspace_eq_top [IsAlgClosed K] [FiniteDimensional K V cases' n with n -- If the vector space is 0-dimensional, the result is trivial. · rw [← top_le_iff] - simp only [finrank_eq_zero.1 (Eq.trans (finrank_top _ _) h_dim), bot_le] + simp only [Submodule.finrank_eq_zero.1 (Eq.trans (finrank_top _ _) h_dim), bot_le] -- Otherwise the vector space is nontrivial. · haveI : Nontrivial V := finrank_pos_iff.1 (by rw [h_dim]; apply Nat.zero_lt_succ) -- Hence, `f` has an eigenvalue `μ₀`. diff --git a/Mathlib/LinearAlgebra/FiniteDimensional.lean b/Mathlib/LinearAlgebra/FiniteDimensional.lean index fbfc8ffe2d1df..098d690e09217 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean @@ -67,13 +67,8 @@ in `Mathlib.LinearAlgebra.Dimension`. Not all results have been ported yet. You should not assume that there has been any effort to state lemmas as generally as possible. -One of the characterizations of finite-dimensionality is in terms of finite generation. This -property is currently defined only for submodules, so we express it through the fact that the -maximal submodule (which, as a set, coincides with the whole space) is finitely generated. This is -not very convenient to use, although there are some helper functions. However, this becomes very -convenient when speaking of submodules which are finite-dimensional, as this notion coincides with -the fact that the submodule is finitely generated (as a submodule of the whole space). This -equivalence is proved in `Submodule.fg_iff_finiteDimensional`. +Plenty of the results hold for general fg modules or notherian modules, and they can be found in +`Mathlib.LinearAlgebra.FreeModule.Finite.Rank` and `Mathlib.RingTheory.Noetherian`. -/ @@ -115,13 +110,12 @@ theorem of_surjective (f : V →ₗ[K] V₂) (w : Function.Surjective f) [Finite variable (K V) instance finiteDimensional_pi {ι : Type*} [Finite ι] : FiniteDimensional K (ι → K) := - iff_fg.1 isNoetherian_pi + Finite.pi #align finite_dimensional.finite_dimensional_pi FiniteDimensional.finiteDimensional_pi instance finiteDimensional_pi' {ι : Type*} [Finite ι] (M : ι → Type*) [∀ i, AddCommGroup (M i)] - [∀ i, Module K (M i)] [I : ∀ i, FiniteDimensional K (M i)] : FiniteDimensional K (∀ i, M i) := - haveI : ∀ i : ι, IsNoetherian K (M i) := fun i => iff_fg.2 (I i) - iff_fg.1 isNoetherian_pi + [∀ i, Module K (M i)] [∀ i, FiniteDimensional K (M i)] : FiniteDimensional K (∀ i, M i) := + Finite.pi #align finite_dimensional.finite_dimensional_pi' FiniteDimensional.finiteDimensional_pi' /-- A finite dimensional vector space over a finite field is finite -/ @@ -138,19 +132,14 @@ theorem finite_of_finite [Finite K] [FiniteDimensional K V] : Finite V := by variable {K V} /-- If a vector space has a finite basis, then it is finite-dimensional. -/ -theorem of_fintype_basis {ι : Type w} [Finite ι] (h : Basis ι K V) : FiniteDimensional K V := by - classical - cases nonempty_fintype ι - exact ⟨⟨Finset.univ.image h, by - convert h.span_eq - simp⟩⟩ +theorem of_fintype_basis {ι : Type w} [Finite ι] (h : Basis ι K V) : FiniteDimensional K V := + Module.Finite.of_basis h #align finite_dimensional.of_fintype_basis FiniteDimensional.of_fintype_basis /-- If a vector space is `FiniteDimensional`, all bases are indexed by a finite type -/ noncomputable def fintypeBasisIndex {ι : Type*} [FiniteDimensional K V] (b : Basis ι K V) : Fintype ι := - letI : IsNoetherian K V := IsNoetherian.iff_fg.2 inferInstance - IsNoetherian.fintypeBasisIndex b + @Fintype.ofFinite _ (Module.Free.finite_basis b) #align finite_dimensional.fintype_basis_index FiniteDimensional.fintypeBasisIndex /-- If a vector space is `FiniteDimensional`, `Basis.ofVectorSpace` is indexed by @@ -181,7 +170,7 @@ instance finiteDimensional_submodule [FiniteDimensional K V] (S : Submodule K V) /-- A quotient of a finite-dimensional space is also finite-dimensional. -/ instance finiteDimensional_quotient [FiniteDimensional K V] (S : Submodule K V) : FiniteDimensional K (V ⧸ S) := - Module.Finite.of_surjective (Submodule.mkQ S) <| surjective_quot_mk _ + Module.Finite.quotient K S #align finite_dimensional.finite_dimensional_quotient FiniteDimensional.finiteDimensional_quotient variable (K V) @@ -195,152 +184,43 @@ theorem finrank_eq_rank' [FiniteDimensional K V] : (finrank K V : Cardinal.{v}) variable {K V} theorem finrank_of_infinite_dimensional (h : ¬FiniteDimensional K V) : finrank K V = 0 := - dif_neg <| mt IsNoetherian.iff_rank_lt_aleph0.2 <| (not_iff_not.2 iff_fg).2 h + FiniteDimensional.finrank_of_not_finite h #align finite_dimensional.finrank_of_infinite_dimensional FiniteDimensional.finrank_of_infinite_dimensional -theorem finiteDimensional_of_finrank (h : 0 < finrank K V) : FiniteDimensional K V := by - contrapose h - simp [finrank_of_infinite_dimensional h] +theorem finiteDimensional_of_finrank (h : 0 < finrank K V) : FiniteDimensional K V := + Module.finite_of_finrank_pos h #align finite_dimensional.finite_dimensional_of_finrank FiniteDimensional.finiteDimensional_of_finrank theorem finiteDimensional_of_finrank_eq_succ {n : ℕ} (hn : finrank K V = n.succ) : FiniteDimensional K V := - finiteDimensional_of_finrank <| by rw [hn]; exact n.succ_pos + Module.finite_of_finrank_eq_succ hn #align finite_dimensional.finite_dimensional_of_finrank_eq_succ FiniteDimensional.finiteDimensional_of_finrank_eq_succ /-- We can infer `FiniteDimensional K V` in the presence of `[Fact (finrank K V = n + 1)]`. Declare this as a local instance where needed. -/ -theorem fact_finiteDimensional_of_finrank_eq_succ (n : ℕ) [Fact (finrank K V = n + 1)] : +theorem fact_finiteDimensional_of_finrank_eq_succ (n : ℕ) [hn : Fact (finrank K V = n + 1)] : FiniteDimensional K V := - finiteDimensional_of_finrank <| by convert Nat.succ_pos n; apply Fact.out + finiteDimensional_of_finrank_eq_succ hn.out #align finite_dimensional.fact_finite_dimensional_of_finrank_eq_succ FiniteDimensional.fact_finiteDimensional_of_finrank_eq_succ theorem finiteDimensional_iff_of_rank_eq_nsmul {W} [AddCommGroup W] [Module K W] {n : ℕ} (hn : n ≠ 0) (hVW : Module.rank K V = n • Module.rank K W) : - FiniteDimensional K V ↔ FiniteDimensional K W := by - simp only [FiniteDimensional, ← IsNoetherian.iff_fg, IsNoetherian.iff_rank_lt_aleph0, hVW, - Cardinal.nsmul_lt_aleph0_iff_of_ne_zero hn] + FiniteDimensional K V ↔ FiniteDimensional K W := + Module.finite_iff_of_rank_eq_nsmul hn hVW #align finite_dimensional.finite_dimensional_iff_of_rank_eq_nsmul FiniteDimensional.finiteDimensional_iff_of_rank_eq_nsmul /-- If a vector space is finite-dimensional, then the cardinality of any basis is equal to its `finrank`. -/ theorem finrank_eq_card_basis' [FiniteDimensional K V] {ι : Type w} (h : Basis ι K V) : - (finrank K V : Cardinal.{w}) = #ι := by - haveI : IsNoetherian K V := iff_fg.2 inferInstance - haveI : Fintype ι := fintypeBasisIndex h - rw [Cardinal.mk_fintype, finrank_eq_card_basis h] + (finrank K V : Cardinal.{w}) = #ι := + Module.mk_finrank_eq_card_basis h #align finite_dimensional.finrank_eq_card_basis' FiniteDimensional.finrank_eq_card_basis' -/-- Given a basis of a division ring over itself indexed by a type `ι`, then `ι` is `Unique`. -/ -noncomputable def _root_.Basis.unique {ι : Type*} (b : Basis ι K K) : Unique ι := by - have A : Cardinal.mk ι = ↑(FiniteDimensional.finrank K K) := - (FiniteDimensional.finrank_eq_card_basis' b).symm - -- porting note: replace `algebraMap.coe_one` with `Nat.cast_one` - simp only [Cardinal.eq_one_iff_unique, FiniteDimensional.finrank_self, Nat.cast_one] at A - exact Nonempty.some ((unique_iff_subsingleton_and_nonempty _).2 A) -#align basis.unique Basis.unique - -variable (K V) - -/-- A finite dimensional vector space has a basis indexed by `Fin (finrank K V)`. -/ -noncomputable def finBasis [FiniteDimensional K V] : Basis (Fin (finrank K V)) K V := - have h : Fintype.card (@finsetBasisIndex K V _ _ _ (iff_fg.2 inferInstance)) = finrank K V := - (finrank_eq_card_basis (@finsetBasis K V _ _ _ (iff_fg.2 inferInstance))).symm - (@finsetBasis K V _ _ _ (iff_fg.2 inferInstance)).reindex (Fintype.equivFinOfCardEq h) -#align finite_dimensional.fin_basis FiniteDimensional.finBasis - -/-- An `n`-dimensional vector space has a basis indexed by `Fin n`. -/ -noncomputable def finBasisOfFinrankEq [FiniteDimensional K V] {n : ℕ} (hn : finrank K V = n) : - Basis (Fin n) K V := - (finBasis K V).reindex (Fin.castIso hn).toEquiv -#align finite_dimensional.fin_basis_of_finrank_eq FiniteDimensional.finBasisOfFinrankEq - -variable {K V} - -/-- A module with dimension 1 has a basis with one element. -/ -noncomputable def basisUnique (ι : Type*) [Unique ι] (h : finrank K V = 1) : Basis ι K V := - haveI : FiniteDimensional _ _ := - finiteDimensional_of_finrank (_root_.zero_lt_one.trans_le h.symm.le) - (finBasisOfFinrankEq K V h).reindex (Equiv.equivOfUnique _ _) -#align finite_dimensional.basis_unique FiniteDimensional.basisUnique - -@[simp] -theorem basisUnique.repr_eq_zero_iff {ι : Type*} [Unique ι] {h : finrank K V = 1} {v : V} {i : ι} : - (basisUnique ι h).repr v i = 0 ↔ v = 0 := - ⟨fun hv => - (basisUnique ι h).repr.map_eq_zero_iff.mp (Finsupp.ext fun j => Subsingleton.elim i j ▸ hv), - fun hv => by rw [hv, LinearEquiv.map_zero, Finsupp.zero_apply]⟩ -#align finite_dimensional.basis_unique.repr_eq_zero_iff FiniteDimensional.basisUnique.repr_eq_zero_iff - -theorem cardinal_mk_le_finrank_of_linearIndependent [FiniteDimensional K V] {ι : Type w} {b : ι → V} - (h : LinearIndependent K b) : #ι ≤ finrank K V := by - rw [← lift_le.{max v w}] - simpa [← finrank_eq_rank', -finrank_eq_rank] using - cardinal_lift_le_rank_of_linearIndependent h -#align finite_dimensional.cardinal_mk_le_finrank_of_linear_independent FiniteDimensional.cardinal_mk_le_finrank_of_linearIndependent - -theorem fintype_card_le_finrank_of_linearIndependent [FiniteDimensional K V] {ι : Type*} - [Fintype ι] {b : ι → V} (h : LinearIndependent K b) : Fintype.card ι ≤ finrank K V := by - simpa using cardinal_mk_le_finrank_of_linearIndependent h -#align finite_dimensional.fintype_card_le_finrank_of_linear_independent FiniteDimensional.fintype_card_le_finrank_of_linearIndependent - -theorem finset_card_le_finrank_of_linearIndependent [FiniteDimensional K V] {b : Finset V} - (h : LinearIndependent K (fun x => x : b → V)) : b.card ≤ finrank K V := by - rw [← Fintype.card_coe] - exact fintype_card_le_finrank_of_linearIndependent h -#align finite_dimensional.finset_card_le_finrank_of_linear_independent FiniteDimensional.finset_card_le_finrank_of_linearIndependent - theorem lt_aleph0_of_linearIndependent {ι : Type w} [FiniteDimensional K V] {v : ι → V} - (h : LinearIndependent K v) : #ι < ℵ₀ := by - apply Cardinal.lift_lt.1 - apply lt_of_le_of_lt - apply cardinal_lift_le_rank_of_linearIndependent h - rw [← finrank_eq_rank, Cardinal.lift_aleph0, Cardinal.lift_natCast] - apply Cardinal.nat_lt_aleph0 + (h : LinearIndependent K v) : #ι < ℵ₀ := + Module.Finite.lt_aleph0_of_linearIndependent h #align finite_dimensional.lt_aleph_0_of_linear_independent FiniteDimensional.lt_aleph0_of_linearIndependent -lemma _root_.LinearIndependent.finite {ι : Type*} [FiniteDimensional K V] {f : ι → V} - (h : LinearIndependent K f) : Finite ι := - Cardinal.lt_aleph0_iff_finite.1 <| FiniteDimensional.lt_aleph0_of_linearIndependent h - -theorem not_linearIndependent_of_infinite {ι : Type*} [Infinite ι] [FiniteDimensional K V] - (v : ι → V) : ¬LinearIndependent K v := mt LinearIndependent.finite <| @not_finite _ _ -#align finite_dimensional.not_linear_independent_of_infinite FiniteDimensional.not_linearIndependent_of_infinite - -theorem _root_.LinearIndependent.setFinite [FiniteDimensional K V] {b : Set V} - (h : LinearIndependent K fun x : b => (x : V)) : b.Finite := - Cardinal.lt_aleph0_iff_set_finite.mp (FiniteDimensional.lt_aleph0_of_linearIndependent h) -#align linear_independent.finite LinearIndependent.setFinite - -/-- A finite dimensional space has positive `finrank` iff it has a nonzero element. -/ -theorem finrank_pos_iff_exists_ne_zero [FiniteDimensional K V] : 0 < finrank K V ↔ ∃ x : V, x ≠ 0 := - Iff.trans - (by - rw [← finrank_eq_rank] - norm_cast) - (@rank_pos_iff_exists_ne_zero K V _ _ _ _ _) -#align finite_dimensional.finrank_pos_iff_exists_ne_zero FiniteDimensional.finrank_pos_iff_exists_ne_zero - -/-- A finite dimensional space has positive `finrank` iff it is nontrivial. -/ -theorem finrank_pos_iff [FiniteDimensional K V] : 0 < finrank K V ↔ Nontrivial V := - Iff.trans - (by rw [← finrank_eq_rank]; norm_cast) - (rank_pos_iff_nontrivial (R := K)) -#align finite_dimensional.finrank_pos_iff FiniteDimensional.finrank_pos_iff - -/-- A nontrivial finite dimensional space has positive `finrank`. -/ -theorem finrank_pos [FiniteDimensional K V] [h : Nontrivial V] : 0 < finrank K V := - finrank_pos_iff.mpr h -#align finite_dimensional.finrank_pos FiniteDimensional.finrank_pos - -/-- A finite dimensional space has zero `finrank` iff it is a subsingleton. -This is the `finrank` version of `rank_zero_iff`. -/ -theorem finrank_zero_iff [FiniteDimensional K V] : finrank K V = 0 ↔ Subsingleton V := - Iff.trans - (by rw [← finrank_eq_rank]; norm_cast) - (rank_zero_iff (R := K)) -#align finite_dimensional.finrank_zero_iff FiniteDimensional.finrank_zero_iff - /-- If a submodule has maximal dimension in a finite dimensional space, then it is equal to the whole space. -/ theorem _root_.Submodule.eq_top_of_finrank_eq [FiniteDimensional K V] {S : Submodule K V} @@ -378,17 +258,17 @@ instance finiteDimensional_self : FiniteDimensional K K := by infer_instance /-- The submodule generated by a finite set is finite-dimensional. -/ theorem span_of_finite {A : Set V} (hA : Set.Finite A) : FiniteDimensional K (Submodule.span K A) := - iff_fg.1 <| isNoetherian_span_of_finite K hA + Module.Finite.span_of_finite K hA #align finite_dimensional.span_of_finite FiniteDimensional.span_of_finite /-- The submodule generated by a single element is finite-dimensional. -/ instance span_singleton (x : V) : FiniteDimensional K (K ∙ x) := - span_of_finite K <| Set.finite_singleton _ + Module.Finite.span_singleton K x #align finite_dimensional.span_singleton FiniteDimensional.span_singleton /-- The submodule generated by a finset is finite-dimensional. -/ instance span_finset (s : Finset V) : FiniteDimensional K (span K (s : Set V)) := - span_of_finite K <| s.finite_toSet + Module.Finite.span_finset K s #align finite_dimensional.span_finset FiniteDimensional.span_finset /-- Pushforwards of finite-dimensional submodules are finite-dimensional. -/ @@ -398,172 +278,12 @@ instance (f : V →ₗ[K] V₂) (p : Submodule K V) [FiniteDimensional K p] : variable {K} -theorem _root_.CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux [FiniteDimensional K V] - {ι : Type w} {p : ι → Submodule K V} (hp : CompleteLattice.Independent p) : - #{ i // p i ≠ ⊥ } ≤ (finrank K V : Cardinal.{w}) := by - suffices Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{v} (finrank K V : Cardinal.{w}) by - rwa [Cardinal.lift_le] at this - calc - Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{w} (Module.rank K V) := - hp.subtype_ne_bot_le_rank - _ = Cardinal.lift.{w} (finrank K V : Cardinal.{v}) := by rw [finrank_eq_rank] - _ = Cardinal.lift.{v} (finrank K V : Cardinal.{w}) := by simp -#align complete_lattice.independent.subtype_ne_bot_le_finrank_aux CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux - -/-- If `p` is an independent family of subspaces of a finite-dimensional space `V`, then the -number of nontrivial subspaces in the family `p` is finite. -/ -noncomputable def _root_.CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional - [FiniteDimensional K V] {ι : Type w} {p : ι → Submodule K V} - (hp : CompleteLattice.Independent p) : Fintype { i : ι // p i ≠ ⊥ } := by - suffices #{ i // p i ≠ ⊥ } < (ℵ₀ : Cardinal.{w}) by - rw [Cardinal.lt_aleph0_iff_fintype] at this - exact this.some - refine' lt_of_le_of_lt hp.subtype_ne_bot_le_finrank_aux _ - simp [Cardinal.nat_lt_aleph0] -#align complete_lattice.independent.fintype_ne_bot_of_finite_dimensional CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional - -/-- If `p` is an independent family of subspaces of a finite-dimensional space `V`, then the -number of nontrivial subspaces in the family `p` is bounded above by the dimension of `V`. - -Note that the `Fintype` hypothesis required here can be provided by -`CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional`. -/ -theorem _root_.CompleteLattice.Independent.subtype_ne_bot_le_finrank [FiniteDimensional K V] - {ι : Type w} {p : ι → Submodule K V} (hp : CompleteLattice.Independent p) - [Fintype { i // p i ≠ ⊥ }] : - Fintype.card { i // p i ≠ ⊥ } ≤ finrank K V := by simpa using hp.subtype_ne_bot_le_finrank_aux -#align complete_lattice.independent.subtype_ne_bot_le_finrank CompleteLattice.Independent.subtype_ne_bot_le_finrank - section open BigOperators open Finset -/-- If a finset has cardinality larger than the dimension of the space, -then there is a nontrivial linear relation amongst its elements. --/ -theorem exists_nontrivial_relation_of_rank_lt_card [FiniteDimensional K V] {t : Finset V} - (h : finrank K V < t.card) : ∃ f : V → K, ∑ e in t, f e • e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by - classical - have := mt finset_card_le_finrank_of_linearIndependent (by simpa using h) - rw [not_linearIndependent_iff] at this - obtain ⟨s, g, sum, z, zm, nonzero⟩ := this - -- Now we have to extend `g` to all of `t`, then to all of `V`. - let f : V → K := fun x => if h : x ∈ t then if (⟨x, h⟩ : t) ∈ s then g ⟨x, h⟩ else 0 else 0 - -- and finally clean up the mess caused by the extension. - refine' ⟨f, _, _⟩ - · dsimp - rw [← (sum)] -- porting note: need parens to disambiguate - fapply sum_bij_ne_zero fun v hvt _ => (⟨v, hvt⟩ : { v // v ∈ t }) - · intro v hvt H - dsimp - rw [dif_pos hvt] at H - contrapose! H - rw [if_neg H, zero_smul] - · intro _ _ _ _ _ _ - exact Subtype.mk.inj - · intro b hbs hb - use b - simpa only [hbs, exists_prop, dif_pos, Finset.mk_coe, and_true_iff, if_true, Finset.coe_mem, - eq_self_iff_true, exists_prop_of_true, Ne.def] using hb - · intro a h₁ - dsimp - rw [dif_pos h₁] - intro h₂ - rw [if_pos] - contrapose! h₂ - rw [if_neg h₂, zero_smul] - · refine' ⟨z, z.2, _⟩ - dsimp only - erw [dif_pos z.2, if_pos] <;> rwa [Subtype.coe_eta] -#align finite_dimensional.exists_nontrivial_relation_of_rank_lt_card FiniteDimensional.exists_nontrivial_relation_of_rank_lt_card - -/-- If a finset has cardinality larger than `finrank + 1`, -then there is a nontrivial linear relation amongst its elements, -such that the coefficients of the relation sum to zero. --/ -theorem exists_nontrivial_relation_sum_zero_of_rank_succ_lt_card [FiniteDimensional K V] - {t : Finset V} (h : finrank K V + 1 < t.card) : - ∃ f : V → K, ∑ e in t, f e • e = 0 ∧ ∑ e in t, f e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by - classical - -- Pick an element x₀ ∈ t, - have card_pos : 0 < t.card := lt_trans (Nat.succ_pos _) h - obtain ⟨x₀, m⟩ := (Finset.card_pos.1 card_pos).bex - -- and apply the previous lemma to the {xᵢ - x₀} - let shift : V ↪ V := ⟨fun x => x - x₀, sub_left_injective⟩ - let t' := (t.erase x₀).map shift - have h' : finrank K V < t'.card := by - simp only [card_map, Finset.card_erase_of_mem m] - exact Nat.lt_pred_iff.mpr h - -- to obtain a function `g`. - obtain ⟨g, gsum, x₁, x₁_mem, nz⟩ := exists_nontrivial_relation_of_rank_lt_card h' - -- Then obtain `f` by translating back by `x₀`, - -- and setting the value of `f` at `x₀` to ensure `∑ e in t, f e = 0`. - let f : V → K := fun z => if z = x₀ then -∑ z in t.erase x₀, g (z - x₀) else g (z - x₀) - refine' ⟨f, _, _, _⟩ - -- After this, it's a matter of verifying the properties, - -- based on the corresponding properties for `g`. - · show (∑ e : V in t, f e • e) = 0 - -- We prove this by splitting off the `x₀` term of the sum, - -- which is itself a sum over `t.erase x₀`, - -- combining the two sums, and - -- observing that after reindexing we have exactly - -- ∑ (x : V) in t', g x • x = 0. - simp only - conv_lhs => - apply_congr - rfl - rw [ite_smul] - rw [Finset.sum_ite] - conv => - congr - congr - apply_congr - -- Porting note: the next two steps used to work by `simp [filter_eq', m]` - erw [filter_eq'] - simp [m] - conv => - congr - congr - rfl - apply_congr - simp [filter_ne'] - rw [sum_singleton, neg_smul, add_comm, ← sub_eq_add_neg, sum_smul, ← sum_sub_distrib] - simp only [← smul_sub] - -- At the end we have to reindex the sum, so we use `change` to - -- express the summand using `shift`. - change (∑ x : V in t.erase x₀, (fun e => g e • e) (shift x)) = 0 - -- porting note: last argument can't be inferred - rw [← sum_map _ shift (fun e => g e • e)] - exact gsum - · show (∑ e : V in t, f e) = 0 - -- Again we split off the `x₀` term, - -- observing that it exactly cancels the other terms. - rw [← insert_erase m, sum_insert (not_mem_erase x₀ t)] - dsimp - rw [if_pos rfl] - conv_lhs => - congr - rfl - apply_congr - rfl - rw [if_neg (show _ ≠ x₀ from (mem_erase.mp ‹_›).1)] - exact neg_add_self _ - · show ∃ (x : V), x ∈ t ∧ f x ≠ 0 - -- We can use x₁ + x₀. - refine' ⟨x₁ + x₀, _, _⟩ - · rw [Finset.mem_map] at x₁_mem - rcases x₁_mem with ⟨x₁, x₁_mem, rfl⟩ - rw [mem_erase] at x₁_mem - simp only [x₁_mem, sub_add_cancel, Function.Embedding.coeFn_mk] - · dsimp only - rwa [if_neg, add_sub_cancel] - rw [add_left_eq_self] - rintro rfl - simp only [sub_eq_zero, exists_prop, Finset.mem_map, Embedding.coeFn_mk, eq_self_iff_true, - mem_erase, not_true, exists_eq_right, Ne.def, false_and_iff] at x₁_mem -#align finite_dimensional.exists_nontrivial_relation_sum_zero_of_rank_succ_lt_card FiniteDimensional.exists_nontrivial_relation_sum_zero_of_rank_succ_lt_card - section variable {L : Type*} [LinearOrderedField L] @@ -574,12 +294,14 @@ variable {W : Type v} [AddCommGroup W] [Module L W] available when working over an ordered field: we can ensure a positive coefficient, not just a nonzero coefficient. -/ -theorem exists_relation_sum_zero_pos_coefficient_of_rank_succ_lt_card [FiniteDimensional L W] +theorem exists_relation_sum_zero_pos_coefficient_of_finrank_succ_lt_card [FiniteDimensional L W] {t : Finset W} (h : finrank L W + 1 < t.card) : ∃ f : W → L, ∑ e in t, f e • e = 0 ∧ ∑ e in t, f e = 0 ∧ ∃ x ∈ t, 0 < f x := by - obtain ⟨f, sum, total, nonzero⟩ := exists_nontrivial_relation_sum_zero_of_rank_succ_lt_card h + obtain ⟨f, sum, total, nonzero⟩ := + Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card h exact ⟨f, sum, total, exists_pos_of_sum_zero_of_exists_nonzero f total nonzero⟩ -#align finite_dimensional.exists_relation_sum_zero_pos_coefficient_of_rank_succ_lt_card FiniteDimensional.exists_relation_sum_zero_pos_coefficient_of_rank_succ_lt_card +#align finite_dimensional.exists_relation_sum_zero_pos_coefficient_of_rank_succ_lt_card FiniteDimensional.exists_relation_sum_zero_pos_coefficient_of_finrank_succ_lt_card + end @@ -589,8 +311,8 @@ end @[simps repr_apply] noncomputable def basisSingleton (ι : Type*) [Unique ι] (h : finrank K V = 1) (v : V) (hv : v ≠ 0) : Basis ι K V := - let b := basisUnique ι h - let h : b.repr v default ≠ 0 := mt basisUnique.repr_eq_zero_iff.mp hv + let b := FiniteDimensional.basisUnique ι h + let h : b.repr v default ≠ 0 := mt FiniteDimensional.basisUnique_repr_eq_zero_iff.mp hv Basis.ofRepr { toFun := fun w => Finsupp.single default (b.repr w default / b.repr v default) invFun := fun f => f default • v @@ -632,26 +354,19 @@ variable [DivisionRing K] [AddCommGroup V] [Module K V] open FiniteDimensional theorem finiteDimensional_of_rank_eq_nat {n : ℕ} (h : Module.rank K V = n) : - FiniteDimensional K V := by - rw [FiniteDimensional, ← IsNoetherian.iff_fg, IsNoetherian.iff_rank_lt_aleph0, h] - exact nat_lt_aleph0 n + FiniteDimensional K V := + Module.finite_of_rank_eq_nat h #align finite_dimensional_of_rank_eq_nat finiteDimensional_of_rank_eq_nat -- TODO: generalize to free modules over general rings. theorem finiteDimensional_of_rank_eq_zero (h : Module.rank K V = 0) : FiniteDimensional K V := - finiteDimensional_of_rank_eq_nat <| h.trans Nat.cast_zero.symm + Module.finite_of_rank_eq_zero h #align finite_dimensional_of_rank_eq_zero finiteDimensional_of_rank_eq_zero theorem finiteDimensional_of_rank_eq_one (h : Module.rank K V = 1) : FiniteDimensional K V := - finiteDimensional_of_rank_eq_nat <| h.trans Nat.cast_one.symm + Module.finite_of_rank_eq_one h #align finite_dimensional_of_rank_eq_one finiteDimensional_of_rank_eq_one -theorem finrank_eq_zero_of_rank_eq_zero [FiniteDimensional K V] (h : Module.rank K V = 0) : - finrank K V = 0 := by - convert finrank_eq_rank K V - rw [h]; norm_cast -#align finrank_eq_zero_of_rank_eq_zero finrank_eq_zero_of_rank_eq_zero - variable (K V) instance finiteDimensional_bot : FiniteDimensional K (⊥ : Submodule K V) := @@ -660,27 +375,6 @@ instance finiteDimensional_bot : FiniteDimensional K (⊥ : Submodule K V) := variable {K V} -theorem bot_eq_top_of_rank_eq_zero (h : Module.rank K V = 0) : (⊥ : Submodule K V) = ⊤ := by - haveI : FiniteDimensional _ _ := finiteDimensional_of_rank_eq_zero h - apply eq_top_of_finrank_eq - rw [finrank_bot, finrank_eq_zero_of_rank_eq_zero h] -#align bot_eq_top_of_rank_eq_zero bot_eq_top_of_rank_eq_zero - -@[simp] -theorem rank_eq_zero {S : Submodule K V} : Module.rank K S = 0 ↔ S = ⊥ := - ⟨fun h => - (Submodule.eq_bot_iff _).2 fun x hx => - congr_arg Subtype.val <| - ((Submodule.eq_bot_iff _).1 <| Eq.symm <| bot_eq_top_of_rank_eq_zero h) ⟨x, hx⟩ - Submodule.mem_top, - fun h => by rw [h, rank_bot]⟩ -#align rank_eq_zero rank_eq_zero - -@[simp] -theorem finrank_eq_zero {S : Submodule K V} [FiniteDimensional K S] : finrank K S = 0 ↔ S = ⊥ := by - rw [← rank_eq_zero, ← finrank_eq_rank, ← @Nat.cast_zero Cardinal, Cardinal.natCast_inj] -#align finrank_eq_zero finrank_eq_zero - end ZeroRank namespace Submodule @@ -826,7 +520,7 @@ variable [DivisionRing K] [AddCommGroup V] [Module K V] instance finiteDimensional_finsupp {ι : Type*} [Finite ι] [FiniteDimensional K V] : FiniteDimensional K (ι →₀ V) := - (Finsupp.linearEquivFunOnFinite K V ι).symm.finiteDimensional + Module.Finite.finsupp #align finite_dimensional_finsupp finiteDimensional_finsupp end @@ -1080,7 +774,7 @@ section variable [DivisionRing K] [AddCommGroup V] [Module K V] theorem finrank_zero_iff_forall_zero [FiniteDimensional K V] : finrank K V = 0 ↔ ∀ x : V, x = 0 := - finrank_zero_iff.trans (subsingleton_iff_forall_eq 0) + FiniteDimensional.finrank_zero_iff.trans (subsingleton_iff_forall_eq 0) #align finrank_zero_iff_forall_zero finrank_zero_iff_forall_zero /-- If `ι` is an empty type and `V` is zero-dimensional, there is a unique `ι`-indexed basis. -/ @@ -1105,7 +799,7 @@ theorem injective_iff_surjective_of_finrank_eq_finrank [FiniteDimensional K V] · rw [h, finrank_bot, add_zero, H] at this exact eq_top_of_finrank_eq this · rw [h, finrank_top, H] at this - exact finrank_eq_zero.1 (add_right_injective _ this) + exact Submodule.finrank_eq_zero.1 (add_right_injective _ this) #align linear_map.injective_iff_surjective_of_finrank_eq_finrank LinearMap.injective_iff_surjective_of_finrank_eq_finrank theorem ker_eq_bot_iff_range_eq_top_of_finrank_eq_finrank [FiniteDimensional K V] @@ -1334,7 +1028,7 @@ theorem finrank_eq_one_iff (ι : Type*) [Unique ι] : finrank K V = 1 ↔ Nonemp constructor · intro h haveI := finiteDimensional_of_finrank (_root_.zero_lt_one.trans_le h.symm.le) - exact ⟨basisUnique ι h⟩ + exact ⟨FiniteDimensional.basisUnique ι h⟩ · rintro ⟨b⟩ simpa using finrank_eq_card_basis b #align finrank_eq_one_iff finrank_eq_one_iff diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean index 32fb7ab5b68c2..7426961e297b8 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean @@ -31,6 +31,13 @@ section Ring variable [Ring R] [AddCommGroup M] [Module R M] [Module.Free R M] +/-- If a free module is finite, then any arbitrary basis is finite. -/ +lemma finite_basis {R M} [Ring R] [Nontrivial R] [AddCommGroup M] [Module R M] + {ι} [Module.Finite R M] (b : Basis ι R M) : + _root_.Finite ι := + let ⟨s, hs⟩ := ‹Module.Finite R M› + basis_finite_of_finite_spans (↑s) s.finite_toSet hs b + /-- If a free module is finite, then the arbitrary basis is finite. -/ noncomputable instance ChooseBasisIndex.fintype [Module.Finite R M] : Fintype (Module.Free.ChooseBasisIndex R M) := by @@ -39,8 +46,7 @@ noncomputable instance ChooseBasisIndex.fintype [Module.Finite R M] : · have := Module.subsingleton R M rw [ChooseBasisIndex] infer_instance - · obtain ⟨s, hs⟩ := id ‹Module.Finite R M› - exact basis_finite_of_finite_spans (↑s) s.finite_toSet hs (chooseBasis _ _) + · exact finite_basis (chooseBasis _ _) #align module.free.choose_basis_index.fintype Module.Free.ChooseBasisIndex.fintype end Ring @@ -54,7 +60,7 @@ variable [AddCommGroup N] [Module R N] [Module.Free R N] variable {R} /-- A free module with a basis indexed by a `Fintype` is finite. -/ -theorem _root_.Module.Finite.of_basis {R M ι : Type*} [CommRing R] [AddCommGroup M] [Module R M] +theorem _root_.Module.Finite.of_basis {R M ι : Type*} [Semiring R] [AddCommMonoid M] [Module R M] [_root_.Finite ι] (b : Basis ι R M) : Module.Finite R M := by cases nonempty_fintype ι classical diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean index 7d962c45a5e76..046c7e91812e0 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean @@ -19,7 +19,8 @@ This is a basic API for the rank of finite free modules. --TODO: many results from `LinearAlgebra/FiniteDimensional` should be moved here. -universe u v w +--TODO: This file contains many misplaced lemmas and should be reorganized. +universe u v w v' variable (R : Type u) (M : Type v) (N : Type w) @@ -91,11 +92,15 @@ theorem finrank_eq_card_chooseBasisIndex : simp [finrank, rank_eq_card_chooseBasisIndex] #align finite_dimensional.finrank_eq_card_choose_basis_index FiniteDimensional.finrank_eq_card_chooseBasisIndex +@[simp] +theorem finrank_finsupp {ι : Type v} [Fintype ι] : finrank R (ι →₀ M) = card ι * finrank R M := by + rw [finrank, finrank, rank_finsupp, ← mk_toNat_eq_card, toNat_mul, toNat_lift, toNat_lift] + /-- The finrank of `(ι →₀ R)` is `Fintype.card ι`. -/ @[simp] -theorem finrank_finsupp {ι : Type v} [Fintype ι] : finrank R (ι →₀ R) = card ι := by +theorem finrank_finsupp_self {ι : Type v} [Fintype ι] : finrank R (ι →₀ R) = card ι := by rw [finrank, rank_finsupp_self, ← mk_toNat_eq_card, toNat_lift] -#align finite_dimensional.finrank_finsupp FiniteDimensional.finrank_finsupp +#align finite_dimensional.finrank_finsupp FiniteDimensional.finrank_finsupp_self /-- The finrank of `(ι → R)` is `Fintype.card ι`. -/ theorem finrank_pi {ι : Type v} [Fintype ι] : finrank R (ι → R) = card ι := by @@ -227,3 +232,492 @@ theorem Submodule.finrank_le_finrank_of_le {s t : Submodule R M} [Module.Finite #align submodule.finrank_le_finrank_of_le Submodule.finrank_le_finrank_of_le end + + +open Cardinal Submodule Module Function FiniteDimensional + +attribute [local instance] nontrivial_of_invariantBasisNumber + +variable {R} {V : Type v} + +open IsNoetherian + +section DivisionRing + +variable [AddCommGroup V] {V₂ : Type v'} [AddCommGroup V₂] +variable [Ring R] [StrongRankCondition R] [Module R V] [Module.Free R V] + +/-- See `FiniteDimensional.rank_lt_aleph0` for the inverse direction without `Module.Free R V`. -/ +lemma Module.rank_lt_alpeh0_iff : + Module.rank R V < ℵ₀ ↔ Module.Finite R V := by + rw [Free.rank_eq_card_chooseBasisIndex, mk_lt_aleph0_iff] + exact ⟨fun h ↦ Finite.of_basis (Free.chooseBasis R V), + fun I ↦ Finite.of_fintype (Free.ChooseBasisIndex R V)⟩ + +theorem FiniteDimensional.finrank_of_not_finite + (h : ¬Module.Finite R V) : + finrank R V = 0 := + dif_neg (rank_lt_alpeh0_iff.not.mpr h) + +theorem Module.finite_of_finrank_pos (h : 0 < finrank R V) : + Module.Finite R V := by + contrapose h + simp [finrank_of_not_finite h] + +theorem Module.finite_of_finrank_eq_succ {n : ℕ} + (hn : finrank R V = n.succ) : Module.Finite R V := + Module.finite_of_finrank_pos <| by rw [hn]; exact n.succ_pos + +theorem Module.finite_iff_of_rank_eq_nsmul {W} [AddCommGroup W] + [Module R W] [Module.Free R W] {n : ℕ} (hn : n ≠ 0) + (hVW : Module.rank R V = n • Module.rank R W) : + Module.Finite R V ↔ Module.Finite R W := by + simp only [← rank_lt_alpeh0_iff, hVW, nsmul_lt_aleph0_iff_of_ne_zero hn] + +/-- If a free module is of finite rank, then the cardinality of any basis is equal to its +`finrank`. -/ +theorem Module.mk_finrank_eq_card_basis [Module.Finite R V] + {ι : Type w} (h : Basis ι R V) : (finrank R V : Cardinal.{w}) = #ι := by + cases @nonempty_fintype _ (Free.finite_basis h) + rw [Cardinal.mk_fintype, finrank_eq_card_basis h] + +/-- Given a basis of a ring over itself indexed by a type `ι`, then `ι` is `Unique`. -/ +noncomputable def Basis.unique {ι : Type*} (b : Basis ι R R) : Unique ι := by + have A : Cardinal.mk ι = ↑(FiniteDimensional.finrank R R) := + (Module.mk_finrank_eq_card_basis b).symm + -- porting note: replace `algebraMap.coe_one` with `Nat.cast_one` + simp only [Cardinal.eq_one_iff_unique, FiniteDimensional.finrank_self, Nat.cast_one] at A + exact Nonempty.some ((unique_iff_subsingleton_and_nonempty _).2 A) +#align basis.unique Basis.unique + +namespace FiniteDimensional +variable (R V) + +/-- A finite rank free module has a basis indexed by `Fin (finrank R V)`. -/ +noncomputable def finBasis [Module.Finite R V] : + Basis (Fin (finrank R V)) R V := + (Free.chooseBasis R V).reindex (Fintype.equivFinOfCardEq + (finrank_eq_card_chooseBasisIndex R V).symm) +#align finite_dimensional.fin_basis FiniteDimensional.finBasis + +/-- A rank `n` free module has a basis indexed by `Fin n`. -/ +noncomputable def finBasisOfFinrankEq [Module.Finite R V] + {n : ℕ} (hn : finrank R V = n) : + Basis (Fin n) R V := + (finBasis R V).reindex (Fin.castIso hn).toEquiv +#align finite_dimensional.fin_basis_of_finrank_eq FiniteDimensional.finBasisOfFinrankEq + +variable {R V} + +/-- A free module with rank 1 has a basis with one element. -/ +noncomputable def basisUnique (ι : Type*) [Unique ι] + (h : finrank R V = 1) : + Basis ι R V := + haveI : Module.Finite R V := + Module.finite_of_finrank_pos (_root_.zero_lt_one.trans_le h.symm.le) + (finBasisOfFinrankEq R V h).reindex (Equiv.equivOfUnique _ _) +#align finite_dimensional.basis_unique FiniteDimensional.basisUnique + +@[simp] +theorem basisUnique_repr_eq_zero_iff {ι : Type*} [Unique ι] + {h : finrank R V = 1} {v : V} {i : ι} : + (basisUnique ι h).repr v i = 0 ↔ v = 0 := + ⟨fun hv => + (basisUnique ι h).repr.map_eq_zero_iff.mp (Finsupp.ext fun j => Subsingleton.elim i j ▸ hv), + fun hv => by rw [hv, LinearEquiv.map_zero, Finsupp.zero_apply]⟩ +#align finite_dimensional.basis_unique.repr_eq_zero_iff FiniteDimensional.basisUnique_repr_eq_zero_iff + +theorem cardinal_mk_le_finrank_of_linearIndependent [Module.Finite R V] + {ι : Type w} {b : ι → V} (h : LinearIndependent R b) : #ι ≤ finrank R V := by + rw [← lift_le.{max v w}] + simpa only [← finrank_eq_rank, lift_natCast, lift_le_nat_iff] using + cardinal_lift_le_rank_of_linearIndependent h +#align finite_dimensional.cardinal_mk_le_finrank_of_linear_independent FiniteDimensional.cardinal_mk_le_finrank_of_linearIndependent + +theorem fintype_card_le_finrank_of_linearIndependent [Module.Finite R V] + {ι : Type*} [Fintype ι] {b : ι → V} (h : LinearIndependent R b) : + Fintype.card ι ≤ finrank R V := by + simpa using cardinal_mk_le_finrank_of_linearIndependent h +#align finite_dimensional.fintype_card_le_finrank_of_linear_independent FiniteDimensional.fintype_card_le_finrank_of_linearIndependent + +theorem finset_card_le_finrank_of_linearIndependent [Module.Finite R V] + {b : Finset V} (h : LinearIndependent R (fun x => x : b → V)) : + b.card ≤ finrank R V := by + rw [← Fintype.card_coe] + exact fintype_card_le_finrank_of_linearIndependent h +#align finite_dimensional.finset_card_le_finrank_of_linear_independent FiniteDimensional.finset_card_le_finrank_of_linearIndependent + +end FiniteDimensional + +theorem Module.Finite.lt_aleph0_of_linearIndependent {ι : Type w} + [Module.Finite R V] {v : ι → V} (h : LinearIndependent R v) : #ι < ℵ₀ := by + apply Cardinal.lift_lt.1 + apply lt_of_le_of_lt + apply cardinal_lift_le_rank_of_linearIndependent h + rw [← finrank_eq_rank, Cardinal.lift_aleph0, Cardinal.lift_natCast] + apply Cardinal.nat_lt_aleph0 + +theorem LinearIndependent.finite [Module.Finite R V] {ι : Type*} {f : ι → V} + (h : LinearIndependent R f) : Finite ι := + Cardinal.lt_aleph0_iff_finite.1 <| Module.Finite.lt_aleph0_of_linearIndependent h + +theorem LinearIndependent.setFinite [Module.Finite R V] {b : Set V} + (h : LinearIndependent R fun x : b => (x : V)) : b.Finite := + Cardinal.lt_aleph0_iff_set_finite.mp (Module.Finite.lt_aleph0_of_linearIndependent h) +#align linear_independent.finite LinearIndependent.setFinite + +theorem Module.Finite.not_linearIndependent_of_infinite {ι : Type*} [Infinite ι] [Module.Finite R V] + (v : ι → V) : ¬LinearIndependent R v := mt LinearIndependent.finite <| @not_finite _ _ +#align finite_dimensional.not_linear_independent_of_infinite Module.Finite.not_linearIndependent_of_infinite + +/-- A finite rank torsion-free module has positive `finrank` iff it has a nonzero element. -/ +theorem FiniteDimensional.finrank_pos_iff_exists_ne_zero + [Module.Finite R V] [NoZeroSMulDivisors R V] : + 0 < finrank R V ↔ ∃ x : V, x ≠ 0 := + Iff.trans + (by + rw [← finrank_eq_rank] + norm_cast) + (@rank_pos_iff_exists_ne_zero R V _ _ _ _ _) +#align finite_dimensional.finrank_pos_iff_exists_ne_zero FiniteDimensional.finrank_pos_iff_exists_ne_zero + +/-- An `R`-finite torsion-free module has positive `finrank` iff it is nontrivial. -/ +theorem FiniteDimensional.finrank_pos_iff [Module.Finite R V] [NoZeroSMulDivisors R V] : + 0 < finrank R V ↔ Nontrivial V := + Iff.trans + (by rw [← finrank_eq_rank]; norm_cast) + (rank_pos_iff_nontrivial (R := R)) +#align finite_dimensional.finrank_pos_iff FiniteDimensional.finrank_pos_iff + +/-- A nontrivial finite dimensional space has positive `finrank`. -/ +theorem FiniteDimensional.finrank_pos + [Module.Finite R V] [NoZeroSMulDivisors R V] [h : Nontrivial V] : + 0 < finrank R V := + finrank_pos_iff.mpr h +#align finite_dimensional.finrank_pos FiniteDimensional.finrank_pos + +/-- See `FiniteDimensional.finrank_zero_iff` + for the stronger version with `NoZeroSMulDivisors R V`. -/ +theorem FiniteDimensional.finrank_eq_zero_iff [Module.Finite R V] : + finrank R V = 0 ↔ ∀ x : V, ∃ a : R, a ≠ 0 ∧ a • x = 0 := + Iff.trans + (by rw [← finrank_eq_rank]; norm_cast) + (rank_eq_zero_iff (R := R)) + +/-- The `StrongRankCondition` is automatic. See `commRing_strongRankCondition`. -/ +theorem FiniteDimensional.finrank_eq_zero_iff_isTorsion {R} [CommRing R] [StrongRankCondition R] + [IsDomain R] [Module R V] [Module.Finite R V] : + finrank R V = 0 ↔ IsTorsion R V := + Iff.trans + (by rw [← finrank_eq_rank]; norm_cast) + (rank_eq_zero_iff_isTorsion (R := R)) + +/-- A finite dimensional space has zero `finrank` iff it is a subsingleton. +This is the `finrank` version of `rank_zero_iff`. -/ +theorem FiniteDimensional.finrank_zero_iff [Module.Finite R V] [NoZeroSMulDivisors R V] : + finrank R V = 0 ↔ Subsingleton V := + Iff.trans + (by rw [← finrank_eq_rank]; norm_cast) + (rank_zero_iff (R := R)) +#align finite_dimensional.finrank_zero_iff FiniteDimensional.finrank_zero_iff + +variable (R K) + +/-- The submodule generated by a finite set is `R`-finite. -/ +theorem Module.Finite.span_of_finite {A : Set V} (hA : Set.Finite A) : + Module.Finite R (Submodule.span R A) := + ⟨(Submodule.fg_top _).mpr ⟨hA.toFinset, hA.coe_toFinset.symm ▸ rfl⟩⟩ + +/-- The submodule generated by a single element is `R`-finite. -/ +instance Module.Finite.span_singleton (x : V) : Module.Finite R (R ∙ x) := + Module.Finite.span_of_finite R <| Set.finite_singleton _ + +/-- The submodule generated by a finset is `R`-finite. -/ +instance Module.Finite.span_finset (s : Finset V) : Module.Finite R (span R (s : Set V)) := + ⟨(Submodule.fg_top _).mpr ⟨s, rfl⟩⟩ + +variable {K R} + +theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux [Module.Finite R V] + [NoZeroSMulDivisors R V] + {ι : Type w} {p : ι → Submodule R V} (hp : CompleteLattice.Independent p) : + #{ i // p i ≠ ⊥ } ≤ (finrank R V : Cardinal.{w}) := by + suffices Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{v} (finrank R V : Cardinal.{w}) by + rwa [Cardinal.lift_le] at this + calc + Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{w} (Module.rank R V) := + hp.subtype_ne_bot_le_rank + _ = Cardinal.lift.{w} (finrank R V : Cardinal.{v}) := by rw [finrank_eq_rank] + _ = Cardinal.lift.{v} (finrank R V : Cardinal.{w}) := by simp +#align complete_lattice.independent.subtype_ne_bot_le_finrank_aux CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux + +/-- If `p` is an independent family of submodules of a `R`-finite module `V`, then the +number of nontrivial subspaces in the family `p` is finite. -/ +noncomputable def CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional + [Module.Finite R V] [NoZeroSMulDivisors R V] {ι : Type w} {p : ι → Submodule R V} + (hp : CompleteLattice.Independent p) : Fintype { i : ι // p i ≠ ⊥ } := by + suffices #{ i // p i ≠ ⊥ } < (ℵ₀ : Cardinal.{w}) by + rw [Cardinal.lt_aleph0_iff_fintype] at this + exact this.some + refine' lt_of_le_of_lt hp.subtype_ne_bot_le_finrank_aux _ + simp [Cardinal.nat_lt_aleph0] +#align complete_lattice.independent.fintype_ne_bot_of_finite_dimensional CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional + +/-- If `p` is an independent family of submodules of a `R`-finite module `V`, then the +number of nontrivial subspaces in the family `p` is bounded above by the dimension of `V`. + +Note that the `Fintype` hypothesis required here can be provided by +`CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional`. -/ +theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank + [Module.Finite R V] [NoZeroSMulDivisors R V] + {ι : Type w} {p : ι → Submodule R V} (hp : CompleteLattice.Independent p) + [Fintype { i // p i ≠ ⊥ }] : + Fintype.card { i // p i ≠ ⊥ } ≤ finrank R V := by simpa using hp.subtype_ne_bot_le_finrank_aux +#align complete_lattice.independent.subtype_ne_bot_le_finrank CompleteLattice.Independent.subtype_ne_bot_le_finrank + +section + +open BigOperators + +open Finset + +/-- If a finset has cardinality larger than the rank of a module, +then there is a nontrivial linear relation amongst its elements. +-/ +-- TODO: golf this +theorem Module.exists_nontrivial_relation_of_finrank_lt_card + [Module.Finite R V] {t : Finset V} + (h : finrank R V < t.card) : ∃ f : V → R, ∑ e in t, f e • e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by + classical + have := mt FiniteDimensional.finset_card_le_finrank_of_linearIndependent (by simpa using h) + rw [_root_.not_linearIndependent_iff] at this + obtain ⟨s, g, sum, z, zm, nonzero⟩ := this + -- Now we have to extend `g` to all of `t`, then to all of `V`. + let f : V → R := fun x => if h : x ∈ t then if (⟨x, h⟩ : t) ∈ s then g ⟨x, h⟩ else 0 else 0 + -- and finally clean up the mess caused by the extension. + refine' ⟨f, _, _⟩ + · dsimp + rw [← (sum)] -- porting note: need parens to disambiguate + fapply sum_bij_ne_zero fun v hvt _ => (⟨v, hvt⟩ : { v // v ∈ t }) + · intro v hvt H + dsimp + rw [dif_pos hvt] at H + contrapose! H + rw [if_neg H, zero_smul] + · intro _ _ _ _ _ _ + exact Subtype.mk.inj + · intro b hbs hb + use b + simpa only [hbs, exists_prop, dif_pos, Finset.mk_coe, and_true_iff, if_true, Finset.coe_mem, + eq_self_iff_true, exists_prop_of_true, Ne.def] using hb + · intro a h₁ + dsimp + rw [dif_pos h₁] + intro h₂ + rw [if_pos] + contrapose! h₂ + rw [if_neg h₂, zero_smul] + · refine' ⟨z, z.2, _⟩ + dsimp only + erw [dif_pos z.2, if_pos] <;> rwa [Subtype.coe_eta] +#align finite_dimensional.exists_nontrivial_relation_of_rank_lt_card Module.exists_nontrivial_relation_of_finrank_lt_card + +/-- If a finset has cardinality larger than `finrank + 1`, +then there is a nontrivial linear relation amongst its elements, +such that the coefficients of the relation sum to zero. +-/ +-- TODO: golf this +theorem Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card [Module.Finite R V] + {t : Finset V} (h : finrank R V + 1 < t.card) : + ∃ f : V → R, ∑ e in t, f e • e = 0 ∧ ∑ e in t, f e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by + classical + -- Pick an element x₀ ∈ t, + have card_pos : 0 < t.card := lt_trans (Nat.succ_pos _) h + obtain ⟨x₀, m⟩ := (Finset.card_pos.1 card_pos).bex + -- and apply the previous lemma to the {xᵢ - x₀} + let shift : V ↪ V := ⟨fun x => x - x₀, sub_left_injective⟩ + let t' := (t.erase x₀).map shift + have h' : finrank R V < t'.card := by + simp only [card_map, Finset.card_erase_of_mem m] + exact Nat.lt_pred_iff.mpr h + -- to obtain a function `g`. + obtain ⟨g, gsum, x₁, x₁_mem, nz⟩ := exists_nontrivial_relation_of_finrank_lt_card h' + -- Then obtain `f` by translating back by `x₀`, + -- and setting the value of `f` at `x₀` to ensure `∑ e in t, f e = 0`. + let f : V → R := fun z => if z = x₀ then -∑ z in t.erase x₀, g (z - x₀) else g (z - x₀) + refine' ⟨f, _, _, _⟩ + -- After this, it's a matter of verifying the properties, + -- based on the corresponding properties for `g`. + · show (∑ e : V in t, f e • e) = 0 + -- We prove this by splitting off the `x₀` term of the sum, + -- which is itself a sum over `t.erase x₀`, + -- combining the two sums, and + -- observing that after reindexing we have exactly + -- ∑ (x : V) in t', g x • x = 0. + simp only + conv_lhs => + apply_congr + rfl + rw [ite_smul] + rw [Finset.sum_ite] + conv => + congr + congr + apply_congr + -- Porting note: the next two steps used to work by `simp [filter_eq', m]` + erw [filter_eq'] + simp [m] + conv => + congr + congr + rfl + apply_congr + simp [filter_ne'] + rw [sum_singleton, neg_smul, add_comm, ← sub_eq_add_neg, sum_smul, ← sum_sub_distrib] + simp only [← smul_sub] + -- At the end we have to reindex the sum, so we use `change` to + -- express the summand using `shift`. + change (∑ x : V in t.erase x₀, (fun e => g e • e) (shift x)) = 0 + -- porting note: last argument can't be inferred + rw [← sum_map _ shift (fun e => g e • e)] + exact gsum + · show (∑ e : V in t, f e) = 0 + -- Again we split off the `x₀` term, + -- observing that it exactly cancels the other terms. + rw [← insert_erase m, sum_insert (not_mem_erase x₀ t)] + dsimp + rw [if_pos rfl] + conv_lhs => + congr + rfl + apply_congr + rfl + rw [if_neg (show _ ≠ x₀ from (mem_erase.mp ‹_›).1)] + exact neg_add_self _ + · show ∃ (x : V), x ∈ t ∧ f x ≠ 0 + -- We can use x₁ + x₀. + refine' ⟨x₁ + x₀, _, _⟩ + · rw [Finset.mem_map] at x₁_mem + rcases x₁_mem with ⟨x₁, x₁_mem, rfl⟩ + rw [mem_erase] at x₁_mem + simp only [x₁_mem, sub_add_cancel, Function.Embedding.coeFn_mk] + · dsimp only + rwa [if_neg, add_sub_cancel] + rw [add_left_eq_self] + rintro rfl + simp only [sub_eq_zero, exists_prop, Finset.mem_map, Embedding.coeFn_mk, eq_self_iff_true, + mem_erase, not_true, exists_eq_right, Ne.def, false_and_iff] at x₁_mem +#align finite_dimensional.exists_nontrivial_relation_sum_zero_of_rank_succ_lt_card Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card + +end + +end DivisionRing + +section ZeroRank + +variable [Ring R] [StrongRankCondition R] [AddCommGroup V] [Module R V] + +attribute [local instance] nontrivial_of_invariantBasisNumber + +open FiniteDimensional + +theorem Module.finite_of_rank_eq_nat [Module.Free R V] {n : ℕ} (h : Module.rank R V = n) : + Module.Finite R V := by + have := Cardinal.mk_lt_aleph0_iff.mp + (((Free.rank_eq_card_chooseBasisIndex R V).symm.trans h).trans_lt (nat_lt_aleph0 n)) + exact Module.Finite.of_basis (Free.chooseBasis R V) + +theorem Module.finite_of_rank_eq_zero [NoZeroSMulDivisors R V] + (h : Module.rank R V = 0) : + Module.Finite R V := by + rw [rank_zero_iff] at h + infer_instance + +theorem Module.finite_of_rank_eq_one [Module.Free R V] (h : Module.rank R V = 1) : + Module.Finite R V := + Module.finite_of_rank_eq_nat <| h.trans Nat.cast_one.symm + +theorem FiniteDimensional.finrank_eq_zero_of_rank_eq_zero (h : Module.rank R V = 0) : + finrank R V = 0 := by + delta finrank + rw [h, zero_toNat] +#align finrank_eq_zero_of_rank_eq_zero FiniteDimensional.finrank_eq_zero_of_rank_eq_zero + +variable (R V) + +instance Module.finite_bot : Module.Finite R (⊥ : Submodule R V) := inferInstance + +variable {R V} + +theorem Submodule.bot_eq_top_of_rank_eq_zero [NoZeroSMulDivisors R V] (h : Module.rank R V = 0) : + (⊥ : Submodule R V) = ⊤ := by + rw [rank_zero_iff] at h + exact Subsingleton.elim _ _ +#align bot_eq_top_of_rank_eq_zero Submodule.bot_eq_top_of_rank_eq_zero + +@[simp] +theorem Submodule.rank_eq_zero [NoZeroSMulDivisors R V] {S : Submodule R V} : + Module.rank R S = 0 ↔ S = ⊥ := + ⟨fun h => + (Submodule.eq_bot_iff _).2 fun x hx => + congr_arg Subtype.val <| + ((Submodule.eq_bot_iff _).1 <| Eq.symm <| Submodule.bot_eq_top_of_rank_eq_zero h) ⟨x, hx⟩ + Submodule.mem_top, + fun h => by rw [h, rank_bot]⟩ +#align rank_eq_zero Submodule.rank_eq_zero + +@[simp] +theorem Submodule.finrank_eq_zero [NoZeroSMulDivisors R V] {S : Submodule R V} [Module.Finite R S] : + finrank R S = 0 ↔ S = ⊥ := by + rw [← Submodule.rank_eq_zero, ← finrank_eq_rank, ← @Nat.cast_zero Cardinal, Cardinal.natCast_inj] +#align finrank_eq_zero Submodule.finrank_eq_zero + +end ZeroRank + +namespace Submodule + +open IsNoetherian FiniteDimensional + +variable [AddCommGroup V] [Ring R] [StrongRankCondition R] [Module R V] + +theorem fg_iff_finite (s : Submodule R V) : s.FG ↔ Module.Finite R s := + (finite_def.trans (fg_top s)).symm + +/-- The sup of two fg submodules is finite. Also see `Submodule.FG.sup`. -/ +instance finite_sup (S₁ S₂ : Submodule R V) [h₁ : Module.Finite R S₁] + [h₂ : Module.Finite R S₂] : Module.Finite R (S₁ ⊔ S₂ : Submodule R V) := by + rw [finite_def] at * + exact (fg_top _).2 (((fg_top S₁).1 h₁).sup ((fg_top S₂).1 h₂)) + +/-- The submodule generated by a finite supremum of finite dimensional submodules is +finite-dimensional. + +Note that strictly this only needs `∀ i ∈ s, FiniteDimensional K (S i)`, but that doesn't +work well with typeclass search. -/ +instance finite_finset_sup {ι : Type*} (s : Finset ι) (S : ι → Submodule R V) + [∀ i, Module.Finite R (S i)] : Module.Finite R (s.sup S : Submodule R V) := by + refine' + @Finset.sup_induction _ _ _ _ s S (fun i => Module.Finite R ↑i) (Module.finite_bot R V) + _ fun i _ => by infer_instance + · intro S₁ hS₁ S₂ hS₂ + exact Submodule.finite_sup S₁ S₂ + +/-- The submodule generated by a supremum of finite dimensional submodules, indexed by a finite +sort is finite-dimensional. -/ +instance finite_iSup {ι : Sort*} [Finite ι] (S : ι → Submodule R V) + [∀ i, Module.Finite R (S i)] : Module.Finite R ↑(⨆ i, S i) := by + cases nonempty_fintype (PLift ι) + rw [← iSup_plift_down, ← Finset.sup_univ_eq_iSup] + exact Submodule.finite_finset_sup _ _ + +end Submodule + +section + +variable [Ring R] [StrongRankCondition R] [AddCommGroup V] [Module R V] + +instance Module.Finite.finsupp {ι : Type*} [_root_.Finite ι] [Module.Finite R V] : + Module.Finite R (ι →₀ V) := + Module.Finite.equiv (Finsupp.linearEquivFunOnFinite R V ι).symm + +end diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean index 60d510360cfc4..03dc54465341c 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean @@ -448,7 +448,7 @@ theorem addHaar_ball_of_pos (x : E) {r : ℝ} (hr : 0 < r) : theorem addHaar_ball_mul [Nontrivial E] (x : E) {r : ℝ} (hr : 0 ≤ r) (s : ℝ) : μ (ball x (r * s)) = ENNReal.ofReal (r ^ finrank ℝ E) * μ (ball 0 s) := by rcases hr.eq_or_lt with (rfl | h) - · simp only [zero_pow (finrank_pos (K := ℝ) (V := E)), measure_empty, zero_mul, + · simp only [zero_pow (finrank_pos (R := ℝ) (V := E)), measure_empty, zero_mul, ENNReal.ofReal_zero, ball_zero] · exact addHaar_ball_mul_of_pos μ x h s #align measure_theory.measure.add_haar_ball_mul MeasureTheory.Measure.addHaar_ball_mul diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index cc448dc748335..4cb5b954b4aad 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -588,6 +588,11 @@ theorem of_surjective [hM : Finite R M] (f : M →ₗ[R] N) (hf : Surjective f) exact hM.1.map f⟩ #align module.finite.of_surjective Module.Finite.of_surjective +instance quotient (R) {A M} [Semiring R] [AddCommGroup M] [Ring A] [Module A M] [Module R M] + [SMul R A] [IsScalarTower R A M] [Finite R M] + (N : Submodule A M) : Finite R (M ⧸ N) := + Module.Finite.of_surjective (N.mkQ.restrictScalars R) N.mkQ_surjective + /-- The range of a linear map from a finite module is finite. -/ instance range [Finite R M] (f : M →ₗ[R] N) : Finite R (LinearMap.range f) := of_surjective f.rangeRestrict fun ⟨_, y, hy⟩ => ⟨y, Subtype.ext hy⟩ diff --git a/Mathlib/Topology/Algebra/Module/Basic.lean b/Mathlib/Topology/Algebra/Module/Basic.lean index 72e581dbfc63a..6d5ac30602e06 100644 --- a/Mathlib/Topology/Algebra/Module/Basic.lean +++ b/Mathlib/Topology/Algebra/Module/Basic.lean @@ -714,6 +714,9 @@ theorem one_apply (x : M₁) : (1 : M₁ →L[R₁] M₁) x = x := rfl #align continuous_linear_map.one_apply ContinuousLinearMap.one_apply +instance [Nontrivial M₁] : Nontrivial (M₁ →L[R₁] M₁) := + ⟨0, 1, fun e ↦ have ⟨x, hx⟩ := exists_ne (0 : M₁); hx (by simpa using FunLike.congr_fun e.symm x)⟩ + section Add variable [ContinuousAdd M₂] diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index afb64a2a6e7f9..fda352aed6b75 100644 --- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean +++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean @@ -133,7 +133,7 @@ theorem LinearMap.continuous_of_isClosed_ker (l : E →ₗ[𝕜] 𝕜) Continuous l := by -- `l` is either constant or surjective. If it is constant, the result is trivial. by_cases H : finrank 𝕜 (LinearMap.range l) = 0 - · rw [finrank_eq_zero, LinearMap.range_eq_bot] at H + · rw [Submodule.finrank_eq_zero, LinearMap.range_eq_bot] at H rw [H] exact continuous_zero · -- In the case where `l` is surjective, we factor it as `φ : (E ⧸ l.ker) ≃ₗ[𝕜] 𝕜`. Note that @@ -225,7 +225,7 @@ private theorem continuous_equivFun_basis_aux [ht2 : T2Space E] {ι : Type v} [F have H₂ : ∀ f : E →ₗ[𝕜] 𝕜, Continuous f := by intro f by_cases H : finrank 𝕜 (LinearMap.range f) = 0 - · rw [finrank_eq_zero, LinearMap.range_eq_bot] at H + · rw [Submodule.finrank_eq_zero, LinearMap.range_eq_bot] at H rw [H] exact continuous_zero · have : finrank 𝕜 (LinearMap.ker f) = n := by From 6c05c410db4e12a6f2780f07d6dac01115a5f55f Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 18 Dec 2023 13:47:29 +0000 Subject: [PATCH 058/353] feat(Algebra/Star/Order): more lemmas (#9096) --- Mathlib/Algebra/Order/Ring/Star.lean | 13 +---- Mathlib/Algebra/Star/Order.lean | 73 +++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/Mathlib/Algebra/Order/Ring/Star.lean b/Mathlib/Algebra/Order/Ring/Star.lean index 13b4b35f6981f..3d5b271af22e8 100644 --- a/Mathlib/Algebra/Order/Ring/Star.lean +++ b/Mathlib/Algebra/Order/Ring/Star.lean @@ -27,17 +27,8 @@ type class assumptions to be satisfied without a `CommSemiring` intance already it is impossible, only that it shouldn't occur in practice. -/ example {R : Type*} [OrderedSemiring R] [StarOrderedRing R] {x y : R} (hx : 0 ≤ x) (hy : 0 ≤ y) : x * y = y * x := by - -- nonnegative elements are self-adjoint; we prove it by hand to avoid adding imports - have : ∀ z : R, 0 ≤ z → star z = z := by - intros z hz - rw [nonneg_iff] at hz - induction hz using AddSubmonoid.closure_induction' with - | Hs _ h => obtain ⟨x, rfl⟩ := h; simp - | H1 => simp - | Hmul x hx y hy => simp only [← nonneg_iff] at hx hy; aesop - -- `0 ≤ y * x`, and hence `y * x` is self-adjoint - have := this _ <| mul_nonneg hy hx - aesop + rw [← IsSelfAdjoint.of_nonneg (mul_nonneg hy hx), star_mul, IsSelfAdjoint.of_nonneg hx, + IsSelfAdjoint.of_nonneg hy] /- This will be implied by the instance below, we only prove it to avoid duplicating the argument in the instance below for `mul_le_mul_of_nonneg_right`. -/ diff --git a/Mathlib/Algebra/Star/Order.lean b/Mathlib/Algebra/Star/Order.lean index 715476260bc80..fe8c3756b67a2 100644 --- a/Mathlib/Algebra/Star/Order.lean +++ b/Mathlib/Algebra/Star/Order.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ -import Mathlib.Algebra.Star.Basic +import Mathlib.Algebra.Star.SelfAdjoint import Mathlib.GroupTheory.Submonoid.Basic #align_import algebra.star.order from "leanprover-community/mathlib"@"31c24aa72e7b3e5ed97a8412470e904f82b81004" @@ -185,4 +185,75 @@ theorem conjugate_le_conjugate' {a b : R} (hab : a ≤ b) (c : R) : c * a * star by simpa only [star_star] using conjugate_le_conjugate hab (star c) #align conjugate_le_conjugate' conjugate_le_conjugate' +@[simp] +lemma star_le_star_iff {x y : R} : star x ≤ star y ↔ x ≤ y := by + suffices ∀ x y, x ≤ y → star x ≤ star y from + ⟨by simpa only [star_star] using this (star x) (star y), this x y⟩ + intro x y h + rw [StarOrderedRing.le_iff] at h ⊢ + obtain ⟨d, hd, rfl⟩ := h + refine ⟨starAddEquiv d, ?_, star_add _ _⟩ + refine AddMonoidHom.mclosure_preimage_le _ _ <| AddSubmonoid.closure_mono ?_ hd + rintro - ⟨s, rfl⟩ + exact ⟨s, by simp⟩ + +@[simp] +lemma star_lt_star_iff {x y : R} : star x < star y ↔ x < y := by + by_cases h : x = y + · simp [h] + · simpa [le_iff_lt_or_eq, h] using star_le_star_iff (x := x) (y := y) + +lemma star_le_iff {x y : R} : star x ≤ y ↔ x ≤ star y := by rw [← star_le_star_iff, star_star] + +lemma star_lt_iff {x y : R} : star x < y ↔ x < star y := by rw [← star_lt_star_iff, star_star] + +@[simp] +lemma star_nonneg_iff {x : R} : 0 ≤ star x ↔ 0 ≤ x := by + simpa using star_le_star_iff (x := 0) (y := x) + +@[simp] +lemma star_nonpos_iff {x : R} : star x ≤ 0 ↔ x ≤ 0 := by + simpa using star_le_star_iff (x := x) (y := 0) + +@[simp] +lemma star_pos_iff {x : R} : 0 < star x ↔ 0 < x := by + simpa using star_lt_star_iff (x := 0) (y := x) + +@[simp] +lemma star_neg_iff {x : R} : star x < 0 ↔ x < 0 := by + simpa using star_lt_star_iff (x := x) (y := 0) + +lemma IsSelfAdjoint.mono {x y : R} (h : x ≤ y) (hx : IsSelfAdjoint x) : IsSelfAdjoint y := by + rw [StarOrderedRing.le_iff] at h + obtain ⟨d, hd, rfl⟩ := h + rw [IsSelfAdjoint, star_add, hx.star_eq] + congr + refine AddMonoidHom.eqOn_closureM (f := starAddEquiv (R := R)) (g := .id R) ?_ hd + rintro - ⟨s, rfl⟩ + simp + +lemma IsSelfAdjoint.of_nonneg {x : R} (hx : 0 ≤ x) : IsSelfAdjoint x := + (isSelfAdjoint_zero R).mono hx + end NonUnitalSemiring + +section Semiring +variable [Semiring R] [PartialOrder R] [StarOrderedRing R] + +@[simp] +lemma one_le_star_iff {x : R} : 1 ≤ star x ↔ 1 ≤ x := by + simpa using star_le_star_iff (x := 1) (y := x) + +@[simp] +lemma star_le_one_iff {x : R} : star x ≤ 1 ↔ x ≤ 1 := by + simpa using star_le_star_iff (x := x) (y := 1) + +@[simp] +lemma one_lt_star_iff {x : R} : 1 < star x ↔ 1 < x := by + simpa using star_lt_star_iff (x := 1) (y := x) + +@[simp] +lemma star_lt_one_iff {x : R} : star x < 1 ↔ x < 1 := by + simpa using star_lt_star_iff (x := x) (y := 1) + +end Semiring From 9e1e18da15a810d7f193da8afc09b6fcc89bd5dd Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Mon, 18 Dec 2023 13:47:30 +0000 Subject: [PATCH 059/353] feat: Restriction of galois group onto integrally closed subrings. (#9113) Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 1 + Mathlib/NumberTheory/NumberField/Basic.lean | 2 +- .../DedekindDomain/IntegralClosure.lean | 15 ++- Mathlib/RingTheory/IntegralRestrict.lean | 121 ++++++++++++++++++ 4 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 Mathlib/RingTheory/IntegralRestrict.lean diff --git a/Mathlib.lean b/Mathlib.lean index 35cad24521ea9..8bd2eb421ebf6 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3070,6 +3070,7 @@ import Mathlib.RingTheory.Ideal.QuotientOperations import Mathlib.RingTheory.Int.Basic import Mathlib.RingTheory.IntegralClosure import Mathlib.RingTheory.IntegralDomain +import Mathlib.RingTheory.IntegralRestrict import Mathlib.RingTheory.IntegrallyClosed import Mathlib.RingTheory.IsAdjoinRoot import Mathlib.RingTheory.IsTensorProduct diff --git a/Mathlib/NumberTheory/NumberField/Basic.lean b/Mathlib/NumberTheory/NumberField/Basic.lean index 0c9c5896b60fc..fc9a2847b6041 100644 --- a/Mathlib/NumberTheory/NumberField/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Basic.lean @@ -146,7 +146,7 @@ instance : Free ℤ (𝓞 K) := IsIntegralClosure.module_free ℤ ℚ K (𝓞 K) instance : IsLocalization (Algebra.algebraMapSubmonoid (𝓞 K) ℤ⁰) K := - IsIntegralClosure.isLocalization ℤ ℚ K (𝓞 K) + IsIntegralClosure.isLocalization_of_isSeparable ℤ ℚ K (𝓞 K) /-- A ℤ-basis of the ring of integers of `K`. -/ noncomputable def basis : Basis (Free.ChooseBasisIndex ℤ (𝓞 K)) ℤ (𝓞 K) := diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index 24f2f23df8ec1..f62909baf08d2 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -64,12 +64,13 @@ variable [Algebra K L] [Algebra A L] [IsScalarTower A K L] variable [Algebra C L] [IsIntegralClosure C A L] [Algebra A C] [IsScalarTower A C L] -/- If `L` is a separable extension of `K = Frac(A)` and `L` has no zero smul divisors by `A`, +/- If `L` is an algebraic extension of `K = Frac(A)` and `L` has no zero smul divisors by `A`, then `L` is the localization of the integral closure `C` of `A` in `L` at `A⁰`. -/ -theorem IsIntegralClosure.isLocalization [IsSeparable K L] [NoZeroSMulDivisors A L] : +theorem IsIntegralClosure.isLocalization (hKL : Algebra.IsAlgebraic K L) : IsLocalization (Algebra.algebraMapSubmonoid C A⁰) L := by haveI : IsDomain C := (IsIntegralClosure.equiv A C L (integralClosure A L)).toMulEquiv.isDomain (integralClosure A L) + haveI : NoZeroSMulDivisors A L := NoZeroSMulDivisors.trans A K L haveI : NoZeroSMulDivisors A C := IsIntegralClosure.noZeroSMulDivisors A L refine' ⟨_, fun z => _, fun {x y} h => ⟨1, _⟩⟩ · rintro ⟨_, x, hx, rfl⟩ @@ -77,13 +78,17 @@ theorem IsIntegralClosure.isLocalization [IsSeparable K L] [NoZeroSMulDivisors A Subtype.coe_mk, map_ne_zero_iff _ (NoZeroSMulDivisors.algebraMap_injective A C)] exact mem_nonZeroDivisors_iff_ne_zero.mp hx · obtain ⟨m, hm⟩ := - IsIntegral.exists_multiple_integral_of_isLocalization A⁰ z (IsSeparable.isIntegral K z) + IsIntegral.exists_multiple_integral_of_isLocalization A⁰ z (hKL z).isIntegral obtain ⟨x, hx⟩ : ∃ x, algebraMap C L x = m • z := IsIntegralClosure.isIntegral_iff.mp hm refine' ⟨⟨x, algebraMap A C m, m, SetLike.coe_mem m, rfl⟩, _⟩ rw [Subtype.coe_mk, ← IsScalarTower.algebraMap_apply, hx, mul_comm, Submonoid.smul_def, smul_def] · simp only [IsIntegralClosure.algebraMap_injective C A L h] -#align is_integral_closure.is_localization IsIntegralClosure.isLocalization + +theorem IsIntegralClosure.isLocalization_of_isSeparable [IsSeparable K L] : + IsLocalization (Algebra.algebraMapSubmonoid C A⁰) L := + IsIntegralClosure.isLocalization A K L C (IsSeparable.isAlgebraic _ _) +#align is_integral_closure.is_localization IsIntegralClosure.isLocalization_of_isSeparable variable [FiniteDimensional K L] @@ -210,7 +215,7 @@ theorem IsIntegralClosure.rank [IsPrincipalIdealRing A] [NoZeroSMulDivisors A L] haveI : Module.Free A C := IsIntegralClosure.module_free A K L C haveI : IsNoetherian A C := IsIntegralClosure.isNoetherian A K L C haveI : IsLocalization (Algebra.algebraMapSubmonoid C A⁰) L := - IsIntegralClosure.isLocalization A K L C + IsIntegralClosure.isLocalization A K L C (Algebra.IsIntegral.of_finite _ _).isAlgebraic let b := Basis.localizationLocalization K A⁰ L (Module.Free.chooseBasis A C) rw [FiniteDimensional.finrank_eq_card_chooseBasisIndex, FiniteDimensional.finrank_eq_card_basis b] #align is_integral_closure.rank IsIntegralClosure.rank diff --git a/Mathlib/RingTheory/IntegralRestrict.lean b/Mathlib/RingTheory/IntegralRestrict.lean new file mode 100644 index 0000000000000..6b8c14ce86206 --- /dev/null +++ b/Mathlib/RingTheory/IntegralRestrict.lean @@ -0,0 +1,121 @@ +/- +Copyright (c) 2023 Andrew Yang, Patrick Lutz. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.RingTheory.IntegrallyClosed +import Mathlib.RingTheory.Norm +import Mathlib.RingTheory.DedekindDomain.IntegralClosure +/-! +# Restriction of various maps between fields to integrally closed subrings. + +In this file, we assume `A` is an integrally closed domain; `K` is the fraction ring of `A`; +`L` is a finite (separable) extension of `K`; `B` is the integral closure of `A` in `L`. +We call this the AKLB setup. + +## Main definition +- `galRestrict`: The restriction `Aut(L/K) → Aut(B/A)` as an `MulEquiv` in an AKLB setup. + +## TODO +Define the restriction of norms and traces. + +-/ +open BigOperators nonZeroDivisors + +variable (A K L B : Type*) [CommRing A] [CommRing B] [Algebra A B] [Field K] [Field L] + [Algebra A K] [IsFractionRing A K] [Algebra B L] + [Algebra K L] [Algebra A L] [IsScalarTower A B L] [IsScalarTower A K L] + [IsIntegralClosure B A L] [FiniteDimensional K L] + +/-- The lift `End(B/A) → End(L/K)` in an ALKB setup. +This is inverse to the restriction. See `galRestrictHom`. -/ +noncomputable +def galLift (σ : B →ₐ[A] B) : L →ₐ[K] L := + haveI := (IsFractionRing.injective A K).isDomain + haveI := NoZeroSMulDivisors.trans A K L + haveI := IsIntegralClosure.isLocalization A K L B (Algebra.IsIntegral.of_finite _ _).isAlgebraic + haveI H : ∀ (y : Algebra.algebraMapSubmonoid B A⁰), + IsUnit (((algebraMap B L).comp σ) (y : B)) := by + rintro ⟨_, x, hx, rfl⟩ + simpa only [RingHom.coe_comp, RingHom.coe_coe, Function.comp_apply, AlgHom.commutes, + isUnit_iff_ne_zero, ne_eq, map_eq_zero_iff _ (NoZeroSMulDivisors.algebraMap_injective _ _), + ← IsScalarTower.algebraMap_apply] using nonZeroDivisors.ne_zero hx + haveI H_eq : (IsLocalization.lift (S := L) H).comp (algebraMap K L) = (algebraMap K L) := by + apply IsLocalization.ringHom_ext A⁰ + ext + simp only [RingHom.coe_comp, Function.comp_apply, ← IsScalarTower.algebraMap_apply A K L, + IsScalarTower.algebraMap_apply A B L, IsLocalization.lift_eq, + RingHom.coe_coe, AlgHom.commutes] + { IsLocalization.lift (S := L) H with commutes' := FunLike.congr_fun H_eq } + +/-- The restriction `End(L/K) → End(B/A)` in an AKLB setup. +Also see `galRestrict` for the `AlgEquiv` version. -/ +noncomputable +def galRestrictHom : (L →ₐ[K] L) ≃* (B →ₐ[A] B) where + toFun := fun f ↦ (IsIntegralClosure.equiv A (integralClosure A L) L B).toAlgHom.comp + (((f.restrictScalars A).comp (IsScalarTower.toAlgHom A B L)).codRestrict + (integralClosure A L) (fun x ↦ IsIntegral.map _ (IsIntegralClosure.isIntegral A L x))) + map_mul' := by + intros σ₁ σ₂ + ext x + apply (IsIntegralClosure.equiv A (integralClosure A L) L B).symm.injective + ext + dsimp + simp only [AlgEquiv.symm_apply_apply, AlgHom.coe_codRestrict, AlgHom.coe_comp, + AlgHom.coe_restrictScalars', IsScalarTower.coe_toAlgHom', Function.comp_apply, + AlgHom.mul_apply, IsIntegralClosure.algebraMap_equiv, Subalgebra.algebraMap_eq] + rfl + invFun := galLift A K L B + left_inv σ := + have := (IsFractionRing.injective A K).isDomain + have := IsIntegralClosure.isLocalization A K L B (Algebra.IsIntegral.of_finite _ _).isAlgebraic + AlgHom.coe_ringHom_injective <| IsLocalization.ringHom_ext (Algebra.algebraMapSubmonoid B A⁰) + <| RingHom.ext fun x ↦ by simp [Subalgebra.algebraMap_eq, galLift] + right_inv σ := + have := (IsFractionRing.injective A K).isDomain + have := IsIntegralClosure.isLocalization A K L B (Algebra.IsIntegral.of_finite _ _).isAlgebraic + AlgHom.ext fun x ↦ + IsIntegralClosure.algebraMap_injective B A L (by simp [Subalgebra.algebraMap_eq, galLift]) + +@[simp] +lemma algebraMap_galRestrictHom_apply (σ : L →ₐ[K] L) (x : B) : + algebraMap B L (galRestrictHom A K L B σ x) = σ (algebraMap B L x) := by + simp [galRestrictHom, Subalgebra.algebraMap_eq] + +@[simp, nolint unusedHavesSuffices] -- false positive from unfolding galRestrictHom +lemma galRestrictHom_symm_algebraMap_apply (σ : B →ₐ[A] B) (x : B) : + (galRestrictHom A K L B).symm σ (algebraMap B L x) = algebraMap B L (σ x) := by + have := (IsFractionRing.injective A K).isDomain + have := IsIntegralClosure.isLocalization A K L B (Algebra.IsIntegral.of_finite _ _).isAlgebraic + simp [galRestrictHom, galLift, Subalgebra.algebraMap_eq] + +/-- The restriction `Aut(L/K) → Aut(B/A)` in an AKLB setup. -/ +noncomputable +def galRestrict : (L ≃ₐ[K] L) ≃* (B ≃ₐ[A] B) := + (AlgEquiv.algHomUnitsEquiv K L).symm.trans + ((Units.mapEquiv <| galRestrictHom A K L B).trans (AlgEquiv.algHomUnitsEquiv A B)) + +variable {K L} + +lemma coe_galRestrict_apply (σ : L ≃ₐ[K] L) : + (galRestrict A K L B σ : B →ₐ[A] B) = galRestrictHom A K L B σ := rfl + +variable {B} + +lemma galRestrict_apply (σ : L ≃ₐ[K] L) (x : B) : + galRestrict A K L B σ x = galRestrictHom A K L B σ x := rfl + +lemma algebraMap_galRestrict_apply (σ : L ≃ₐ[K] L) (x : B) : + algebraMap B L (galRestrict A K L B σ x) = σ (algebraMap B L x) := + algebraMap_galRestrictHom_apply A K L B σ.toAlgHom x + +variable (K L B) + +lemma prod_galRestrict_eq_norm [IsGalois K L] [IsIntegrallyClosed A] (x : B) : + (∏ σ : L ≃ₐ[K] L, galRestrict A K L B σ x) = + algebraMap A B (IsIntegralClosure.mk' (R := A) A (Algebra.norm K <| algebraMap B L x) + (Algebra.isIntegral_norm K (IsIntegralClosure.isIntegral A L x).algebraMap)) := by + apply IsIntegralClosure.algebraMap_injective B A L + rw [← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_eq A K L] + simp only [map_prod, algebraMap_galRestrict_apply, IsIntegralClosure.algebraMap_mk', + Algebra.norm_eq_prod_automorphisms, AlgHom.coe_coe, RingHom.coe_comp, Function.comp_apply] From a3e8d01e04f285df56c4b2a60eaf393b3fceb2ac Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Mon, 18 Dec 2023 16:03:42 +0000 Subject: [PATCH 060/353] =?UTF-8?q?feat:=20injective=20bilinear=20pairing?= =?UTF-8?q?=20V=E2=86=92W*=20with=20V=20f.d.=20induces=20surjective=20W?= =?UTF-8?q?=E2=86=92V*=20(#8820)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the Hairer challenge + add `flip_in/sur/bijective_iff₁₂`: if either of the spaces V and W is finite-dimensional, a linear map `V → W*` is injective/surjective/bijective iff the flipped map `W → V*` is surjective/injective/bijective. + also add consequence for SeparatingDual from the [projective space thread](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Projective.20space/near/392642695) (cc @smorel394) + remove the `FiniteDimensional` condition from `dual_finrank_eq`, `finrank_range_dualMap_eq_finrank_range`, and `dualMap_injective/bijective_iff`, completing two TODO items by @kmill + add two lemmas `toDual_injective` and `finite_dual_iff` + golf several proofs in LinearAlgebra/Dual Co-authored-by: Kyle Miller Co-authored-by: Junyan Xu --- .../HahnBanach/SeparatingDual.lean | 22 ++ Mathlib/LinearAlgebra/Dimension.lean | 38 ++- Mathlib/LinearAlgebra/Dual.lean | 252 ++++++++---------- 3 files changed, 142 insertions(+), 170 deletions(-) diff --git a/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean b/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean index fb07426e93fcc..0062fb9613dbe 100644 --- a/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean +++ b/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean @@ -5,6 +5,7 @@ Authors: Sébastien Gouëzel -/ import Mathlib.Analysis.NormedSpace.HahnBanach.Extension import Mathlib.Analysis.NormedSpace.HahnBanach.Separation +import Mathlib.LinearAlgebra.Dual /-! # Spaces with separating dual @@ -22,6 +23,7 @@ equivalences acts transitively on the set of nonzero vectors. /-- When `E` is a topological module over a topological ring `R`, the class `SeparatingDual R E` registers that continuous linear forms on `E` separate points of `E`. -/ +@[mk_iff separatingDual_def] class SeparatingDual (R V : Type*) [Ring R] [AddCommGroup V] [TopologicalSpace V] [TopologicalSpace R] [Module R V] : Prop := /-- Any nonzero vector can be mapped by a continuous linear map to a nonzero scalar. -/ @@ -73,6 +75,26 @@ section Field variable {R V : Type*} [Field R] [AddCommGroup V] [TopologicalSpace R] [TopologicalSpace V] [TopologicalRing R] [TopologicalAddGroup V] [Module R V] [SeparatingDual R V] +-- TODO (@alreadydone): this could generalize to CommRing R if we were to add a section +theorem _root_.separatingDual_iff_injective : SeparatingDual R V ↔ + Function.Injective (ContinuousLinearMap.coeLM (R := R) R (M := V) (N₃ := R)).flip := by + simp_rw [separatingDual_def, Ne, injective_iff_map_eq_zero] + congrm ∀ v, ?_ + rw [not_imp_comm, LinearMap.ext_iff] + push_neg; rfl + +open Function in +/-- Given a finite-dimensional subspace `W` of a space `V` with separating dual, any + linear functional on `W` extends to a continuous linear functional on `V`. + This is stated more generally for an injective linear map from `W` to `V`. -/ +theorem dualMap_surjective_iff {W} [AddCommGroup W] [Module R W] [FiniteDimensional R W] + {f : W →ₗ[R] V} : Surjective (f.dualMap ∘ ContinuousLinearMap.toLinearMap) ↔ Injective f := by + constructor <;> intro hf + · exact LinearMap.dualMap_surjective_iff.mp hf.of_comp + have := (separatingDual_iff_injective.mp ‹_›).comp hf + rw [← LinearMap.coe_comp] at this + exact LinearMap.flip_surjective_iff₁.mpr this + lemma exists_eq_one {x : V} (hx : x ≠ 0) : ∃ f : V →L[R] R, f x = 1 := by rcases exists_ne_zero (R := R) hx with ⟨f, hf⟩ diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean index ce91bab259f73..498fb191118c6 100644 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ b/Mathlib/LinearAlgebra/Dimension.lean @@ -128,7 +128,7 @@ theorem LinearMap.lift_rank_le_of_injective (f : M →ₗ[R] M') (i : Injective apply ciSup_mono' (Cardinal.bddAbove_range.{v', v} _) rintro ⟨s, li⟩ refine' ⟨⟨f '' s, _⟩, Cardinal.lift_mk_le'.mpr ⟨(Equiv.Set.image f s i).toEmbedding⟩⟩ - exact (li.map' _ <| LinearMap.ker_eq_bot.mpr i).image + exact (li.map' _ <| LinearMap.ker_eq_bot_of_injective i).image #align linear_map.lift_rank_le_of_injective LinearMap.lift_rank_le_of_injective theorem LinearMap.rank_le_of_injective (f : M →ₗ[R] M₁) (i : Injective f) : @@ -347,8 +347,7 @@ lemma basis_finite_of_finite_spans (w : Set M) (hw : w.Finite) (s : span R w = rw [k] exact mem_top -- giving the desire contradiction. - refine' b.linearIndependent.not_mem_span_image _ k' - exact nm + exact b.linearIndependent.not_mem_span_image nm k' #align basis_fintype_of_finite_spans basis_finite_of_finite_spansₓ -- From [Les familles libres maximales d'un module ont-elles le meme cardinal?][lazarus1973] @@ -382,18 +381,10 @@ theorem union_support_maximal_linearIndependent_eq_range_basis {ι : Type w} (b rfl rw [← e] at p exact r' p - have inj' : Injective v' := by - rintro (_ | k) (_ | k) z - · rfl - · exfalso - exact r' ⟨k, z.symm⟩ - · exfalso - exact r' ⟨k, z⟩ - · congr - exact i.injective z -- The key step in the proof is checking that this strictly larger family is linearly independent. have i' : LinearIndependent R ((↑) : range v' → M) := by - rw [linearIndependent_subtype_range inj', linearIndependent_iff] + apply LinearIndependent.to_subtype_range + rw [linearIndependent_iff] intro l z rw [Finsupp.total_option] at z simp only [Option.elim'] at z @@ -418,7 +409,7 @@ theorem union_support_maximal_linearIndependent_eq_range_basis {ι : Type w} (b · simp only [l₀, Finsupp.coe_zero, Pi.zero_apply] · erw [FunLike.congr_fun l₁ a] simp only [Finsupp.coe_zero, Pi.zero_apply] - dsimp [LinearIndependent.Maximal] at m + rw [LinearIndependent.Maximal] at m specialize m (range v') i' r exact r'' m #align union_support_maximal_linear_independent_eq_range_basis union_support_maximal_linearIndependent_eq_range_basis @@ -709,14 +700,15 @@ then any linearly independent family `v : ι → M` contained in the span of some finite `w : Set M`, is itself finite. -/ -def linearIndependentFintypeOfLeSpanFintype {ι : Type*} (v : ι → M) (i : LinearIndependent R v) - (w : Set M) [Fintype w] (s : range v ≤ span R w) : Fintype ι := - fintypeOfFinsetCardLe (Fintype.card w) fun t => by +lemma LinearIndependent.finite_of_le_span_finite {ι : Type*} (v : ι → M) (i : LinearIndependent R v) + (w : Set M) [Finite w] (s : range v ≤ span R w) : Finite ι := + letI := Fintype.ofFinite w + Fintype.finite <| fintypeOfFinsetCardLe (Fintype.card w) fun t => by let v' := fun x : (t : Set ι) => v x have i' : LinearIndependent R v' := i.comp _ Subtype.val_injective have s' : range v' ≤ span R w := (range_comp_subset_range _ _).trans s simpa using linearIndependent_le_span_aux' v' i' w s' -#align linear_independent_fintype_of_le_span_fintype linearIndependentFintypeOfLeSpanFintype +#align linear_independent_fintype_of_le_span_fintype LinearIndependent.finite_of_le_span_finite /-- If `R` satisfies the strong rank condition, then for any linearly independent family `v : ι → M` @@ -725,7 +717,8 @@ the cardinality of `ι` is bounded by the cardinality of `w`. -/ theorem linearIndependent_le_span' {ι : Type*} (v : ι → M) (i : LinearIndependent R v) (w : Set M) [Fintype w] (s : range v ≤ span R w) : #ι ≤ Fintype.card w := by - haveI : Fintype ι := linearIndependentFintypeOfLeSpanFintype v i w s + haveI : Finite ι := i.finite_of_le_span_finite v w s + letI := Fintype.ofFinite ι rw [Cardinal.mk_fintype] simp only [Cardinal.natCast_le] exact linearIndependent_le_span_aux' v i w s @@ -761,8 +754,8 @@ theorem linearIndependent_le_infinite_basis {ι : Type w} (b : Basis ι R M) [In obtain ⟨s, w : Infinite ↑(Φ ⁻¹' {s})⟩ := Cardinal.exists_infinite_fiber Φ h (by infer_instance) let v' := fun k : Φ ⁻¹' {s} => v k have i' : LinearIndependent R v' := i.comp _ Subtype.val_injective - have w' : Fintype (Φ ⁻¹' {s}) := by - apply linearIndependentFintypeOfLeSpanFintype v' i' (s.image b) + have w' : Finite (Φ ⁻¹' {s}) := by + apply i'.finite_of_le_span_finite v' (s.image b) rintro m ⟨⟨p, ⟨rfl⟩⟩, rfl⟩ simp only [SetLike.mem_coe, Subtype.coe_mk, Finset.coe_image] apply Basis.mem_span_repr_support @@ -907,10 +900,11 @@ theorem rank_span_set {s : Set M} (hs : LinearIndependent R (fun x => x : s → finite free module `M`. A property is true for all submodules of `M` if it satisfies the following "inductive step": the property is true for a submodule `N` if it's true for all submodules `N'` of `N` with the property that there exists `0 ≠ x ∈ N` such that the sum `N' + Rx` is direct. -/ -def Submodule.inductionOnRank [IsDomain R] [Fintype ι] (b : Basis ι R M) +def Submodule.inductionOnRank [IsDomain R] [Finite ι] (b : Basis ι R M) (P : Submodule R M → Sort*) (ih : ∀ N : Submodule R M, (∀ N' ≤ N, ∀ x ∈ N, (∀ (c : R), ∀ y ∈ N', c • x + y = (0 : M) → c = 0) → P N') → P N) (N : Submodule R M) : P N := + letI := Fintype.ofFinite ι Submodule.inductionOnRankAux b P ih (Fintype.card ι) N fun hs hli => by simpa using b.card_le_card_of_linearIndependent hli #align submodule.induction_on_rank Submodule.inductionOnRank diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 21caf4bfb3d3d..9574160cc460d 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -4,10 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Fabian Glöckle, Kyle Miller -/ import Mathlib.LinearAlgebra.FiniteDimensional +import Mathlib.LinearAlgebra.FreeModule.Finite.Basic +import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition import Mathlib.LinearAlgebra.Projection import Mathlib.LinearAlgebra.SesquilinearForm -import Mathlib.RingTheory.Finiteness -import Mathlib.LinearAlgebra.FreeModule.Finite.Basic import Mathlib.RingTheory.TensorProduct #align_import linear_algebra.dual from "leanprover-community/mathlib"@"b1c017582e9f18d8494e5c18602a8cb4a6f843ac" @@ -229,17 +229,11 @@ theorem LinearMap.dualMap_injective_of_surjective {f : M₁ →ₗ[R] M₂} (hf #align linear_map.dual_map_injective_of_surjective LinearMap.dualMap_injective_of_surjective /-- The `Linear_equiv` version of `LinearMap.dualMap`. -/ -def LinearEquiv.dualMap (f : M₁ ≃ₗ[R] M₂) : Dual R M₂ ≃ₗ[R] Dual R M₁ := - { f.toLinearMap.dualMap with - invFun := f.symm.toLinearMap.dualMap - left_inv := by - intro φ; ext x - simp only [LinearMap.dualMap_apply, LinearEquiv.coe_toLinearMap, LinearMap.toFun_eq_coe, - LinearEquiv.apply_symm_apply] - right_inv := by - intro φ; ext x - simp only [LinearMap.dualMap_apply, LinearEquiv.coe_toLinearMap, LinearMap.toFun_eq_coe, - LinearEquiv.symm_apply_apply] } +def LinearEquiv.dualMap (f : M₁ ≃ₗ[R] M₂) : Dual R M₂ ≃ₗ[R] Dual R M₁ where + __ := f.toLinearMap.dualMap + invFun := f.symm.toLinearMap.dualMap + left_inv φ := LinearMap.ext fun x ↦ congr_arg φ (f.right_inv x) + right_inv φ := LinearMap.ext fun x ↦ congr_arg φ (f.left_inv x) #align linear_equiv.dual_map LinearEquiv.dualMap @[simp] @@ -347,12 +341,11 @@ theorem toDual_eq_equivFun [Fintype ι] (m : M) (i : ι) : b.toDual m (b i) = b. rw [b.equivFun_apply, toDual_eq_repr] #align basis.to_dual_eq_equiv_fun Basis.toDual_eq_equivFun -theorem toDual_inj (m : M) (a : b.toDual m = 0) : m = 0 := by - rw [← mem_bot R, ← b.repr.ker, mem_ker, LinearEquiv.coe_coe] - apply Finsupp.ext - intro b - rw [← toDual_eq_repr, a] - rfl +theorem toDual_injective : Injective b.toDual := fun x y h ↦ b.ext_elem_iff.mpr fun i ↦ by + simp_rw [← toDual_eq_repr]; exact FunLike.congr_fun h _ + +theorem toDual_inj (m : M) (a : b.toDual m = 0) : m = 0 := + b.toDual_injective (by rwa [_root_.map_zero]) #align basis.to_dual_inj Basis.toDual_inj -- Porting note: broken dot notation lean4#1910 LinearMap.ker @@ -362,10 +355,8 @@ theorem toDual_ker : LinearMap.ker b.toDual = ⊥ := -- Porting note: broken dot notation lean4#1910 LinearMap.range theorem toDual_range [Finite ι] : LinearMap.range b.toDual = ⊤ := by - cases nonempty_fintype ι refine' eq_top_iff'.2 fun f => _ - rw [LinearMap.mem_range] - let lin_comb : ι →₀ R := Finsupp.equivFunOnFinite.symm fun i => f.toFun (b i) + let lin_comb : ι →₀ R := Finsupp.equivFunOnFinite.symm fun i => f (b i) refine' ⟨Finsupp.total ι M R b lin_comb, b.ext fun i => _⟩ rw [b.toDual_eq_repr _ i, repr_total b] rfl @@ -499,15 +490,9 @@ theorem total_coord [CommRing R] [AddCommGroup M] [Module R M] [Finite ι] (b : rw [← coe_dualBasis, total_dualBasis] #align basis.total_coord Basis.total_coord --- Porting note: universes very dodgy in Cardinals... theorem dual_rank_eq [CommRing K] [AddCommGroup V] [Module K V] [Finite ι] (b : Basis ι K V) : Cardinal.lift.{uK,uV} (Module.rank K V) = Module.rank K (Dual K V) := by - classical - cases nonempty_fintype ι - have := LinearEquiv.lift_rank_eq b.toDualEquiv - rw [Cardinal.lift_umax.{uV,uK}] at this - rw [this, ← Cardinal.lift_umax] - apply Cardinal.lift_id + classical rw [← lift_umax.{uV,uK}, b.toDualEquiv.lift_rank_eq, lift_id'.{uV,uK}] #align basis.dual_rank_eq Basis.dual_rank_eq end Basis @@ -533,17 +518,15 @@ theorem eval_ker : LinearMap.ker (eval K V) = ⊥ := by theorem map_eval_injective : (Submodule.map (eval K V)).Injective := by apply Submodule.map_injective_of_injective rw [← LinearMap.ker_eq_bot] - apply eval_ker K V + exact eval_ker K V #align module.map_eval_injective Module.map_eval_injective --- elaborates faster than `exact` theorem comap_eval_surjective : (Submodule.comap (eval K V)).Surjective := by apply Submodule.comap_surjective_of_injective rw [← LinearMap.ker_eq_bot] - apply eval_ker K V + exact eval_ker K V #align module.comap_eval_surjective Module.comap_eval_surjective --- elaborates faster than `exact` end section @@ -585,6 +568,17 @@ theorem nontrivial_dual_iff : instance instNontrivialDual [Nontrivial V] : Nontrivial (Dual K V) := (nontrivial_dual_iff K).mpr inferInstance +theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by + constructor <;> intro h + · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) + nontriviality K + obtain ⟨⟨s, span_s⟩⟩ := h + classical + haveI := (b.linearIndependent.map' _ b.toDual_ker).finite_of_le_span_finite _ s ?_ + · exact Finite.of_basis b + · rw [span_s]; apply le_top + · infer_instance + end theorem dual_rank_eq [Module.Finite K V] : @@ -609,9 +603,9 @@ Any finitely-generated free module (and thus any finite-dimensional vector space See `Module.IsReflexive.of_finite_of_free`. -/ class IsReflexive : Prop where /-- A reflexive module is one for which the natural map to its double dual is a bijection. -/ - bijective_dual_eval' : Bijective $ Dual.eval R M + bijective_dual_eval' : Bijective (Dual.eval R M) -lemma bijective_dual_eval [IsReflexive R M] : Bijective $ Dual.eval R M := +lemma bijective_dual_eval [IsReflexive R M] : Bijective (Dual.eval R M) := IsReflexive.bijective_dual_eval' instance IsReflexive.of_finite_of_free [Finite R M] [Free R M] : IsReflexive R M where @@ -622,7 +616,7 @@ variable [IsReflexive R M] /-- The bijection between a reflexive module and its double dual, bundled as a `LinearEquiv`. -/ def evalEquiv : M ≃ₗ[R] Dual R (Dual R M) := - LinearEquiv.ofBijective _ $ bijective_dual_eval R M + LinearEquiv.ofBijective _ (bijective_dual_eval R M) #align module.eval_equiv Module.evalEquiv @[simp] lemma evalEquiv_toLinearMap : evalEquiv R M = Dual.eval R M := rfl @@ -630,7 +624,7 @@ def evalEquiv : M ≃ₗ[R] Dual R (Dual R M) := @[simp] lemma evalEquiv_apply (m : M) : evalEquiv R M m = Dual.eval R M m := rfl -@[simp] lemma apply_evalEquiv_symm_apply (f : Dual R M) (g : Dual R $ Dual R M) : +@[simp] lemma apply_evalEquiv_symm_apply (f : Dual R M) (g : Dual R (Dual R M)) : f ((evalEquiv R M).symm g) = g f := by set m := (evalEquiv R M).symm g rw [← (evalEquiv R M).apply_symm_apply g, evalEquiv_apply, Dual.eval_apply] @@ -1034,28 +1028,12 @@ theorem dualCoannihilator_top (W : Subspace K V) : @[simp] theorem dualAnnihilator_dualCoannihilator_eq {W : Subspace K V} : W.dualAnnihilator.dualCoannihilator = W := by - refine' le_antisymm _ (le_dualAnnihilator_dualCoannihilator _) - intro v + refine le_antisymm (fun v ↦ Function.mtr ?_) (le_dualAnnihilator_dualCoannihilator _) simp only [mem_dualAnnihilator, mem_dualCoannihilator] - contrapose! - intro hv - obtain ⟨W', hW⟩ := Submodule.exists_isCompl W - obtain ⟨⟨w, w'⟩, rfl, -⟩ := existsUnique_add_of_isCompl_prod hW v - have hw'n : (w' : V) ∉ W := by - contrapose! hv - exact Submodule.add_mem W w.2 hv - have hw'nz : w' ≠ 0 := by - rintro rfl - exact hw'n (Submodule.zero_mem W) - rw [Ne.def, ← Module.forall_dual_apply_eq_zero_iff K w'] at hw'nz - push_neg at hw'nz - obtain ⟨φ, hφ⟩ := hw'nz - exists ((LinearMap.ofIsComplProd hW).comp (LinearMap.inr _ _ _)) φ - simp only [coe_comp, coe_inr, Function.comp_apply, ofIsComplProd_apply, map_add, - ofIsCompl_left_apply, zero_apply, ofIsCompl_right_apply, zero_add, Ne.def] - refine' ⟨_, hφ⟩ - intro v hv - apply LinearMap.ofIsCompl_left_apply hW ⟨v, hv⟩ + rw [← Quotient.mk_eq_zero W, ← Module.forall_dual_apply_eq_zero_iff K] + push_neg + refine fun ⟨φ, hφ⟩ ↦ ⟨φ.comp W.mkQ, fun w hw ↦ ?_, hφ⟩ + rw [comp_apply, mkQ_apply, (Quotient.mk_eq_zero W).mpr hw, φ.map_zero] #align subspace.dual_annihilator_dual_coannihilator_eq Subspace.dualAnnihilator_dualCoannihilator_eq -- exact elaborates slowly @@ -1081,31 +1059,27 @@ theorem dualAnnihilator_le_dualAnnihilator_iff {W W' : Subspace K V} : #align subspace.dual_annihilator_le_dual_annihilator_iff Subspace.dualAnnihilator_le_dualAnnihilator_iff theorem dualAnnihilator_inj {W W' : Subspace K V} : - W.dualAnnihilator = W'.dualAnnihilator ↔ W = W' := by - constructor - · apply (dualAnnihilatorGci K V).l_injective - · rintro rfl - rfl + W.dualAnnihilator = W'.dualAnnihilator ↔ W = W' := + ⟨fun h ↦ (dualAnnihilatorGci K V).l_injective h, congr_arg _⟩ #align subspace.dual_annihilator_inj Subspace.dualAnnihilator_inj /-- Given a subspace `W` of `V` and an element of its dual `φ`, `dualLift W φ` is an arbitrary extension of `φ` to an element of the dual of `V`. That is, `dualLift W φ` sends `w ∈ W` to `φ x` and `x` in a chosen complement of `W` to `0`. -/ noncomputable def dualLift (W : Subspace K V) : Module.Dual K W →ₗ[K] Module.Dual K V := - let h := Classical.indefiniteDescription _ W.exists_isCompl - (LinearMap.ofIsComplProd h.2).comp (LinearMap.inl _ _ _) + (Classical.choose <| W.subtype.exists_leftInverse_of_injective W.ker_subtype).dualMap #align subspace.dual_lift Subspace.dualLift variable {W : Subspace K V} @[simp] -theorem dualLift_of_subtype {φ : Module.Dual K W} (w : W) : W.dualLift φ (w : V) = φ w := by - erw [ofIsCompl_left_apply _ w] - rfl +theorem dualLift_of_subtype {φ : Module.Dual K W} (w : W) : W.dualLift φ (w : V) = φ w := + congr_arg φ <| FunLike.congr_fun + (Classical.choose_spec <| W.subtype.exists_leftInverse_of_injective W.ker_subtype) w #align subspace.dual_lift_of_subtype Subspace.dualLift_of_subtype theorem dualLift_of_mem {φ : Module.Dual K W} {w : V} (hw : w ∈ W) : W.dualLift φ w = φ ⟨w, hw⟩ := - by convert dualLift_of_subtype ⟨w, hw⟩ + dualLift_of_subtype ⟨w, hw⟩ #align subspace.dual_lift_of_mem Subspace.dualLift_of_mem @[simp] @@ -1173,12 +1147,21 @@ open FiniteDimensional variable {V₁ : Type*} [AddCommGroup V₁] [Module K V₁] -instance instModuleDualFiniteDimensional [H : FiniteDimensional K V] : +instance instModuleDualFiniteDimensional [FiniteDimensional K V] : FiniteDimensional K (Module.Dual K V) := by infer_instance #align subspace.module.dual.finite_dimensional Subspace.instModuleDualFiniteDimensional -variable [FiniteDimensional K V] [FiniteDimensional K V₁] +@[simp] +theorem dual_finrank_eq : finrank K (Module.Dual K V) = finrank K V := by + by_cases h : Module.Finite K V + · classical exact LinearEquiv.finrank_eq (Basis.ofVectorSpace K V).toDualEquiv.symm + rw [finrank_eq_zero_of_basis_imp_false, finrank_eq_zero_of_basis_imp_false] + · exact fun _ b ↦ h (Module.Finite.of_basis b) + · exact fun _ b ↦ h ((Module.finite_dual_iff K).mp <| Module.Finite.of_basis b) +#align subspace.dual_finrank_eq Subspace.dual_finrank_eq + +variable [FiniteDimensional K V] theorem dualAnnihilator_dualAnnihilator_eq (W : Subspace K V) : W.dualAnnihilator.dualAnnihilator = Module.mapEvalEquiv K V W := by @@ -1187,13 +1170,6 @@ theorem dualAnnihilator_dualAnnihilator_eq (W : Subspace K V) : rwa [← OrderIso.symm_apply_eq] #align subspace.dual_annihilator_dual_annihilator_eq Subspace.dualAnnihilator_dualAnnihilator_eq --- TODO(kmill): https://github.com/leanprover-community/mathlib/pull/17521#discussion_r1083241963 -@[simp] -theorem dual_finrank_eq : finrank K (Module.Dual K V) = finrank K V := by - classical - exact LinearEquiv.finrank_eq (Basis.ofVectorSpace K V).toDualEquiv.symm -#align subspace.dual_finrank_eq Subspace.dual_finrank_eq - /-- The quotient by the dual is isomorphic to its dual annihilator. -/ -- Porting note: broken dot notation lean4#1910 LinearMap.range noncomputable def quotDualEquivAnnihilator (W : Subspace K V) : @@ -1250,15 +1226,10 @@ variable (f : M₁ →ₗ[R] M₂) -- Porting note: broken dot notation lean4#1910 LinearMap.ker theorem ker_dualMap_eq_dualAnnihilator_range : LinearMap.ker f.dualMap = f.range.dualAnnihilator := by - ext φ; constructor <;> intro hφ - · rw [mem_ker] at hφ - rw [Submodule.mem_dualAnnihilator] - rintro y ⟨x, rfl⟩ - rw [← dualMap_apply, hφ, zero_apply] - · ext x - rw [dualMap_apply] - rw [Submodule.mem_dualAnnihilator] at hφ - exact hφ (f x) ⟨x, rfl⟩ + ext + simp_rw [mem_ker, ext_iff, Submodule.mem_dualAnnihilator, + ← SetLike.mem_coe, range_coe, Set.forall_range_iff] + rfl #align linear_map.ker_dual_map_eq_dual_annihilator_range LinearMap.ker_dualMap_eq_dualAnnihilator_range -- Porting note: broken dot notation lean4#1910 LinearMap.range @@ -1332,7 +1303,7 @@ theorem range_dualMap_mkQ_eq (W : Submodule R M) : constructor · rintro ⟨ψ, rfl⟩ have := LinearMap.mem_range_self W.mkQ.dualMap ψ - simpa only [ker_mkQ] using LinearMap.range_dualMap_le_dualAnnihilator_ker W.mkQ this + simpa only [ker_mkQ] using W.mkQ.range_dualMap_le_dualAnnihilator_ker this · intro hφ exists W.dualCopairing ⟨φ, hφ⟩ #align submodule.range_dual_map_mkq_eq Submodule.range_dualMap_mkQ_eq @@ -1348,13 +1319,7 @@ def dualQuotEquivDualAnnihilator (W : Submodule R M) : (W.mkQ.dualMap.codRestrict W.dualAnnihilator fun φ => -- Porting note: broken dot notation lean4#1910 LinearMap.mem_range_self W.range_dualMap_mkQ_eq ▸ LinearMap.mem_range_self W.mkQ.dualMap φ) - W.dualCopairing - (by - ext - rfl) - (by - ext - rfl) + W.dualCopairing (by ext; rfl) (by ext; rfl) #align submodule.dual_quot_equiv_dual_annihilator Submodule.dualQuotEquivDualAnnihilator @[simp] @@ -1382,18 +1347,8 @@ open Submodule -- Porting note: broken dot notation lean4#1910 LinearMap.range theorem range_dualMap_eq_dualAnnihilator_ker_of_surjective (f : M →ₗ[R] M') - (hf : Function.Surjective f) : LinearMap.range f.dualMap = f.ker.dualAnnihilator := by - rw [← f.ker.range_dualMap_mkQ_eq] - let f' := LinearMap.quotKerEquivOfSurjective f hf - trans LinearMap.range (f.dualMap.comp f'.symm.dualMap.toLinearMap) - · rw [LinearMap.range_comp_of_range_eq_top] - apply LinearEquiv.range - · apply congr_arg - ext φ x - simp only [LinearMap.coe_comp, LinearEquiv.coe_toLinearMap, LinearMap.dualMap_apply, - LinearEquiv.dualMap_apply, mkQ_apply, LinearMap.quotKerEquivOfSurjective, - LinearEquiv.trans_symm, LinearEquiv.trans_apply, LinearEquiv.ofTop_symm_apply, - LinearMap.quotKerEquivRange_symm_apply_image, mkQ_apply, Function.comp] + (hf : Function.Surjective f) : LinearMap.range f.dualMap = f.ker.dualAnnihilator := + ((f.quotKerEquivOfSurjective hf).dualMap.range_comp _).trans f.ker.range_dualMap_mkQ_eq #align linear_map.range_dual_map_eq_dual_annihilator_ker_of_surjective LinearMap.range_dualMap_eq_dualAnnihilator_ker_of_surjective -- Note, this can be specialized to the case where `R` is an injective `R`-module, or when @@ -1402,16 +1357,15 @@ theorem range_dualMap_eq_dualAnnihilator_ker_of_subtype_range_surjective (f : M (hf : Function.Surjective f.range.subtype.dualMap) : LinearMap.range f.dualMap = f.ker.dualAnnihilator := by have rr_surj : Function.Surjective f.rangeRestrict := by - rw [← LinearMap.range_eq_top, LinearMap.range_rangeRestrict] + rw [← range_eq_top, range_rangeRestrict] have := range_dualMap_eq_dualAnnihilator_ker_of_surjective f.rangeRestrict rr_surj convert this using 1 -- Porting note: broken dot notation lean4#1910 - · change LinearMap.range - ((Submodule.subtype <| LinearMap.range f).comp f.rangeRestrict).dualMap = _ - rw [← LinearMap.dualMap_comp_dualMap, LinearMap.range_comp_of_range_eq_top] - rwa [LinearMap.range_eq_top] + · change range ((range f).subtype.comp f.rangeRestrict).dualMap = _ + rw [← dualMap_comp_dualMap, range_comp_of_range_eq_top] + rwa [range_eq_top] · apply congr_arg - exact (LinearMap.ker_rangeRestrict f).symm + exact (ker_rangeRestrict f).symm #align linear_map.range_dual_map_eq_dual_annihilator_ker_of_subtype_range_surjective LinearMap.range_dualMap_eq_dualAnnihilator_ker_of_subtype_range_surjective end LinearMap @@ -1433,15 +1387,9 @@ theorem dualPairing_nondegenerate : (dualPairing K V₁).Nondegenerate := #align linear_map.dual_pairing_nondegenerate LinearMap.dualPairing_nondegenerate theorem dualMap_surjective_of_injective {f : V₁ →ₗ[K] V₂} (hf : Function.Injective f) : - Function.Surjective f.dualMap := by - intro φ - let f' := LinearEquiv.ofInjective f hf - use Subspace.dualLift (range f) (f'.symm.dualMap φ) - ext x - rw [LinearMap.dualMap_apply, Subspace.dualLift_of_mem (mem_range_self f x), - LinearEquiv.dualMap_apply] - congr 1 - exact LinearEquiv.symm_apply_apply f' x + Function.Surjective f.dualMap := fun φ ↦ + have ⟨f', hf'⟩ := f.exists_leftInverse_of_injective (ker_eq_bot.mpr hf) + ⟨φ.comp f', ext fun x ↦ congr(φ <| $hf' x)⟩ #align linear_map.dual_map_surjective_of_injective LinearMap.dualMap_surjective_of_injective -- Porting note: broken dot notation lean4#1910 LinearMap.range @@ -1455,8 +1403,8 @@ theorem range_dualMap_eq_dualAnnihilator_ker (f : V₁ →ₗ[K] V₂) : @[simp] theorem dualMap_surjective_iff {f : V₁ →ₗ[K] V₂} : Function.Surjective f.dualMap ↔ Function.Injective f := by - rw [← LinearMap.range_eq_top, range_dualMap_eq_dualAnnihilator_ker, ← - Submodule.dualAnnihilator_bot, Subspace.dualAnnihilator_inj, LinearMap.ker_eq_bot] + rw [← LinearMap.range_eq_top, range_dualMap_eq_dualAnnihilator_ker, + ← Submodule.dualAnnihilator_bot, Subspace.dualAnnihilator_inj, LinearMap.ker_eq_bot] #align linear_map.dual_map_surjective_iff LinearMap.dualMap_surjective_iff end LinearMap @@ -1523,7 +1471,7 @@ theorem dualAnnihilator_inf_eq (W W' : Subspace K V₁) : theorem dualAnnihilator_iInf_eq {ι : Type*} [Finite ι] (W : ι → Subspace K V₁) : (⨅ i : ι, W i).dualAnnihilator = ⨆ i : ι, (W i).dualAnnihilator := by revert ι - refine' @Finite.induction_empty_option _ _ _ _ + apply Finite.induction_empty_option · intro α β h hyp W rw [← h.iInf_comp, hyp _, ← h.iSup_comp] · intro W @@ -1555,41 +1503,27 @@ section FiniteDimensional open FiniteDimensional LinearMap -variable [FiniteDimensional K V₂] - namespace LinearMap --- TODO(kmill) remove finite_dimensional if possible --- see https://github.com/leanprover-community/mathlib/pull/17521#discussion_r1083242551 @[simp] theorem finrank_range_dualMap_eq_finrank_range (f : V₁ →ₗ[K] V₂) : -- Porting note: broken dot notation lean4#1910 finrank K (LinearMap.range f.dualMap) = finrank K (LinearMap.range f) := by - have that := Submodule.finrank_quotient_add_finrank (LinearMap.range f) - -- Porting note: Again LinearEquiv.finrank_eq needs help - let equiv := (Subspace.quotEquivAnnihilator <| LinearMap.range f) - have eq := LinearEquiv.finrank_eq (R := K) (M := (V₂ ⧸ range f)) - (M₂ := { x // x ∈ Submodule.dualAnnihilator (range f) }) equiv - rw [eq, ← ker_dualMap_eq_dualAnnihilator_range] at that - -- Porting note: cannot convert at `this`? - conv_rhs at that => rw [← Subspace.dual_finrank_eq] - refine' add_left_injective (finrank K <| LinearMap.ker f.dualMap) _ - change _ + _ = _ + _ - rw [finrank_range_add_finrank_ker f.dualMap, add_comm, that] + rw [congr_arg dualMap (show f = (range f).subtype.comp f.rangeRestrict by rfl), + ← dualMap_comp_dualMap, range_comp, + range_eq_top.mpr (dualMap_surjective_of_injective (range f).injective_subtype), + Submodule.map_top, finrank_range_of_inj, Subspace.dual_finrank_eq] + exact dualMap_injective_of_surjective (range_eq_top.mp f.range_rangeRestrict) #align linear_map.finrank_range_dual_map_eq_finrank_range LinearMap.finrank_range_dualMap_eq_finrank_range /-- `f.dualMap` is injective if and only if `f` is surjective -/ @[simp] theorem dualMap_injective_iff {f : V₁ →ₗ[K] V₂} : Function.Injective f.dualMap ↔ Function.Surjective f := by - refine' ⟨_, fun h => dualMap_injective_of_surjective h⟩ - rw [← range_eq_top, ← ker_eq_bot] - intro h - apply Submodule.eq_top_of_finrank_eq - rw [← Submodule.finrank_eq_zero] at h - rw [← add_zero (FiniteDimensional.finrank K <| LinearMap.range f), ← h, ← - LinearMap.finrank_range_dualMap_eq_finrank_range, LinearMap.finrank_range_add_finrank_ker, - Subspace.dual_finrank_eq] + refine ⟨Function.mtr fun not_surj inj ↦ ?_, dualMap_injective_of_surjective⟩ + rw [← range_eq_top, ← Ne, ← lt_top_iff_ne_top] at not_surj + obtain ⟨φ, φ0, range_le_ker⟩ := (range f).exists_le_ker_of_lt_top not_surj + exact φ0 (inj <| ext fun x ↦ range_le_ker ⟨x, rfl⟩) #align linear_map.dual_map_injective_iff LinearMap.dualMap_injective_iff /-- `f.dualMap` is bijective if and only if `f` is -/ @@ -1599,6 +1533,28 @@ theorem dualMap_bijective_iff {f : V₁ →ₗ[K] V₂} : simp_rw [Function.Bijective, dualMap_surjective_iff, dualMap_injective_iff, and_comm] #align linear_map.dual_map_bijective_iff LinearMap.dualMap_bijective_iff +variable {B : V₁ →ₗ[K] V₂ →ₗ[K] K} + +open Function + +theorem flip_injective_iff₁ [FiniteDimensional K V₁] : Injective B.flip ↔ Surjective B := by + rw [← dualMap_surjective_iff, ← (evalEquiv K V₁).toEquiv.surjective_comp]; rfl + +theorem flip_injective_iff₂ [FiniteDimensional K V₂] : Injective B.flip ↔ Surjective B := by + rw [← dualMap_injective_iff]; exact (evalEquiv K V₂).toEquiv.injective_comp B.dualMap + +theorem flip_surjective_iff₁ [FiniteDimensional K V₁] : Surjective B.flip ↔ Injective B := + flip_injective_iff₂.symm + +theorem flip_surjective_iff₂ [FiniteDimensional K V₂] : Surjective B.flip ↔ Injective B := + flip_injective_iff₁.symm + +theorem flip_bijective_iff₁ [FiniteDimensional K V₁] : Bijective B.flip ↔ Bijective B := by + simp_rw [Bijective, flip_injective_iff₁, flip_surjective_iff₁, and_comm] + +theorem flip_bijective_iff₂ [FiniteDimensional K V₂] : Bijective B.flip ↔ Bijective B := + flip_bijective_iff₁.symm + end LinearMap end FiniteDimensional From 564283d73b2fd220603e983d5c6057a27239798c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 18 Dec 2023 19:32:57 +0000 Subject: [PATCH 061/353] feat: Comap of a probability measure under an ae surjective embedding (#8954) From PFR --- .../Measure/ProbabilityMeasure.lean | 2 ++ .../MeasureTheory/Measure/Typeclasses.lean | 25 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean b/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean index d2d7e1cc86237..a6450db04283a 100644 --- a/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean @@ -135,6 +135,8 @@ instance (μ : ProbabilityMeasure Ω) : IsProbabilityMeasure (μ : Measure Ω) : -- porting note: syntactic tautology because of the way coercions work in Lean 4 #noalign measure_theory.probability_measure.coe_fn_eq_to_nnreal_coe_fn_to_measure +@[simp, norm_cast] lemma coe_mk (μ : Measure Ω) (hμ) : toMeasure ⟨μ, hμ⟩ = μ := rfl + @[simp] theorem val_eq_to_measure (ν : ProbabilityMeasure Ω) : ν.val = (ν : Measure Ω) := rfl diff --git a/Mathlib/MeasureTheory/Measure/Typeclasses.lean b/Mathlib/MeasureTheory/Measure/Typeclasses.lean index f957f76d25591..bc3dacabea3b3 100644 --- a/Mathlib/MeasureTheory/Measure/Typeclasses.lean +++ b/Mathlib/MeasureTheory/Measure/Typeclasses.lean @@ -21,7 +21,7 @@ We introduce the following typeclasses for measures: -/ open scoped ENNReal NNReal Topology -open Set MeasureTheory Measure Filter MeasurableSpace ENNReal +open Set MeasureTheory Measure Filter Function MeasurableSpace ENNReal variable {α β δ ι : Type*} @@ -218,6 +218,9 @@ export MeasureTheory.IsProbabilityMeasure (measure_univ) attribute [simp] IsProbabilityMeasure.measure_univ +lemma isProbabilityMeasure_iff : IsProbabilityMeasure μ ↔ μ univ = 1 := + ⟨fun _ ↦ measure_univ, IsProbabilityMeasure.mk⟩ + instance (priority := 100) IsProbabilityMeasure.toIsFiniteMeasure (μ : Measure α) [IsProbabilityMeasure μ] : IsFiniteMeasure μ := ⟨by simp only [measure_univ, ENNReal.one_lt_top]⟩ @@ -276,6 +279,26 @@ theorem prob_compl_eq_one_iff [IsProbabilityMeasure μ] (hs : MeasurableSet s) : μ sᶜ = 1 ↔ μ s = 0 := by rw [← prob_compl_eq_zero_iff hs.compl, compl_compl] #align measure_theory.prob_compl_eq_one_iff MeasureTheory.prob_compl_eq_one_iff +variable [IsProbabilityMeasure μ] {p : α → Prop} {f : β → α} + +lemma mem_ae_iff_prob_eq_one (hs : MeasurableSet s) : s ∈ μ.ae ↔ μ s = 1 := + mem_ae_iff.trans $ prob_compl_eq_zero_iff hs + +lemma ae_iff_prob_eq_one (hp : Measurable p) : (∀ᵐ a ∂μ, p a) ↔ μ {a | p a} = 1 := + mem_ae_iff_prob_eq_one hp.setOf + +lemma isProbabilityMeasure_comap (hf : Injective f) (hf' : ∀ᵐ a ∂μ, a ∈ range f) + (hf'' : ∀ s, MeasurableSet s → MeasurableSet (f '' s)) : + IsProbabilityMeasure (μ.comap f) where + measure_univ := by + rw [comap_apply _ hf hf'' _ MeasurableSet.univ, + ← mem_ae_iff_prob_eq_one (hf'' _ MeasurableSet.univ)] + simpa + +protected lemma _root_.MeasurableEmbedding.isProbabilityMeasure_comap (hf : MeasurableEmbedding f) + (hf' : ∀ᵐ a ∂μ, a ∈ range f) : IsProbabilityMeasure (μ.comap f) := + isProbabilityMeasure_comap hf.injective hf' hf.measurableSet_image' + end IsProbabilityMeasure section NoAtoms From 448da11d38dcaf0667a55aa464af1553ecd6718b Mon Sep 17 00:00:00 2001 From: David Loeffler Date: Mon, 18 Dec 2023 20:33:43 +0000 Subject: [PATCH 062/353] feat(LinearAlgebra/Matrix/PosDef): unique positive semidef square root (#8809) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds two main results about positive semidefinite matrices: - a positive semidefinite matrix has a unique positive semidefinite square root; - if `A` is positive semidefinite then `x* A x = 0` implies `A x = 0` (proof extracted from #8594). Co-authored-by: Adrian Wüthrich (@awueth) Co-authored-by: Eric Wieser --- Mathlib/LinearAlgebra/Matrix/Hermitian.lean | 7 +- Mathlib/LinearAlgebra/Matrix/PosDef.lean | 243 +++++++++++++++++--- Mathlib/LinearAlgebra/Matrix/Spectrum.lean | 22 ++ 3 files changed, 243 insertions(+), 29 deletions(-) diff --git a/Mathlib/LinearAlgebra/Matrix/Hermitian.lean b/Mathlib/LinearAlgebra/Matrix/Hermitian.lean index 25b5cb610bd7e..0c81e187da734 100644 --- a/Mathlib/LinearAlgebra/Matrix/Hermitian.lean +++ b/Mathlib/LinearAlgebra/Matrix/Hermitian.lean @@ -131,13 +131,18 @@ section AddMonoid variable [AddMonoid α] [StarAddMonoid α] [AddMonoid β] [StarAddMonoid β] -/-- A diagonal matrix is hermitian if the entries are self-adjoint -/ +/-- A diagonal matrix is hermitian if the entries are self-adjoint (as a vector) -/ theorem isHermitian_diagonal_of_self_adjoint [DecidableEq n] (v : n → α) (h : IsSelfAdjoint v) : (diagonal v).IsHermitian := (-- TODO: add a `pi.has_trivial_star` instance and remove the `funext` diagonal_conjTranspose v).trans <| congr_arg _ h #align matrix.is_hermitian_diagonal_of_self_adjoint Matrix.isHermitian_diagonal_of_self_adjoint +/-- A diagonal matrix is hermitian if each diagonal entry is self-adjoint -/ +lemma isHermitian_diagonal_iff [DecidableEq n]{d : n → α} : + IsHermitian (diagonal d) ↔ (∀ i : n, IsSelfAdjoint (d i)) := by + simp [isSelfAdjoint_iff, IsHermitian, conjTranspose, diagonal_transpose, diagonal_map] + /-- A diagonal matrix is hermitian if the entries have the trivial `star` operation (such as on the reals). -/ @[simp] diff --git a/Mathlib/LinearAlgebra/Matrix/PosDef.lean b/Mathlib/LinearAlgebra/Matrix/PosDef.lean index 9f0a7a1b85de7..79e48fbece6b3 100644 --- a/Mathlib/LinearAlgebra/Matrix/PosDef.lean +++ b/Mathlib/LinearAlgebra/Matrix/PosDef.lean @@ -11,20 +11,25 @@ import Mathlib.LinearAlgebra.QuadraticForm.Basic /-! # Positive Definite Matrices This file defines positive (semi)definite matrices and connects the notion to positive definiteness -of quadratic forms. +of quadratic forms. Most results require `𝕜 = ℝ` or `ℂ`. -## Main definition +## Main definitions * `Matrix.PosDef` : a matrix `M : Matrix n n 𝕜` is positive definite if it is hermitian and `xᴴMx` is greater than zero for all nonzero `x`. * `Matrix.PosSemidef` : a matrix `M : Matrix n n 𝕜` is positive semidefinite if it is hermitian and `xᴴMx` is nonnegative for all `x`. +## Main results + +* `Matrix.posSemidef_iff_eq_transpose_mul_self` : a matrix `M : Matrix n n 𝕜` is positive + semidefinite iff it has the form `Bᴴ * B` for some `B`. +* `Matrix.PosSemidef.sqrt` : the unique positive semidefinite square root of a positive semidefinite + matrix. (See `Matrix.PosSemidef.eq_sqrt_of_sq_eq` for the proof of uniqueness.) -/ open scoped ComplexOrder - namespace Matrix variable {m n R 𝕜 : Type*} @@ -37,32 +42,186 @@ open scoped Matrix ## Positive semidefinite matrices -/ -/-- A matrix `M : Matrix n n R` is positive semidefinite if it is hermitian - and `xᴴMx` is nonnegative for all `x`. -/ +/-- A matrix `M : Matrix n n R` is positive semidefinite if it is Hermitian and `xᴴ * M * x` is +nonnegative for all `x`. -/ def PosSemidef (M : Matrix n n R) := M.IsHermitian ∧ ∀ x : n → R, 0 ≤ dotProduct (star x) (M.mulVec x) #align matrix.pos_semidef Matrix.PosSemidef -theorem PosSemidef.re_dotProduct_nonneg {M : Matrix n n 𝕜} (hM : M.PosSemidef) (x : n → 𝕜) : +/-- A diagonal matrix is positive semidefinite iff its diagonal entries are nonnegative. -/ +lemma posSemidef_diagonal_iff [DecidableEq n] {d : n → R} : + PosSemidef (diagonal d) ↔ (∀ i : n, 0 ≤ d i) := by + refine ⟨fun ⟨_, hP⟩ i ↦ by simpa using hP (Pi.single i 1), ?_⟩ + refine fun hd ↦ ⟨isHermitian_diagonal_iff.2 <| fun i ↦ IsSelfAdjoint.of_nonneg (hd i), ?_⟩ + refine fun x ↦ Finset.sum_nonneg fun i _ ↦ ?_ + simpa only [mulVec_diagonal, mul_assoc] using conjugate_nonneg (hd i) _ + +namespace PosSemidef + +theorem isHermitian {M : Matrix n n R} (hM : M.PosSemidef) : M.IsHermitian := + hM.1 + +theorem re_dotProduct_nonneg {M : Matrix n n 𝕜} (hM : M.PosSemidef) (x : n → 𝕜) : 0 ≤ IsROrC.re (dotProduct (star x) (M.mulVec x)) := IsROrC.nonneg_iff.mp (hM.2 _) |>.1 -theorem PosSemidef.submatrix {M : Matrix n n R} (hM : M.PosSemidef) (e : m ≃ n) : +lemma conjTranspose_mul_mul_same {A : Matrix n n R} (hA : PosSemidef A) + {m : Type*} [Fintype m] (B : Matrix n m R) : + PosSemidef (Bᴴ * A * B) := by + constructor + · exact isHermitian_conjTranspose_mul_mul B hA.1 + · intro x + simpa only [star_mulVec, dotProduct_mulVec, vecMul_vecMul] using hA.2 (mulVec B x) + +lemma mul_mul_conjTranspose_same {A : Matrix n n R} (hA : PosSemidef A) + {m : Type*} [Fintype m] (B : Matrix m n R): + PosSemidef (B * A * Bᴴ) := by + simpa only [conjTranspose_conjTranspose] using hA.conjTranspose_mul_mul_same Bᴴ + +theorem submatrix {M : Matrix n n R} (hM : M.PosSemidef) (e : m → n) : (M.submatrix e e).PosSemidef := by - refine' ⟨hM.1.submatrix e, fun x => _⟩ - have : (M.submatrix (⇑e) e).mulVec x = (M.mulVec fun i : n => x (e.symm i)) ∘ e := by - ext i - dsimp only [(· ∘ ·), mulVec, dotProduct] - rw [Finset.sum_bij' (fun i _ => e i) _ _ fun i _ => e.symm i] <;> - simp only [eq_self_iff_true, imp_true_iff, Equiv.symm_apply_apply, Finset.mem_univ, - submatrix_apply, Equiv.apply_symm_apply] - rw [this] - convert hM.2 fun i => x (e.symm i) using 3 - unfold dotProduct - rw [Finset.sum_bij' (fun i _ => e i) _ _ fun i _ => e.symm i] <;> - simp + classical + rw [(by simp : M = 1 * M * 1), submatrix_mul (he₂ := Function.bijective_id), + submatrix_mul (he₂ := Function.bijective_id), submatrix_id_id] + simpa only [conjTranspose_submatrix, conjTranspose_one] using + conjTranspose_mul_mul_same hM (Matrix.submatrix 1 id e) #align matrix.pos_semidef.submatrix Matrix.PosSemidef.submatrix +protected lemma zero : PosSemidef (0 : Matrix n n R) := + ⟨isHermitian_zero, by simp⟩ + +protected lemma one [DecidableEq n] : PosSemidef (1 : Matrix n n R) := + ⟨isHermitian_one, fun x => by + rw [one_mulVec]; exact Fintype.sum_nonneg fun i => star_mul_self_nonneg _⟩ + +protected lemma pow [DecidableEq n] {M : Matrix n n R} (hM : M.PosSemidef) (k : ℕ) : + PosSemidef (M ^ k) := + match k with + | 0 => .one + | 1 => by simpa using hM + | (k + 2) => by + rw [pow_succ', pow_succ] + simpa only [hM.isHermitian.eq] using (hM.pow k).mul_mul_conjTranspose_same M + +/-- The eigenvalues of a positive semi-definite matrix are non-negative -/ +lemma eigenvalues_nonneg [DecidableEq n] {A : Matrix n n 𝕜} + (hA : Matrix.PosSemidef A) (i : n) : 0 ≤ hA.1.eigenvalues i := + (hA.re_dotProduct_nonneg _).trans_eq (hA.1.eigenvalues_eq _).symm + +theorem transpose {M : Matrix n n R} (hM : M.PosSemidef) : Mᵀ.PosSemidef := by + refine ⟨IsHermitian.transpose hM.1, fun x => ?_⟩ + convert hM.2 (star x) using 1 + rw [mulVec_transpose, Matrix.dotProduct_mulVec, star_star, dotProduct_comm] + +section sqrt + +variable [DecidableEq n] {A : Matrix n n 𝕜} (hA : PosSemidef A) + +/-- The positive semidefinite square root of a positive semidefinite matrix -/ +@[pp_dot] +noncomputable def sqrt : Matrix n n 𝕜 := + hA.1.eigenvectorMatrix * diagonal ((↑) ∘ Real.sqrt ∘ hA.1.eigenvalues) * hA.1.eigenvectorMatrixᴴ + +open Lean PrettyPrinter.Delaborator SubExpr in +/-- Custom elaborator to produce output like `(_ : PosSemidef A).sqrt` in the goal view. -/ +@[delab app.Matrix.PosSemidef.sqrt] +def delabSqrt : Delab := + whenPPOption getPPNotation <| + whenNotPPOption getPPAnalysisSkip <| + withOptionAtCurrPos `pp.analysis.skip true do + let e ← getExpr + guard <| e.isAppOfArity ``Matrix.PosSemidef.sqrt 7 + let optionsPerPos ← withNaryArg 6 do + return (← read).optionsPerPos.setBool (← getPos) `pp.proofs.withType true + withTheReader Context ({· with optionsPerPos}) delab + +-- test for custom elaborator +/-- +info: (_ : PosSemidef A).sqrt : Matrix n n 𝕜 +-/ +#guard_msgs in +#check (id hA).sqrt + +lemma posSemidef_sqrt : PosSemidef hA.sqrt := by + apply PosSemidef.mul_mul_conjTranspose_same + refine posSemidef_diagonal_iff.mpr fun i ↦ ?_ + rw [Function.comp_apply, IsROrC.nonneg_iff] + constructor + · simp only [IsROrC.ofReal_re] + exact Real.sqrt_nonneg _ + · simp only [IsROrC.ofReal_im] + +@[simp] +lemma sq_sqrt : hA.sqrt ^ 2 = A := by + let C := hA.1.eigenvectorMatrix + let E := diagonal ((↑) ∘ Real.sqrt ∘ hA.1.eigenvalues : n → 𝕜) + suffices : C * (E * (Cᴴ * C) * E) * Cᴴ = A + · rw [Matrix.PosSemidef.sqrt, pow_two] + change (C * E * Cᴴ) * (C * E * Cᴴ) = A + simpa only [← mul_assoc] using this + have : Cᴴ * C = 1 + · rw [Matrix.IsHermitian.conjTranspose_eigenvectorMatrix, mul_eq_one_comm] + exact hA.1.eigenvectorMatrix_mul_inv + rw [this, mul_one] + have : E * E = diagonal ((↑) ∘ hA.1.eigenvalues) + · rw [diagonal_mul_diagonal] + refine congr_arg _ (funext fun v ↦ ?_) -- why doesn't "congr with v" work? + simp [← pow_two, ← IsROrC.ofReal_pow, Real.sq_sqrt (hA.eigenvalues_nonneg v)] + rw [this] + convert hA.1.spectral_theorem'.symm + apply Matrix.IsHermitian.conjTranspose_eigenvectorMatrix + +@[simp] +lemma sqrt_mul_self : hA.sqrt * hA.sqrt = A := by rw [← pow_two, sq_sqrt] + +lemma eq_of_sq_eq_sq {B : Matrix n n 𝕜} (hB : PosSemidef B) (hAB : A ^ 2 = B ^ 2) : A = B := by + /- This is deceptively hard, much more difficult than the positive *definite* case. We follow a + clever proof due to Koeber and Schäfer. The idea is that if `A ≠ B`, then `A - B` has a nonzero + real eigenvalue, with eigenvector `v`. Then a manipulation using the identity + `A ^ 2 - B ^ 2 = A * (A - B) + (A - B) * B` leads to the conclusion that + `⟨v, A v⟩ + ⟨v, B v⟩ = 0`. Since `A, B` are positive semidefinite, both terms must be zero. Thus + `⟨v, (A - B) v⟩ = 0`, but this is a nonzero scalar multiple of `⟨v, v⟩`, contradiction. -/ + by_contra h_ne + let ⟨v, t, ht, hv, hv'⟩ := (hA.1.sub hB.1).exists_eigenvector_of_ne_zero (sub_ne_zero.mpr h_ne) + have h_sum : 0 = t * (star v ⬝ᵥ mulVec A v + star v ⬝ᵥ mulVec B v) + · calc + 0 = star v ⬝ᵥ mulVec (A ^ 2 - B ^ 2) v := by rw [hAB, sub_self, zero_mulVec, dotProduct_zero] + _ = star v ⬝ᵥ mulVec A (mulVec (A - B) v) + star v ⬝ᵥ mulVec (A - B) (mulVec B v) := by + rw [mulVec_mulVec, mulVec_mulVec, ← dotProduct_add, ← add_mulVec, mul_sub, sub_mul, + add_sub, sub_add_cancel, pow_two, pow_two] + _ = t * (star v ⬝ᵥ mulVec A v) + vecMul (star v) (A - B)ᴴ ⬝ᵥ mulVec B v := by + rw [hv', mulVec_smul, dotProduct_smul, IsROrC.real_smul_eq_coe_mul, + dotProduct_mulVec _ (A - B), hA.1.sub hB.1] + _ = t * (star v ⬝ᵥ mulVec A v + star v ⬝ᵥ mulVec B v) := by + simp_rw [← star_mulVec, hv', mul_add, ← IsROrC.real_smul_eq_coe_mul, ← smul_dotProduct] + congr 2 with i + simp only [Pi.star_apply, Pi.smul_apply, IsROrC.real_smul_eq_coe_mul, star_mul', + IsROrC.star_def, IsROrC.conj_ofReal] + replace h_sum : star v ⬝ᵥ mulVec A v + star v ⬝ᵥ mulVec B v = 0 + · rw [eq_comm, ← mul_zero (t : 𝕜)] at h_sum + exact mul_left_cancel₀ (IsROrC.ofReal_ne_zero.mpr ht) h_sum + have h_van : star v ⬝ᵥ mulVec A v = 0 ∧ star v ⬝ᵥ mulVec B v = 0 + · refine ⟨le_antisymm ?_ (hA.2 v), le_antisymm ?_ (hB.2 v)⟩ + · rw [add_comm, add_eq_zero_iff_eq_neg] at h_sum + simpa only [h_sum, neg_nonneg] using hB.2 v + · simpa only [add_eq_zero_iff_eq_neg.mp h_sum, neg_nonneg] using hA.2 v + have aux : star v ⬝ᵥ mulVec (A - B) v = 0 + · rw [sub_mulVec, dotProduct_sub, h_van.1, h_van.2, sub_zero] + rw [hv', dotProduct_smul, IsROrC.real_smul_eq_coe_mul, ← mul_zero ↑t] at aux + exact hv <| Matrix.dotProduct_star_self_eq_zero.mp <| mul_left_cancel₀ + (IsROrC.ofReal_ne_zero.mpr ht) aux + +lemma sqrt_sq : (hA.pow 2 : PosSemidef (A ^ 2)).sqrt = A := + (hA.pow 2).posSemidef_sqrt.eq_of_sq_eq_sq hA (hA.pow 2).sq_sqrt + +lemma eq_sqrt_of_sq_eq {B : Matrix n n 𝕜} (hB : PosSemidef B) (hAB : A ^ 2 = B) : A = hB.sqrt := by + subst B + rw [hA.sqrt_sq] + +end sqrt + +end PosSemidef + @[simp] theorem posSemidef_submatrix_equiv {M : Matrix n n R} (e : m ≃ n) : (M.submatrix e e).PosSemidef ↔ M.PosSemidef := @@ -70,27 +229,55 @@ theorem posSemidef_submatrix_equiv {M : Matrix n n R} (e : m ≃ n) : #align matrix.pos_semidef_submatrix_equiv Matrix.posSemidef_submatrix_equiv /-- The conjugate transpose of a matrix mulitplied by the matrix is positive semidefinite -/ -theorem posSemidef_conjTranspose_mul_self (A : Matrix m n R) : Matrix.PosSemidef (Aᴴ * A) := by +theorem posSemidef_conjTranspose_mul_self (A : Matrix m n R) : PosSemidef (Aᴴ * A) := by refine ⟨isHermitian_transpose_mul_self _, fun x => ?_⟩ rw [← mulVec_mulVec, dotProduct_mulVec, vecMul_conjTranspose, star_star] exact Finset.sum_nonneg fun i _ => star_mul_self_nonneg _ /-- A matrix multiplied by its conjugate transpose is positive semidefinite -/ -theorem posSemidef_self_mul_conjTranspose (A : Matrix m n R) : Matrix.PosSemidef (A * Aᴴ) := +theorem posSemidef_self_mul_conjTranspose (A : Matrix m n R) : PosSemidef (A * Aᴴ) := by simpa only [conjTranspose_conjTranspose] using posSemidef_conjTranspose_mul_self Aᴴ -/-- The eigenvalues of a positive semi-definite matrix are non-negative -/ -lemma PosSemidef.eigenvalues_nonneg [DecidableEq n] {A : Matrix n n 𝕜} - (hA : Matrix.PosSemidef A) (i : n) : 0 ≤ hA.1.eigenvalues i := - (hA.re_dotProduct_nonneg _).trans_eq (hA.1.eigenvalues_eq _).symm - lemma eigenvalues_conjTranspose_mul_self_nonneg (A : Matrix m n 𝕜) [DecidableEq n] (i : n) : 0 ≤ (isHermitian_transpose_mul_self A).eigenvalues i := - (Matrix.posSemidef_conjTranspose_mul_self _).eigenvalues_nonneg _ + (posSemidef_conjTranspose_mul_self _).eigenvalues_nonneg _ lemma eigenvalues_self_mul_conjTranspose_nonneg (A : Matrix m n 𝕜) [DecidableEq m] (i : m) : 0 ≤ (isHermitian_mul_conjTranspose_self A).eigenvalues i := - (Matrix.posSemidef_self_mul_conjTranspose _).eigenvalues_nonneg _ + (posSemidef_self_mul_conjTranspose _).eigenvalues_nonneg _ + +/-- A matrix is positive semidefinite if and only if it has the form `Bᴴ * B` for some `B`. -/ +lemma posSemidef_iff_eq_transpose_mul_self [DecidableEq n] {A : Matrix n n 𝕜} : + PosSemidef A ↔ ∃ (B : Matrix n n 𝕜), A = Bᴴ * B := by + refine ⟨fun hA ↦ ⟨hA.sqrt, ?_⟩, fun ⟨B, hB⟩ ↦ (hB ▸ posSemidef_conjTranspose_mul_self B)⟩ + simp_rw [← PosSemidef.sq_sqrt hA, pow_two] + rw [hA.posSemidef_sqrt.1] + +lemma IsHermitian.posSemidef_of_eigenvalues_nonneg [DecidableEq n] {A : Matrix n n 𝕜} + (hA : IsHermitian A) (h : ∀ i : n, 0 ≤ hA.eigenvalues i) : PosSemidef A := by + simp_rw [hA.conjTranspose_eigenvectorMatrix.symm ▸ hA.spectral_theorem'] + refine (posSemidef_diagonal_iff.mpr fun i ↦ ?_).mul_mul_conjTranspose_same _ + rw [IsROrC.le_iff_re_im] + simpa using h i + +/-- For `A` positive semidefinite, we have `x⋆ A x = 0` iff `A x = 0`. -/ +theorem PosSemidef.dotProduct_mulVec_zero_iff [DecidableEq n] + {A : Matrix n n 𝕜} (hA : PosSemidef A) (x : n → 𝕜) : + star x ⬝ᵥ mulVec A x = 0 ↔ mulVec A x = 0 := by + constructor + · obtain ⟨B, rfl⟩ := posSemidef_iff_eq_transpose_mul_self.mp hA + rw [← Matrix.mulVec_mulVec, dotProduct_mulVec, + vecMul_conjTranspose, star_star, dotProduct_star_self_eq_zero] + intro h0 + rw [h0, mulVec_zero] + · intro h0 + rw [h0, dotProduct_zero] + +/-- For `A` positive semidefinite, we have `x⋆ A x = 0` iff `A x = 0` (linear maps version). -/ +theorem PosSemidef.toLinearMap₂'_zero_iff [DecidableEq n] + {A : Matrix n n 𝕜} (hA : PosSemidef A) (x : n → 𝕜) : + Matrix.toLinearMap₂' A (star x) x = 0 ↔ Matrix.toLin' A x = 0 := by + simpa only [toLinearMap₂'_apply', toLin'_apply] using hA.dotProduct_mulVec_zero_iff x /-! ## Positive definite matrices diff --git a/Mathlib/LinearAlgebra/Matrix/Spectrum.lean b/Mathlib/LinearAlgebra/Matrix/Spectrum.lean index 08bde350392b3..8f03821568c01 100644 --- a/Mathlib/LinearAlgebra/Matrix/Spectrum.lean +++ b/Mathlib/LinearAlgebra/Matrix/Spectrum.lean @@ -161,6 +161,28 @@ lemma rank_eq_rank_diagonal : A.rank = (Matrix.diagonal hA.eigenvalues).rank := lemma rank_eq_card_non_zero_eigs : A.rank = Fintype.card {i // hA.eigenvalues i ≠ 0} := by rw [rank_eq_rank_diagonal hA, Matrix.rank_diagonal] +/-- The entries of `eigenvectorBasis` are eigenvectors. -/ +lemma mulVec_eigenvectorBasis (i : n) : + mulVec A (hA.eigenvectorBasis i) = hA.eigenvalues i • hA.eigenvectorBasis i := by + have := congr_arg (· * hA.eigenvectorMatrix) hA.spectral_theorem' + simp only [mul_assoc, mul_eq_one_comm.mp hA.eigenvectorMatrix_mul_inv, mul_one] at this + ext1 j + have := congr_fun (congr_fun this j) i + simp only [mul_diagonal, Function.comp_apply] at this + convert this using 1 + rw [mul_comm, Pi.smul_apply, IsROrC.real_smul_eq_coe_mul, hA.eigenvectorMatrix_apply] + +/-- A nonzero Hermitian matrix has an eigenvector with nonzero eigenvalue. -/ +lemma exists_eigenvector_of_ne_zero (h_ne : A ≠ 0) : + ∃ (v : n → 𝕜) (t : ℝ), t ≠ 0 ∧ v ≠ 0 ∧ mulVec A v = t • v := by + have : hA.eigenvalues ≠ 0 + · contrapose! h_ne + have := hA.spectral_theorem' + rwa [h_ne, Pi.comp_zero, IsROrC.ofReal_zero, (by rfl : Function.const n (0 : 𝕜) = fun _ ↦ 0), + diagonal_zero, mul_zero, zero_mul] at this + obtain ⟨i, hi⟩ := Function.ne_iff.mp this + exact ⟨_, _, hi, hA.eigenvectorBasis.orthonormal.ne_zero i, hA.mulVec_eigenvectorBasis i⟩ + end IsHermitian end Matrix From 8d91b8e7b8e0d6af7baee3d318e6a158969423f4 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Tue, 19 Dec 2023 00:17:00 +0000 Subject: [PATCH 063/353] feat: `Finset/Multiset.powersetCard 1` (#9137) for [#9130](https://github.com/leanprover-community/mathlib4/pull/9130/files#r1429368677) Co-authored-by: Junyan Xu --- Mathlib/Data/Finset/Powerset.lean | 18 +++++++++++------- Mathlib/Data/List/Sublists.lean | 4 ++++ Mathlib/Data/Multiset/Powerset.lean | 4 ++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean index 37696b7f88740..f7bf0c5bd810b 100644 --- a/Mathlib/Data/Finset/Powerset.lean +++ b/Mathlib/Data/Finset/Powerset.lean @@ -218,7 +218,7 @@ theorem card_powersetCard (n : ℕ) (s : Finset α) : #align finset.card_powerset_len Finset.card_powersetCard @[simp] -theorem powersetCard_zero (s : Finset α) : Finset.powersetCard 0 s = {∅} := by +theorem powersetCard_zero (s : Finset α) : s.powersetCard 0 = {∅} := by ext; rw [mem_powersetCard, mem_singleton, card_eq_zero] refine' ⟨fun h => h.2, fun h => by @@ -226,6 +226,16 @@ theorem powersetCard_zero (s : Finset α) : Finset.powersetCard 0 s = {∅} := b exact ⟨empty_subset s, rfl⟩⟩ #align finset.powerset_len_zero Finset.powersetCard_zero +@[simp] +theorem map_val_val_powersetCard (s : Finset α) (i : ℕ) : + (s.powersetCard i).val.map Finset.val = s.1.powersetCard i := by + simp [Finset.powersetCard, map_pmap, pmap_eq_map, map_id'] +#align finset.map_val_val_powerset_len Finset.map_val_val_powersetCard + +theorem powersetCard_one (s : Finset α) : + s.powersetCard 1 = s.map ⟨_, Finset.singleton_injective⟩ := + eq_of_veq <| Multiset.map_injective val_injective <| by simp [Multiset.powersetCard_one] + @[simp] theorem powersetCard_empty (n : ℕ) {s : Finset α} (h : s.card < n) : powersetCard n s = ∅ := Finset.card_eq_zero.mp (by rw [card_powersetCard, Nat.choose_eq_zero_of_lt h]) @@ -324,12 +334,6 @@ theorem powersetCard_card_add (s : Finset α) {i : ℕ} (hi : 0 < i) : Finset.powersetCard_empty _ (lt_add_of_pos_right (Finset.card s) hi) #align finset.powerset_len_card_add Finset.powersetCard_card_add -@[simp] -theorem map_val_val_powersetCard (s : Finset α) (i : ℕ) : - (s.powersetCard i).val.map Finset.val = s.1.powersetCard i := by - simp [Finset.powersetCard, map_pmap, pmap_eq_map, map_id'] -#align finset.map_val_val_powerset_len Finset.map_val_val_powersetCard - theorem powersetCard_map {β : Type*} (f : α ↪ β) (n : ℕ) (s : Finset α) : powersetCard n (s.map f) = (powersetCard n s).map (mapEmbedding f).toEmbedding := ext <| fun t => by diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index adca68d553f26..4d9ab07fff437 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -274,6 +274,10 @@ theorem sublistsLen_succ_cons {α : Type*} (n) (a : α) (l) : append_nil]; rfl #align list.sublists_len_succ_cons List.sublistsLen_succ_cons +theorem sublistsLen_one {α : Type*} (l : List α) : sublistsLen 1 l = l.reverse.map ([·]) := + l.rec (by rw [sublistsLen_succ_nil, reverse_nil, map_nil]) fun a s ih ↦ by + rw [sublistsLen_succ_cons, ih, reverse_cons, map_append, sublistsLen_zero]; rfl + @[simp] theorem length_sublistsLen {α : Type*} : ∀ (n) (l : List α), length (sublistsLen n l) = Nat.choose (length l) n diff --git a/Mathlib/Data/Multiset/Powerset.lean b/Mathlib/Data/Multiset/Powerset.lean index 5e3d047fc5f9b..821f85d657157 100644 --- a/Mathlib/Data/Multiset/Powerset.lean +++ b/Mathlib/Data/Multiset/Powerset.lean @@ -258,6 +258,10 @@ theorem powersetCard_cons (n : ℕ) (a : α) (s) : Quotient.inductionOn s fun l => by simp [powersetCard_coe'] #align multiset.powerset_len_cons Multiset.powersetCard_cons +theorem powersetCard_one (s : Multiset α) : powersetCard 1 s = s.map singleton := + Quotient.inductionOn s fun l ↦ by + simp [powersetCard_coe, sublistsLen_one, map_reverse, Function.comp] + @[simp] theorem mem_powersetCard {n : ℕ} {s t : Multiset α} : s ∈ powersetCard n t ↔ s ≤ t ∧ card s = n := Quotient.inductionOn t fun l => by simp [powersetCard_coe'] From 21ad2c6e9b30d63ade52c7b3aef40e7cc38b82c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Dec 2023 08:26:03 +0000 Subject: [PATCH 064/353] feat: Mixins for monotonicity of scalar multiplication (#8869) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR introduces eight typeclasses for monotonicity of left/right scalar multiplication by nonnegative elements: * `PosSMulMono`: If `a ≥ 0`, then `b₁ ≤ b₂` implies `a • b₁ ≤ a • b₂`. * `PosSMulStrictMono`: If `a > 0`, then `b₁ < b₂` implies `a • b₁ < a • b₂`. * `PosSMulReflectLT`: If `a ≥ 0`, then `a • b₁ < a • b₂` implies `b₁ < b₂`. * `PosSMulReflectLE`: If `a > 0`, then `a • b₁ ≤ a • b₂` implies `b₁ ≤ b₂`. * `SMulPosMono`: If `b ≥ 0`, then `a₁ ≤ a₂` implies `a₁ • b ≤ a₂ • b`. * `SMulPosStrictMono`: If `b > 0`, then `a₁ < a₂` implies `a₁ • b < a₂ • b`. * `SMulPosReflectLT`: If `b ≥ 0`, then `a₁ • b < a₂ • b` implies `a₁ < a₂`. * `SMulPosReflectLE`: If `b > 0`, then `a₁ • b ≤ a₂ • b` implies `a₁ ≤ a₂`. The design is heavily inspired to the corresponding one for multiplication (see `Algebra.Order.Ring.Lemmas`). Note however the following differences: * The new typeclasses are custom typeclasses instead of abbreviations for the correct `CovariantClass`/`ContravariantClass` invokations. This has the following benefits: * They get displayed as classes in the docs. In particular, one can see their list of instances, instead of their instances being invariably dumped to the `CovariantClass`/`ContravariantClass` list. * They don't pollute other typeclass searches. Having many abbreviations of the same typeclass for different purposes always felt like a performance issue to me (more instances with the same key, for no added benefit), and indeed a previous version of this PR hit timeouts due to the higher number of `CovariantClass`/`ContravariantClass` instances. * `SMulPosReflectLT`/`SMulPosReflectLE` did not fit in the framework since they relate `≤` on two different types. So I would have had to generalise `CovariantClass`/`ContravariantClass` to three types and two relations. * Very minor, but the constructors let you work with `a : α`, `h : 0 ≤ a` instead of `a : {a : α // 0 ≤ a}`. This actually makes some instances surprisingly cleaner to prove. * The `CovariantClass`/`ContravariantClass` framework was only used to automate very simple logic anyway. It was easily copied over. * We replace undocumented lemmas stating the equivalence of the four typeclasses mentioning nonnegativity with their positivity version by motivated constructors. * We abandon series of lemmas of dubious utility. Those were already marked as such in `Algebra.Order.Ring.Lemmas` (by myself). * Some lemmas about commutativity of multiplication don't make sense for scalar multiplication. This PR links the new typeclasses to `OrderedSMul` and makes all old lemmas in `Algebra.Order.SMul` one-liners in terms of the new lemmas (except when they have the same name, in which case the lemma is simply moved) but doesn't delete the old ones to reduce churn. What remains to be done afterwards is thus: * finish the transition by deleting the duplicate lemmas from `Algebra.Order.SMul` * rearrange the non-duplicate lemmas into new files * generalise (most of) the lemmas from `Algebra.Order.Module` to `Algebra.Order.Module.Defs` * rethink `OrderedSMul` --- Mathlib.lean | 1 + Mathlib/Algebra/Order/Module.lean | 19 +- Mathlib/Algebra/Order/Module/Defs.lean | 891 +++++++++++++++++++++++++ Mathlib/Algebra/Order/SMul.lean | 75 +-- 4 files changed, 926 insertions(+), 60 deletions(-) create mode 100644 Mathlib/Algebra/Order/Module/Defs.lean diff --git a/Mathlib.lean b/Mathlib.lean index 8bd2eb421ebf6..c2ae7d7b47ca2 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -377,6 +377,7 @@ import Mathlib.Algebra.Order.Invertible import Mathlib.Algebra.Order.Kleene import Mathlib.Algebra.Order.LatticeGroup import Mathlib.Algebra.Order.Module +import Mathlib.Algebra.Order.Module.Defs import Mathlib.Algebra.Order.Module.Synonym import Mathlib.Algebra.Order.Monoid.Basic import Mathlib.Algebra.Order.Monoid.Canonical.Defs diff --git a/Mathlib/Algebra/Order/Module.lean b/Mathlib/Algebra/Order/Module.lean index 9293e492bc803..f8c47a176922a 100644 --- a/Mathlib/Algebra/Order/Module.lean +++ b/Mathlib/Algebra/Order/Module.lean @@ -12,6 +12,10 @@ import Mathlib.Algebra.Order.SMul In this file we provide lemmas about `OrderedSMul` that hold once a module structure is present. +## TODO + +Generalise lemmas to the framework from `Mathlib.Algebra.Order.Module.Defs`. + ## References * https://en.wikipedia.org/wiki/Ordered_vector_space @@ -65,12 +69,6 @@ theorem lt_of_smul_lt_smul_of_nonpos (h : c • a < c • b) (hc : c ≤ 0) : b exact lt_of_smul_lt_smul_of_nonneg h (neg_nonneg_of_nonpos hc) #align lt_of_smul_lt_smul_of_nonpos lt_of_smul_lt_smul_of_nonpos -lemma smul_le_smul_of_nonneg_right (h : c ≤ d) (hb : 0 ≤ b) : c • b ≤ d • b := by - rw [← sub_nonneg, ← sub_smul]; exact smul_nonneg (sub_nonneg.2 h) hb - -lemma smul_le_smul (hcd : c ≤ d) (hab : a ≤ b) (hc : 0 ≤ c) (hb : 0 ≤ b) : c • a ≤ d • b := - (smul_le_smul_of_nonneg_left hab hc).trans $ smul_le_smul_of_nonneg_right hcd hb - theorem smul_lt_smul_iff_of_neg (hc : c < 0) : c • a < c • b ↔ b < a := by rw [← neg_neg c, neg_smul, neg_smul (-c), neg_lt_neg_iff] exact smul_lt_smul_iff_of_pos (neg_pos_of_neg hc) @@ -86,23 +84,16 @@ theorem smul_pos_iff_of_neg (hc : c < 0) : 0 < c • a ↔ a < 0 := by exact smul_neg_iff_of_pos (neg_pos_of_neg hc) #align smul_pos_iff_of_neg smul_pos_iff_of_neg -theorem smul_nonpos_of_nonpos_of_nonneg (hc : c ≤ 0) (ha : 0 ≤ a) : c • a ≤ 0 := - calc - c • a ≤ c • (0 : M) := smul_le_smul_of_nonpos ha hc - _ = 0 := smul_zero c #align smul_nonpos_of_nonpos_of_nonneg smul_nonpos_of_nonpos_of_nonneg theorem smul_nonneg_of_nonpos_of_nonpos (hc : c ≤ 0) (ha : a ≤ 0) : 0 ≤ c • a := - @smul_nonpos_of_nonpos_of_nonneg k Mᵒᵈ _ _ _ _ _ _ hc ha + smul_nonpos_of_nonpos_of_nonneg (β := Mᵒᵈ) hc ha #align smul_nonneg_of_nonpos_of_nonpos smul_nonneg_of_nonpos_of_nonpos alias ⟨_, smul_pos_of_neg_of_neg⟩ := smul_pos_iff_of_neg #align smul_pos_of_neg_of_neg smul_pos_of_neg_of_neg -alias ⟨_, smul_neg_of_pos_of_neg⟩ := smul_neg_iff_of_pos #align smul_neg_of_pos_of_neg smul_neg_of_pos_of_neg - -alias ⟨_, smul_neg_of_neg_of_pos⟩ := smul_neg_iff_of_neg #align smul_neg_of_neg_of_pos smul_neg_of_neg_of_pos theorem antitone_smul_left (hc : c ≤ 0) : Antitone (SMul.smul c : M → M) := fun _ _ h => diff --git a/Mathlib/Algebra/Order/Module/Defs.lean b/Mathlib/Algebra/Order/Module/Defs.lean new file mode 100644 index 0000000000000..540341d9ebf36 --- /dev/null +++ b/Mathlib/Algebra/Order/Module/Defs.lean @@ -0,0 +1,891 @@ +/- +Copyright (c) 2023 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +import Mathlib.Algebra.Order.Module.Synonym +import Mathlib.Algebra.Order.Ring.Lemmas + +/-! +# Monotonicity of scalar multiplication by positive elements + +This file defines typeclasses to reason about monotonicity of the operations +* `b ↦ a • b`, "left scalar multiplication" +* `a ↦ a • b`, "right scalar multiplication" + +We use eight typeclasses to encode the various properties we care about for those two operations. +These typeclasses are meant to be mostly internal to this file, to set up each lemma in the +appropriate generality. + +Less granular typeclasses like `OrderedAddCommMonoid`, `LinearOrderedField`, `OrderedSMul` should be +enough for most purposes, and the system is set up so that they imply the correct granular +typeclasses here. If those are enough for you, you may stop reading here! Else, beware that what +follows is a bit technical. + +## Definitions + +In all that follows, `α` and `β` are orders which have a `0` and such that `α` acts on `β` by scalar +multiplication. Note however that we do not use lawfulness of this action in most of the file. Hence +`•` should be considered here as a mostly arbitrary function `α → β → β`. + +We use the following four typeclasses to reason about left scalar multiplication (`b ↦ a • b`): +* `PosSMulMono`: If `a ≥ 0`, then `b₁ ≤ b₂` implies `a • b₁ ≤ a • b₂`. +* `PosSMulStrictMono`: If `a > 0`, then `b₁ < b₂` implies `a • b₁ < a • b₂`. +* `PosSMulReflectLT`: If `a ≥ 0`, then `a • b₁ < a • b₂` implies `b₁ < b₂`. +* `PosSMulReflectLE`: If `a > 0`, then `a • b₁ ≤ a • b₂` implies `b₁ ≤ b₂`. + +We use the following four typeclasses to reason about right scalar multiplication (`a ↦ a • b`): +* `SMulPosMono`: If `b ≥ 0`, then `a₁ ≤ a₂` implies `a₁ • b ≤ a₂ • b`. +* `SMulPosStrictMono`: If `b > 0`, then `a₁ < a₂` implies `a₁ • b < a₂ • b`. +* `SMulPosReflectLT`: If `b ≥ 0`, then `a₁ • b < a₂ • b` implies `a₁ < a₂`. +* `SMulPosReflectLE`: If `b > 0`, then `a₁ • b ≤ a₂ • b` implies `a₁ ≤ a₂`. + +## Constructors + +The four typeclasses about nonnegativity can usually be checked only on positive inputs due to their +condition becoming trivial when `a = 0` or `b = 0`. We therefore make the following constructors +available: `PosSMulMono.of_pos`, `PosSMulReflectLT.of_pos`, `SMulPosMono.of_pos`, +`SMulPosReflectLT.of_pos` + +## Implications + +As `α` and `β` get more and more structure, those typeclasses end up being equivalent. The commonly +used implications are: +* When `α`, `β` are partial orders: + * `PosSMulStrictMono → PosSMulMono` + * `SMulPosStrictMono → SMulPosMono` + * `PosSMulReflectLE → PosSMulReflectLT` + * `SMulPosReflectLE → SMulPosReflectLT` +* When `β` is a linear order: `PosSMulStrictMono → PosSMulReflectLE` +* When `α` is a linear order: `SMulPosStrictMono → SMulPosReflectLE` +* When `α` is an ordered ring, `β` an ordered group and also an `α`-module: + * `PosSMulMono → SMulPosMono` + * `PosSMulStrictMono → SMulPosStrictMono` +* When `α` is an ordered semifield, `β` is an `α`-module: + * `PosSMulStrictMono → PosSMulReflectLT` + * `PosSMulMono → PosSMulReflectLE` + +Further, the bundled non-granular typeclasses imply the granular ones like so: +* `OrderedSMul → PosSMulStrictMono` +* `OrderedSMul → PosSMulReflectLT` + +All these are registered as instances, which means that in practice you should not worry about these +implications. However, if you encounter a case where you think a statement is true but not covered +by the current implications, please bring it up on Zulip! + +## Implementation notes + +This file uses custom typeclasses instead of abbreviations of `CovariantClass`/`ContravariantClass` +because: +* They get displayed as classes in the docs. In particular, one can see their list of instances, + instead of their instances being invariably dumped to the `CovariantClass`/`ContravariantClass` + list. +* They don't pollute other typeclass searches. Having many abbreviations of the same typeclass for + different purposes always felt like a performance issue (more instances with the same key, for no + added benefit), and indeed making the classes here abbreviation previous creates timeouts due to + the higher number of `CovariantClass`/`ContravariantClass` instances. +* `SMulPosReflectLT`/`SMulPosReflectLE` do not fit in the framework since they relate `≤` on two + different types. So we would have to generalise `CovariantClass`/`ContravariantClass` to three + types and two relations. +* Very minor, but the constructors let you work with `a : α`, `h : 0 ≤ a` instead of + `a : {a : α // 0 ≤ a}`. This actually makes some instances surprisingly cleaner to prove. +* The `CovariantClass`/`ContravariantClass` framework is only useful to automate very simple logic + anyway. It is easily copied over. + +In the future, it would be good to make the corresponding typeclasses in +`Mathlib.Algebra.Order.Ring.Lemmas` custom typeclasses too. + +## TODO + +This file acts as a substitute for `Mathlib.Algebra.Order.SMul`. We now need to +* finish the transition by deleting the duplicate lemmas +* rearrange the non-duplicate lemmas into new files +* generalise (most of) the lemmas from `Mathlib.Algebra.Order.Module` to here +* rethink `OrderedSMul` +-/ + +variable (α β : Type*) + +section Defs +variable [SMul α β] [Preorder α] [Preorder β] + +section Left +variable [Zero α] + +/-- Typeclass for monotonicity of scalar multiplication by nonnegative elements on the left, +namely `b₁ ≤ b₂ → a • b₁ ≤ a • b₂` if `0 ≤ a`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedSMul`. -/ +class PosSMulMono : Prop where + /-- Do not use this. Use `smul_le_smul_of_nonneg_left` instead. -/ + protected elim ⦃a : α⦄ (ha : 0 ≤ a) ⦃b₁ b₂ : β⦄ (hb : b₁ ≤ b₂) : a • b₁ ≤ a • b₂ + +/-- Typeclass for strict monotonicity of scalar multiplication by positive elements on the left, +namely `b₁ < b₂ → a • b₁ < a • b₂` if `0 < a`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedSMul`. -/ +class PosSMulStrictMono : Prop where + /-- Do not use this. Use `smul_lt_smul_of_pos_left` instead. -/ + protected elim ⦃a : α⦄ (ha : 0 < a) ⦃b₁ b₂ : β⦄ (hb : b₁ < b₂) : a • b₁ < a • b₂ + +/-- Typeclass for strict reverse monotonicity of scalar multiplication by nonnegative elements on +the left, namely `a • b₁ < a • b₂ → b₁ < b₂` if `0 ≤ a`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedSMul`. -/ +class PosSMulReflectLT : Prop where + /-- Do not use this. Use `lt_of_smul_lt_smul_left` instead. -/ + protected elim ⦃a : α⦄ (ha : 0 ≤ a) ⦃b₁ b₂ : β⦄ (hb : a • b₁ < a • b₂) : b₁ < b₂ + +/-- Typeclass for reverse monotonicity of scalar multiplication by positive elements on the left, +namely `a • b₁ ≤ a • b₂ → b₁ ≤ b₂` if `0 < a`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedSMul`. -/ +class PosSMulReflectLE : Prop where + /-- Do not use this. Use `le_of_smul_lt_smul_left` instead. -/ + protected elim ⦃a : α⦄ (ha : 0 < a) ⦃b₁ b₂ : β⦄ (hb : a • b₁ ≤ a • b₂) : b₁ ≤ b₂ + +end Left + +section Right +variable [Zero β] + +/-- Typeclass for monotonicity of scalar multiplication by nonnegative elements on the left, +namely `a₁ ≤ a₂ → a₁ • b ≤ a₂ • b` if `0 ≤ b`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedSMul`. -/ +class SMulPosMono : Prop where + /-- Do not use this. Use `smul_le_smul_of_nonneg_right` instead. -/ + protected elim ⦃b : β⦄ (hb : 0 ≤ b) ⦃a₁ a₂ : α⦄ (ha : a₁ ≤ a₂) : a₁ • b ≤ a₂ • b + +/-- Typeclass for strict monotonicity of scalar multiplication by positive elements on the left, +namely `a₁ < a₂ → a₁ • b < a₂ • b` if `0 < b`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedSMul`. -/ +class SMulPosStrictMono : Prop where + /-- Do not use this. Use `smul_lt_smul_of_pos_right` instead. -/ + protected elim ⦃b : β⦄ (hb : 0 < b) ⦃a₁ a₂ : α⦄ (ha : a₁ < a₂) : a₁ • b < a₂ • b + +/-- Typeclass for strict reverse monotonicity of scalar multiplication by nonnegative elements on +the left, namely `a₁ • b < a₂ • b → a₁ < a₂` if `0 ≤ b`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedSMul`. -/ +class SMulPosReflectLT : Prop where + /-- Do not use this. Use `lt_of_smul_lt_smul_right` instead. -/ + protected elim ⦃b : β⦄ (hb : 0 ≤ b) ⦃a₁ a₂ : α⦄ (hb : a₁ • b < a₂ • b) : a₁ < a₂ + +/-- Typeclass for reverse monotonicity of scalar multiplication by positive elements on the left, +namely `a₁ • b ≤ a₂ • b → a₁ ≤ a₂` if `0 < b`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedSMul`. -/ +class SMulPosReflectLE : Prop where + /-- Do not use this. Use `le_of_smul_lt_smul_right` instead. -/ + protected elim ⦃b : β⦄ (hb : 0 < b) ⦃a₁ a₂ : α⦄ (hb : a₁ • b ≤ a₂ • b) : a₁ ≤ a₂ + +end Right +end Defs + +variable {α β} {a a₁ a₂ : α} {b b₁ b₂ : β} + +section Mul +variable [Zero α] [Mul α] [Preorder α] + +-- See note [lower instance priority] +instance (priority := 100) PosMulMono.toPosSMulMono [PosMulMono α] : PosSMulMono α α where + elim _a ha _b₁ _b₂ hb := mul_le_mul_of_nonneg_left hb ha + +-- See note [lower instance priority] +instance (priority := 100) PosMulStrictMono.toPosSMulStrictMono [PosMulStrictMono α] : + PosSMulStrictMono α α where + elim _a ha _b₁ _b₂ hb := mul_lt_mul_of_pos_left hb ha + +-- See note [lower instance priority] +instance (priority := 100) PosMulReflectLT.toPosSMulReflectLT [PosMulReflectLT α] : + PosSMulReflectLT α α where + elim _a ha _b₁ _b₂ h := lt_of_mul_lt_mul_left h ha + +-- See note [lower instance priority] +instance (priority := 100) PosMulReflectLE.toPosSMulReflectLE [PosMulReflectLE α] : + PosSMulReflectLE α α where + elim _a ha _b₁ _b₂ h := le_of_mul_le_mul_left h ha + +-- See note [lower instance priority] +instance (priority := 100) MulPosMono.toSMulPosMono [MulPosMono α] : SMulPosMono α α where + elim _b hb _a₁ _a₂ ha := mul_le_mul_of_nonneg_right ha hb + +-- See note [lower instance priority] +instance (priority := 100) MulPosStrictMono.toSMulPosStrictMono [MulPosStrictMono α] : + SMulPosStrictMono α α where + elim _b hb _a₁ _a₂ ha := mul_lt_mul_of_pos_right ha hb + +-- See note [lower instance priority] +instance (priority := 100) MulPosReflectLT.toSMulPosReflectLT [MulPosReflectLT α] : + SMulPosReflectLT α α where + elim _b hb _a₁ _a₂ h := lt_of_mul_lt_mul_right h hb + +-- See note [lower instance priority] +instance (priority := 100) MulPosReflectLE.toSMulPosReflectLE [MulPosReflectLE α] : + SMulPosReflectLE α α where + elim _b hb _a₁ _a₂ h := le_of_mul_le_mul_right h hb + +end Mul + +section SMul +variable [SMul α β] + +section Preorder +variable [Preorder α] [Preorder β] + +section Left +variable [Zero α] + +lemma monotone_smul_left_of_nonneg [PosSMulMono α β] (ha : 0 ≤ a) : Monotone ((a • ·) : β → β) := + PosSMulMono.elim ha + +lemma strictMono_smul_left_of_pos [PosSMulStrictMono α β] (ha : 0 < a) : + StrictMono ((a • ·) : β → β) := PosSMulStrictMono.elim ha + +lemma smul_le_smul_of_nonneg_left [PosSMulMono α β] (hb : b₁ ≤ b₂) (ha : 0 ≤ a) : a • b₁ ≤ a • b₂ := + monotone_smul_left_of_nonneg ha hb + +lemma smul_lt_smul_of_pos_left [PosSMulStrictMono α β] (hb : b₁ < b₂) (ha : 0 < a) : + a • b₁ < a • b₂ := strictMono_smul_left_of_pos ha hb + +lemma lt_of_smul_lt_smul_left [PosSMulReflectLT α β] (h : a • b₁ < a • b₂) (ha : 0 ≤ a) : b₁ < b₂ := + PosSMulReflectLT.elim ha h + +lemma le_of_smul_le_smul_left [PosSMulReflectLE α β] (h : a • b₁ ≤ a • b₂) (ha : 0 < a) : b₁ ≤ b₂ := + PosSMulReflectLE.elim ha h + +alias lt_of_smul_lt_smul_of_nonneg_left := lt_of_smul_lt_smul_left +alias le_of_smul_le_smul_of_pos_left := le_of_smul_le_smul_left + +@[simp] +lemma smul_le_smul_iff_of_pos_left [PosSMulMono α β] [PosSMulReflectLE α β] (ha : 0 < a) : + a • b₁ ≤ a • b₂ ↔ b₁ ≤ b₂ := + ⟨fun h ↦ le_of_smul_le_smul_left h ha, fun h ↦ smul_le_smul_of_nonneg_left h ha.le⟩ + +@[simp] +lemma smul_lt_smul_iff_of_pos_left [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : + a • b₁ < a • b₂ ↔ b₁ < b₂ := + ⟨fun h ↦ lt_of_smul_lt_smul_left h ha.le, fun hb ↦ smul_lt_smul_of_pos_left hb ha⟩ + +end Left + +section Right +variable [Zero β] + +lemma monotone_smul_right_of_nonneg [SMulPosMono α β] (hb : 0 ≤ b) : Monotone ((· • b) : α → β) := + SMulPosMono.elim hb + +lemma strictMono_smul_right_of_pos [SMulPosStrictMono α β] (hb : 0 < b) : + StrictMono ((· • b) : α → β) := SMulPosStrictMono.elim hb + +lemma smul_le_smul_of_nonneg_right [SMulPosMono α β] (ha : a₁ ≤ a₂) (hb : 0 ≤ b) : + a₁ • b ≤ a₂ • b := monotone_smul_right_of_nonneg hb ha + +lemma smul_lt_smul_of_pos_right [SMulPosStrictMono α β] (ha : a₁ < a₂) (hb : 0 < b) : + a₁ • b < a₂ • b := strictMono_smul_right_of_pos hb ha + +lemma lt_of_smul_lt_smul_right [SMulPosReflectLT α β] (h : a₁ • b < a₂ • b) (hb : 0 ≤ b) : + a₁ < a₂ := SMulPosReflectLT.elim hb h + +lemma le_of_smul_le_smul_right [SMulPosReflectLE α β] (h : a₁ • b ≤ a₂ • b) (hb : 0 < b) : + a₁ ≤ a₂ := SMulPosReflectLE.elim hb h + +alias lt_of_smul_lt_smul_of_nonneg_right := lt_of_smul_lt_smul_right +alias le_of_smul_le_smul_of_pos_right := le_of_smul_le_smul_right + +@[simp] +lemma smul_le_smul_iff_of_pos_right [SMulPosMono α β] [SMulPosReflectLE α β] (hb : 0 < b) : + a₁ • b ≤ a₂ • b ↔ a₁ ≤ a₂ := + ⟨fun h ↦ le_of_smul_le_smul_right h hb, fun ha ↦ smul_le_smul_of_nonneg_right ha hb.le⟩ + +@[simp] +lemma smul_lt_smul_iff_of_pos_right [SMulPosStrictMono α β] [SMulPosReflectLT α β] (hb : 0 < b) : + a₁ • b < a₂ • b ↔ a₁ < a₂ := + ⟨fun h ↦ lt_of_smul_lt_smul_right h hb.le, fun ha ↦ smul_lt_smul_of_pos_right ha hb⟩ + +end Right + +section LeftRight +variable [Zero α] [Zero β] + +lemma smul_lt_smul_of_le_of_lt [PosSMulStrictMono α β] [SMulPosMono α β] (ha : a₁ ≤ a₂) + (hb : b₁ < b₂) (h₁ : 0 < a₁) (h₂ : 0 ≤ b₂) : a₁ • b₁ < a₂ • b₂ := + (smul_lt_smul_of_pos_left hb h₁).trans_le (smul_le_smul_of_nonneg_right ha h₂) + +lemma smul_lt_smul_of_le_of_lt' [PosSMulStrictMono α β] [SMulPosMono α β] (ha : a₁ ≤ a₂) + (hb : b₁ < b₂) (h₂ : 0 < a₂) (h₁ : 0 ≤ b₁) : a₁ • b₁ < a₂ • b₂ := + (smul_le_smul_of_nonneg_right ha h₁).trans_lt (smul_lt_smul_of_pos_left hb h₂) + +lemma smul_lt_smul_of_lt_of_le [PosSMulMono α β] [SMulPosStrictMono α β] (ha : a₁ < a₂) + (hb : b₁ ≤ b₂) (h₁ : 0 ≤ a₁) (h₂ : 0 < b₂) : a₁ • b₁ < a₂ • b₂ := + (smul_le_smul_of_nonneg_left hb h₁).trans_lt (smul_lt_smul_of_pos_right ha h₂) + +lemma smul_lt_smul_of_lt_of_le' [PosSMulMono α β] [SMulPosStrictMono α β] (ha : a₁ < a₂) + (hb : b₁ ≤ b₂) (h₂ : 0 ≤ a₂) (h₁ : 0 < b₁) : a₁ • b₁ < a₂ • b₂ := + (smul_lt_smul_of_pos_right ha h₁).trans_le (smul_le_smul_of_nonneg_left hb h₂) + +lemma smul_lt_smul [PosSMulStrictMono α β] [SMulPosStrictMono α β] (ha : a₁ < a₂) (hb : b₁ < b₂) + (h₁ : 0 < a₁) (h₂ : 0 < b₂) : a₁ • b₁ < a₂ • b₂ := + (smul_lt_smul_of_pos_left hb h₁).trans (smul_lt_smul_of_pos_right ha h₂) + +lemma smul_lt_smul' [PosSMulStrictMono α β] [SMulPosStrictMono α β] (ha : a₁ < a₂) (hb : b₁ < b₂) + (h₂ : 0 < a₂) (h₁ : 0 < b₁) : a₁ • b₁ < a₂ • b₂ := + (smul_lt_smul_of_pos_right ha h₁).trans (smul_lt_smul_of_pos_left hb h₂) + +lemma smul_le_smul [PosSMulMono α β] [SMulPosMono α β] (ha : a₁ ≤ a₂) (hb : b₁ ≤ b₂) + (h₁ : 0 ≤ a₁) (h₂ : 0 ≤ b₂) : a₁ • b₁ ≤ a₂ • b₂ := + (smul_le_smul_of_nonneg_left hb h₁).trans (smul_le_smul_of_nonneg_right ha h₂) + +lemma smul_le_smul' [PosSMulMono α β] [SMulPosMono α β] (ha : a₁ ≤ a₂) (hb : b₁ ≤ b₂) (h₂ : 0 ≤ a₂) + (h₁ : 0 ≤ b₁) : a₁ • b₁ ≤ a₂ • b₂ := + (smul_le_smul_of_nonneg_right ha h₁).trans (smul_le_smul_of_nonneg_left hb h₂) + +end LeftRight +end Preorder + +section LinearOrder +variable [Preorder α] [LinearOrder β] + +section Left +variable [Zero α] + +-- See note [lower instance priority] +instance (priority := 100) PosSMulStrictMono.toPosSMulReflectLE [PosSMulStrictMono α β] : + PosSMulReflectLE α β where + elim _a ha _b₁ _b₂ := (strictMono_smul_left_of_pos ha).le_iff_le.1 + +lemma PosSMulReflectLE.toPosSMulStrictMono [PosSMulReflectLE α β] : PosSMulStrictMono α β where + elim _a ha _b₁ _b₂ hb := not_le.1 fun h ↦ hb.not_le $ le_of_smul_le_smul_left h ha + +lemma posSMulStrictMono_iff_PosSMulReflectLE : PosSMulStrictMono α β ↔ PosSMulReflectLE α β := + ⟨fun _ ↦ inferInstance, fun _ ↦ PosSMulReflectLE.toPosSMulStrictMono⟩ + +instance PosSMulMono.toPosSMulReflectLT [PosSMulMono α β] : PosSMulReflectLT α β where + elim _a ha _b₁ _b₂ := (monotone_smul_left_of_nonneg ha).reflect_lt + +lemma PosSMulReflectLT.toPosSMulMono [PosSMulReflectLT α β] : PosSMulMono α β where + elim _a ha _b₁ _b₂ hb := not_lt.1 fun h ↦ hb.not_lt $ lt_of_smul_lt_smul_left h ha + +lemma posSMulMono_iff_posSMulReflectLT : PosSMulMono α β ↔ PosSMulReflectLT α β := + ⟨fun _ ↦ PosSMulMono.toPosSMulReflectLT, fun _ ↦ PosSMulReflectLT.toPosSMulMono⟩ + +lemma smul_max_of_nonneg [PosSMulMono α β] (ha : 0 ≤ a) (b₁ b₂ : β) : + a • max b₁ b₂ = max (a • b₁) (a • b₂) := (monotone_smul_left_of_nonneg ha).map_max + +lemma smul_min_of_nonneg [PosSMulMono α β] (ha : 0 ≤ a) (b₁ b₂ : β) : + a • min b₁ b₂ = min (a • b₁) (a • b₂) := (monotone_smul_left_of_nonneg ha).map_min + +end Left + +section Right +variable [Zero β] + +lemma SMulPosReflectLE.toSMulPosStrictMono [SMulPosReflectLE α β] : SMulPosStrictMono α β where + elim _b hb _a₁ _a₂ ha := not_le.1 fun h ↦ ha.not_le $ le_of_smul_le_smul_of_pos_right h hb + +lemma SMulPosReflectLT.toSMulPosMono [SMulPosReflectLT α β] : SMulPosMono α β where + elim _b hb _a₁ _a₂ ha := not_lt.1 fun h ↦ ha.not_lt $ lt_of_smul_lt_smul_right h hb + +end Right +end LinearOrder + +section LinearOrder +variable [LinearOrder α] [Preorder β] + +section Right +variable [Zero β] + +-- See note [lower instance priority] +instance (priority := 100) SMulPosStrictMono.toSMulPosReflectLE [SMulPosStrictMono α β] : + SMulPosReflectLE α β where + elim _b hb _a₁ _a₂ h := not_lt.1 fun ha ↦ h.not_lt $ smul_lt_smul_of_pos_right ha hb + +lemma SMulPosMono.toSMulPosReflectLT [SMulPosMono α β] : SMulPosReflectLT α β where + elim _b hb _a₁ _a₂ h := not_le.1 fun ha ↦ h.not_le $ smul_le_smul_of_nonneg_right ha hb + +end Right +end LinearOrder + +section LinearOrder +variable [LinearOrder α] [LinearOrder β] + +section Right +variable [Zero β] + +lemma smulPosStrictMono_iff_SMulPosReflectLE : SMulPosStrictMono α β ↔ SMulPosReflectLE α β := + ⟨fun _ ↦ SMulPosStrictMono.toSMulPosReflectLE, fun _ ↦ SMulPosReflectLE.toSMulPosStrictMono⟩ + +lemma smulPosMono_iff_smulPosReflectLT : SMulPosMono α β ↔ SMulPosReflectLT α β := + ⟨fun _ ↦ SMulPosMono.toSMulPosReflectLT, fun _ ↦ SMulPosReflectLT.toSMulPosMono⟩ + +end Right +end LinearOrder +end SMul + +section SMulZeroClass +variable [Zero α] [Zero β] [SMulZeroClass α β] + +section Preorder +variable [Preorder α] [Preorder β] + +lemma smul_pos [PosSMulStrictMono α β] (ha : 0 < a) (hb : 0 < b) : 0 < a • b := by + simpa only [smul_zero] using smul_lt_smul_of_pos_left hb ha + +lemma smul_neg_of_pos_of_neg [PosSMulStrictMono α β] (ha : 0 < a) (hb : b < 0) : a • b < 0 := by + simpa only [smul_zero] using smul_lt_smul_of_pos_left hb ha + +@[simp] +lemma smul_pos_iff_of_pos_left [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : + 0 < a • b ↔ 0 < b := by + simpa only [smul_zero] using smul_lt_smul_iff_of_pos_left ha (b₁ := 0) (b₂ := b) + +lemma smul_nonneg [PosSMulMono α β] (ha : 0 ≤ a) (hb : 0 ≤ b₁) : 0 ≤ a • b₁ := by + simpa only [smul_zero] using smul_le_smul_of_nonneg_left hb ha + +lemma smul_nonpos_of_nonneg_of_nonpos [PosSMulMono α β] (ha : 0 ≤ a) (hb : b ≤ 0) : a • b ≤ 0 := by + simpa only [smul_zero] using smul_le_smul_of_nonneg_left hb ha + +lemma pos_of_smul_pos_right [PosSMulReflectLT α β] (h : 0 < a • b) (ha : 0 ≤ a) : 0 < b := + lt_of_smul_lt_smul_left (by rwa [smul_zero]) ha + +end Preorder +end SMulZeroClass + +section SMulWithZero +variable [Zero α] [Zero β] [SMulWithZero α β] + +section Preorder +variable [Preorder α] [Preorder β] + +lemma smul_pos' [SMulPosStrictMono α β] (ha : 0 < a) (hb : 0 < b) : 0 < a • b := by + simpa only [zero_smul] using smul_lt_smul_of_pos_right ha hb + +lemma smul_neg_of_neg_of_pos [SMulPosStrictMono α β] (ha : a < 0) (hb : 0 < b) : a • b < 0 := by + simpa only [zero_smul] using smul_lt_smul_of_pos_right ha hb + +@[simp] +lemma smul_pos_iff_of_pos_right [SMulPosStrictMono α β] [SMulPosReflectLT α β] (hb : 0 < b) : + 0 < a • b ↔ 0 < a := by + simpa only [zero_smul] using smul_lt_smul_iff_of_pos_right hb (a₁ := 0) (a₂ := a) + +lemma smul_nonneg' [SMulPosMono α β] (ha : 0 ≤ a) (hb : 0 ≤ b₁) : 0 ≤ a • b₁ := by + simpa only [zero_smul] using smul_le_smul_of_nonneg_right ha hb + +lemma smul_nonpos_of_nonpos_of_nonneg [SMulPosMono α β] (ha : a ≤ 0) (hb : 0 ≤ b) : a • b ≤ 0 := by + simpa only [zero_smul] using smul_le_smul_of_nonneg_right ha hb + +lemma pos_of_smul_pos_left [SMulPosReflectLT α β] (h : 0 < a • b) (hb : 0 ≤ b) : 0 < a := + lt_of_smul_lt_smul_right (by rwa [zero_smul]) hb + +lemma pos_iff_pos_of_smul_pos [PosSMulReflectLT α β] [SMulPosReflectLT α β] (hab : 0 < a • b) : + 0 < a ↔ 0 < b := + ⟨pos_of_smul_pos_right hab ∘ le_of_lt, pos_of_smul_pos_left hab ∘ le_of_lt⟩ + +end Preorder + +section PartialOrder +variable [PartialOrder α] [Preorder β] + +/-- A constructor for `PosSMulMono` requiring you to prove `b₁ ≤ b₂ → a • b₁ ≤ a • b₂` only when +`0 < a`-/ +lemma PosSMulMono.of_pos (h₀ : ∀ a : α, 0 < a → ∀ b₁ b₂ : β, b₁ ≤ b₂ → a • b₁ ≤ a • b₂) : + PosSMulMono α β where + elim a ha b₁ b₂ h := by + obtain ha | ha := ha.eq_or_lt + · simp [← ha] + · exact h₀ _ ha _ _ h + +/-- A constructor for `PosSMulReflectLT` requiring you to prove `a • b₁ < a • b₂ → b₁ < b₂` only +when `0 < a`-/ +lemma PosSMulReflectLT.of_pos (h₀ : ∀ a : α, 0 < a → ∀ b₁ b₂ : β, a • b₁ < a • b₂ → b₁ < b₂) : + PosSMulReflectLT α β where + elim a ha b₁ b₂ h := by + obtain ha | ha := ha.eq_or_lt + · simp [← ha] at h + · exact h₀ _ ha _ _ h + +end PartialOrder + +section PartialOrder +variable [Preorder α] [PartialOrder β] + +/-- A constructor for `SMulPosMono` requiring you to prove `a₁ ≤ a₂ → a₁ • b ≤ a₂ • b` only when +`0 < b`-/ +lemma SMulPosMono.of_pos (h₀ : ∀ b : β, 0 < b → ∀ a₁ a₂ : α, a₁ ≤ a₂ → a₁ • b ≤ a₂ • b) : + SMulPosMono α β where + elim b hb a₁ a₂ h := by + obtain hb | hb := hb.eq_or_lt + · simp [← hb] + · exact h₀ _ hb _ _ h + +/-- A constructor for `SMulPosReflectLT` requiring you to prove `a₁ • b < a₂ • b → a₁ < a₂` only +when `0 < b`-/ +lemma SMulPosReflectLT.of_pos (h₀ : ∀ b : β, 0 < b → ∀ a₁ a₂ : α, a₁ • b < a₂ • b → a₁ < a₂) : + SMulPosReflectLT α β where + elim b hb a₁ a₂ h := by + obtain hb | hb := hb.eq_or_lt + · simp [← hb] at h + · exact h₀ _ hb _ _ h + +end PartialOrder + +section PartialOrder +variable [PartialOrder α] [PartialOrder β] + +-- See note [lower instance priority] +instance (priority := 100) PosSMulStrictMono.toPosSMulMono [PosSMulStrictMono α β] : + PosSMulMono α β := + PosSMulMono.of_pos fun _a ha ↦ (strictMono_smul_left_of_pos ha).monotone + +-- See note [lower instance priority] +instance (priority := 100) SMulPosStrictMono.toSMulPosMono [SMulPosStrictMono α β] : + SMulPosMono α β := + SMulPosMono.of_pos fun _b hb ↦ (strictMono_smul_right_of_pos hb).monotone + +-- See note [lower instance priority] +instance (priority := 100) PosSMulReflectLE.toPosSMulReflectLT [PosSMulReflectLE α β] : + PosSMulReflectLT α β := + PosSMulReflectLT.of_pos fun a ha b₁ b₂ h ↦ + (le_of_smul_le_smul_of_pos_left h.le ha).lt_of_ne $ by rintro rfl; simp at h + +-- See note [lower instance priority] +instance (priority := 100) SMulPosReflectLE.toSMulPosReflectLT [SMulPosReflectLE α β] : + SMulPosReflectLT α β := + SMulPosReflectLT.of_pos fun b hb a₁ a₂ h ↦ + (le_of_smul_le_smul_of_pos_right h.le hb).lt_of_ne $ by rintro rfl; simp at h + +lemma smul_eq_smul_iff_eq_and_eq_of_pos [PosSMulStrictMono α β] [SMulPosStrictMono α β] + (ha : a₁ ≤ a₂) (hb : b₁ ≤ b₂) (h₁ : 0 < a₁) (h₂ : 0 < b₂) : + a₁ • b₁ = a₂ • b₂ ↔ a₁ = a₂ ∧ b₁ = b₂ := by + refine ⟨fun h ↦ ?_, by rintro ⟨rfl, rfl⟩; rfl⟩ + simp only [eq_iff_le_not_lt, ha, hb, true_and] + refine ⟨fun ha ↦ h.not_lt ?_, fun hb ↦ h.not_lt ?_⟩ + · exact (smul_le_smul_of_nonneg_left hb h₁.le).trans_lt (smul_lt_smul_of_pos_right ha h₂) + · exact (smul_lt_smul_of_pos_left hb h₁).trans_le (smul_le_smul_of_nonneg_right ha h₂.le) + +lemma smul_eq_smul_iff_eq_and_eq_of_pos' [PosSMulStrictMono α β] [SMulPosStrictMono α β] + (ha : a₁ ≤ a₂) (hb : b₁ ≤ b₂) (h₂ : 0 < a₂) (h₁ : 0 < b₁) : + a₁ • b₁ = a₂ • b₂ ↔ a₁ = a₂ ∧ b₁ = b₂ := by + refine ⟨fun h ↦ ?_, by rintro ⟨rfl, rfl⟩; rfl⟩ + simp only [eq_iff_le_not_lt, ha, hb, true_and] + refine ⟨fun ha ↦ h.not_lt ?_, fun hb ↦ h.not_lt ?_⟩ + · exact (smul_lt_smul_of_pos_right ha h₁).trans_le (smul_le_smul_of_nonneg_left hb h₂.le) + · exact (smul_le_smul_of_nonneg_right ha h₁.le).trans_lt (smul_lt_smul_of_pos_left hb h₂) + +end PartialOrder + +section LinearOrder +variable [LinearOrder α] [LinearOrder β] + +lemma pos_and_pos_or_neg_and_neg_of_smul_pos [PosSMulMono α β] [SMulPosMono α β] (hab : 0 < a • b) : + 0 < a ∧ 0 < b ∨ a < 0 ∧ b < 0 := by + obtain ha | rfl | ha := lt_trichotomy a 0 + · refine' Or.inr ⟨ha, lt_imp_lt_of_le_imp_le (fun hb ↦ _) hab⟩ + exact smul_nonpos_of_nonpos_of_nonneg ha.le hb + · rw [zero_smul] at hab + exact hab.false.elim + · refine' Or.inl ⟨ha, lt_imp_lt_of_le_imp_le (fun hb ↦ _) hab⟩ + exact smul_nonpos_of_nonneg_of_nonpos ha.le hb + +lemma neg_of_smul_pos_right [PosSMulMono α β] [SMulPosMono α β] (h : 0 < a • b) (ha : a ≤ 0) : + b < 0 := ((pos_and_pos_or_neg_and_neg_of_smul_pos h).resolve_left fun h ↦ h.1.not_le ha).2 + +lemma neg_of_smul_pos_left [PosSMulMono α β] [SMulPosMono α β] (h : 0 < a • b) (ha : b ≤ 0) : + a < 0 := ((pos_and_pos_or_neg_and_neg_of_smul_pos h).resolve_left fun h ↦ h.2.not_le ha).1 + +lemma neg_iff_neg_of_smul_pos [PosSMulMono α β] [SMulPosMono α β] (hab : 0 < a • b) : + a < 0 ↔ b < 0 := + ⟨neg_of_smul_pos_right hab ∘ le_of_lt, neg_of_smul_pos_left hab ∘ le_of_lt⟩ + +lemma neg_of_smul_neg_left [PosSMulMono α β] (h : a • b < 0) (ha : 0 ≤ a) : b < 0 := + lt_of_not_ge fun hb ↦ (smul_nonneg ha hb).not_lt h + +lemma neg_of_smul_neg_left' [SMulPosMono α β] (h : a • b < 0) (ha : 0 ≤ a) : b < 0 := + lt_of_not_ge fun hb ↦ (smul_nonneg' ha hb).not_lt h + +lemma neg_of_smul_neg_right [PosSMulMono α β] (h : a • b < 0) (hb : 0 ≤ b) : a < 0 := + lt_of_not_ge fun ha ↦ (smul_nonneg ha hb).not_lt h + +lemma neg_of_smul_neg_right' [SMulPosMono α β] (h : a • b < 0) (hb : 0 ≤ b) : a < 0 := + lt_of_not_ge fun ha ↦ (smul_nonneg' ha hb).not_lt h + +end LinearOrder +end SMulWithZero + +section MulAction +variable [Monoid α] [Zero α] [Zero β] [MulAction α β] + +section Preorder +variable [Preorder α] [Preorder β] + +@[simp] +lemma le_smul_iff_one_le_left [SMulPosMono α β] [SMulPosReflectLE α β] (hb : 0 < b) : + b ≤ a • b ↔ 1 ≤ a := Iff.trans (by rw [one_smul]) (smul_le_smul_iff_of_pos_right hb) + +@[simp] +lemma lt_smul_iff_one_lt_left [SMulPosStrictMono α β] [SMulPosReflectLT α β] (hb : 0 < b) : + b < a • b ↔ 1 < a := Iff.trans (by rw [one_smul]) (smul_lt_smul_iff_of_pos_right hb) + +@[simp] +lemma smul_le_iff_le_one_left [SMulPosMono α β] [SMulPosReflectLE α β] (hb : 0 < b) : + a • b ≤ b ↔ a ≤ 1 := Iff.trans (by rw [one_smul]) (smul_le_smul_iff_of_pos_right hb) + +@[simp] +lemma smul_lt_iff_lt_one_left [SMulPosStrictMono α β] [SMulPosReflectLT α β] (hb : 0 < b) : + a • b < b ↔ a < 1 := Iff.trans (by rw [one_smul]) (smul_lt_smul_iff_of_pos_right hb) + +lemma smul_le_of_le_one_left [SMulPosMono α β] (hb : 0 ≤ b) (h : a ≤ 1) : a • b ≤ b := by + simpa only [one_smul] using smul_le_smul_of_nonneg_right h hb + +lemma le_smul_of_one_le_left [SMulPosMono α β] (hb : 0 ≤ b) (h : 1 ≤ a) : b ≤ a • b := by + simpa only [one_smul] using smul_le_smul_of_nonneg_right h hb + +lemma smul_lt_of_lt_one_left [SMulPosStrictMono α β] (hb : 0 < b) (h : a < 1) : a • b < b := by + simpa only [one_smul] using smul_lt_smul_of_pos_right h hb + +lemma lt_smul_of_one_lt_left [SMulPosStrictMono α β] (hb : 0 < b) (h : 1 < a) : b < a • b := by + simpa only [one_smul] using smul_lt_smul_of_pos_right h hb + +end Preorder +end MulAction + +section Semiring +variable [Semiring α] [AddCommGroup β] [Module α β] [NoZeroSMulDivisors α β] + +section PartialOrder +variable [Preorder α] [PartialOrder β] + +lemma PosSMulMono.toPosSMulStrictMono [PosSMulMono α β] : PosSMulStrictMono α β := + ⟨fun _a ha _b₁ _b₂ hb ↦ (smul_le_smul_of_nonneg_left hb.le ha.le).lt_of_ne $ + (smul_right_injective _ ha.ne').ne hb.ne⟩ + +instance PosSMulReflectLT.toPosSMulReflectLE [PosSMulReflectLT α β] : PosSMulReflectLE α β := + ⟨fun _a ha _b₁ _b₂ h ↦ h.eq_or_lt.elim (fun h ↦ (smul_right_injective _ ha.ne' h).le) fun h' ↦ + (lt_of_smul_lt_smul_left h' ha.le).le⟩ + +end PartialOrder + +section PartialOrder +variable [PartialOrder α] [PartialOrder β] + +lemma posSMulMono_iff_posSMulStrictMono : PosSMulMono α β ↔ PosSMulStrictMono α β := + ⟨fun _ ↦ PosSMulMono.toPosSMulStrictMono, fun _ ↦ inferInstance⟩ + +lemma PosSMulReflectLE_iff_posSMulReflectLT : PosSMulReflectLE α β ↔ PosSMulReflectLT α β := + ⟨fun _ ↦ inferInstance, fun _ ↦ PosSMulReflectLT.toPosSMulReflectLE⟩ + +end PartialOrder +end Semiring + +section Ring +variable [Ring α] [AddCommGroup β] [Module α β] [NoZeroSMulDivisors α β] + +section PartialOrder +variable [PartialOrder α] [PartialOrder β] + +lemma SMulPosMono.toSMulPosStrictMono [SMulPosMono α β] : SMulPosStrictMono α β := + ⟨fun _b hb _a₁ _a₂ ha ↦ (smul_le_smul_of_nonneg_right ha.le hb.le).lt_of_ne $ + (smul_left_injective _ hb.ne').ne ha.ne⟩ + +lemma smulPosMono_iff_smulPosStrictMono : SMulPosMono α β ↔ SMulPosStrictMono α β := + ⟨fun _ ↦ SMulPosMono.toSMulPosStrictMono, fun _ ↦ inferInstance⟩ + +lemma SMulPosReflectLT.toSMulPosReflectLE [SMulPosReflectLT α β] : SMulPosReflectLE α β := + ⟨fun _b hb _a₁ _a₂ h ↦ h.eq_or_lt.elim (fun h ↦ (smul_left_injective _ hb.ne' h).le) fun h' ↦ + (lt_of_smul_lt_smul_right h' hb.le).le⟩ + +lemma SMulPosReflectLE_iff_smulPosReflectLT : SMulPosReflectLE α β ↔ SMulPosReflectLT α β := + ⟨fun _ ↦ inferInstance, fun _ ↦ SMulPosReflectLT.toSMulPosReflectLE⟩ + +end PartialOrder +end Ring + +section OrderedRing +variable [OrderedRing α] [OrderedAddCommGroup β] [Module α β] + +instance PosSMulMono.toSMulPosMono [PosSMulMono α β] : SMulPosMono α β where + elim _b hb a₁ a₂ ha := by rw [← sub_nonneg, ← sub_smul]; exact smul_nonneg (sub_nonneg.2 ha) hb + +instance PosSMulStrictMono.toSMulPosStrictMono [PosSMulStrictMono α β] : SMulPosStrictMono α β where + elim _b hb a₁ a₂ ha := by rw [← sub_pos, ← sub_smul]; exact smul_pos (sub_pos.2 ha) hb + +end OrderedRing + +section Field +variable [GroupWithZero α] [Preorder α] [Preorder β] [MulAction α β] + +lemma inv_smul_le_iff_of_pos [PosSMulMono α β] [PosSMulReflectLE α β] (ha : 0 < a) : + a⁻¹ • b₁ ≤ b₂ ↔ b₁ ≤ a • b₂ := by rw [← smul_le_smul_iff_of_pos_left ha, smul_inv_smul₀ ha.ne'] + +lemma le_inv_smul_iff_of_pos [PosSMulMono α β] [PosSMulReflectLE α β] (ha : 0 < a) : + b₁ ≤ a⁻¹ • b₂ ↔ a • b₁ ≤ b₂ := by rw [← smul_le_smul_iff_of_pos_left ha, smul_inv_smul₀ ha.ne'] + +lemma inv_smul_lt_iff_of_pos [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : + a⁻¹ • b₁ < b₂ ↔ b₁ < a • b₂ := by rw [← smul_lt_smul_iff_of_pos_left ha, smul_inv_smul₀ ha.ne'] + +lemma lt_inv_smul_iff_of_pos [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : + b₁ < a⁻¹ • b₂ ↔ a • b₁ < b₂ := by rw [← smul_lt_smul_iff_of_pos_left ha, smul_inv_smul₀ ha.ne'] + +end Field + +section LinearOrderedSemifield +variable [LinearOrderedSemifield α] [AddCommGroup β] [PartialOrder β] + +-- See note [lower instance priority] +instance (priority := 100) PosSMulMono.toPosSMulReflectLE [MulAction α β] [PosSMulMono α β] : + PosSMulReflectLE α β where + elim _a ha b₁ b₂ h := by simpa [ha.ne'] using smul_le_smul_of_nonneg_left h $ inv_nonneg.2 ha.le + +-- See note [lower instance priority] +instance (priority := 100) PosSMulStrictMono.toPosSMulReflectLT [MulActionWithZero α β] + [PosSMulStrictMono α β] : PosSMulReflectLT α β := + PosSMulReflectLT.of_pos fun a ha b₁ b₂ h ↦ by + simpa [ha.ne'] using smul_lt_smul_of_pos_left h $ inv_pos.2 ha + +end LinearOrderedSemifield + +namespace OrderDual + +section Left +variable [Preorder α] [Preorder β] [SMul α β] [Zero α] + +instance instPosSMulMono [PosSMulMono α β] : PosSMulMono α βᵒᵈ where + elim _a ha _b₁ _b₂ hb := smul_le_smul_of_nonneg_left (β := β) hb ha +instance instPosSMulStrictMono [PosSMulStrictMono α β] : PosSMulStrictMono α βᵒᵈ where + elim _a ha _b₁ _b₂ hb := smul_lt_smul_of_pos_left (β := β) hb ha +instance instPosSMulReflectLT [PosSMulReflectLT α β] : PosSMulReflectLT α βᵒᵈ where + elim _a ha _b₁ _b₂ h := lt_of_smul_lt_smul_of_nonneg_left (β := β) h ha +instance instPosSMulReflectLE [PosSMulReflectLE α β] : PosSMulReflectLE α βᵒᵈ where + elim _a ha _b₁ _b₂ h := le_of_smul_le_smul_of_pos_left (β := β) h ha + +end Left + +section Right +variable [Preorder α] [Ring α] [OrderedAddCommGroup β] [Module α β] + +instance instSMulPosMono [SMulPosMono α β] : SMulPosMono α βᵒᵈ where + elim _b hb a₁ a₂ ha := by + rw [← neg_le_neg_iff, ← smul_neg, ← smul_neg] + exact smul_le_smul_of_nonneg_right (β := β) ha $ neg_nonneg.2 hb + +instance instSMulPosStrictMono [SMulPosStrictMono α β] : SMulPosStrictMono α βᵒᵈ where + elim _b hb a₁ a₂ ha := by + rw [← neg_lt_neg_iff, ← smul_neg, ← smul_neg] + exact smul_lt_smul_of_pos_right (β := β) ha $ neg_pos.2 hb + +instance instSMulPosReflectLT [SMulPosReflectLT α β] : SMulPosReflectLT α βᵒᵈ where + elim _b hb a₁ a₂ h := by + rw [← neg_lt_neg_iff, ← smul_neg, ← smul_neg] at h + exact lt_of_smul_lt_smul_right (β := β) h $ neg_nonneg.2 hb + +instance instSMulPosReflectLE [SMulPosReflectLE α β] : SMulPosReflectLE α βᵒᵈ where + elim _b hb a₁ a₂ h := by + rw [← neg_le_neg_iff, ← smul_neg, ← smul_neg] at h + exact le_of_smul_le_smul_right (β := β) h $ neg_pos.2 hb + +end Right +end OrderDual + +namespace Prod + +end Prod + +namespace Pi +variable {ι : Type*} {β : ι → Type*} [Zero α] [∀ i, Zero (β i)] + +section SMulZeroClass +variable [Preorder α] [∀ i, Preorder (β i)] [∀ i, SMulZeroClass α (β i)] + +instance instPosSMulMono [∀ i, PosSMulMono α (β i)] : PosSMulMono α (∀ i, β i) where + elim _a ha _b₁ _b₂ hb i := smul_le_smul_of_nonneg_left (hb i) ha + +instance instSMulPosMono [∀ i, SMulPosMono α (β i)] : SMulPosMono α (∀ i, β i) where + elim _b hb _a₁ _a₂ ha i := smul_le_smul_of_nonneg_right ha (hb i) + +instance instPosSMulReflectLE [∀ i, PosSMulReflectLE α (β i)] : PosSMulReflectLE α (∀ i, β i) where + elim _a ha _b₁ _b₂ h i := le_of_smul_le_smul_left (h i) ha + +instance instSMulPosReflectLE [∀ i, SMulPosReflectLE α (β i)] : SMulPosReflectLE α (∀ i, β i) where + elim _b hb _a₁ _a₂ h := by + obtain ⟨-, i, hi⟩ := lt_def.1 hb; exact le_of_smul_le_smul_right (h _) hi + +end SMulZeroClass + +section SMulWithZero +variable [PartialOrder α] [∀ i, PartialOrder (β i)] [∀ i, SMulWithZero α (β i)] + +instance instPosSMulStrictMono [∀ i, PosSMulStrictMono α (β i)] : + PosSMulStrictMono α (∀ i, β i) where + elim := by + simp_rw [lt_def] + rintro _a ha _b₁ _b₂ ⟨hb, i, hi⟩ + exact ⟨smul_le_smul_of_nonneg_left hb ha.le, i, smul_lt_smul_of_pos_left hi ha⟩ + +instance instSMulPosStrictMono [∀ i, SMulPosStrictMono α (β i)] : + SMulPosStrictMono α (∀ i, β i) where + elim := by + simp_rw [lt_def] + rintro a ⟨ha, i, hi⟩ _b₁ _b₂ hb + exact ⟨smul_le_smul_of_nonneg_right hb.le ha, i, smul_lt_smul_of_pos_right hb hi⟩ + +-- Note: There is no interesting instance for `PosSMulReflectLT α (∀ i, β i)` that's not already +-- implied by the other instances + +instance instSMulPosReflectLT [∀ i, SMulPosReflectLT α (β i)] : SMulPosReflectLT α (∀ i, β i) where + elim := by + simp_rw [lt_def] + rintro b hb _a₁ _a₂ ⟨-, i, hi⟩ + exact lt_of_smul_lt_smul_right hi $ hb _ + +end SMulWithZero +end Pi + +section Lift +variable {γ : Type*} [Zero α] [Preorder α] [Zero β] [Preorder β] [Zero γ] [Preorder γ] + [SMul α β] [SMul α γ] (f : β → γ) (hf : ∀ {b₁ b₂}, f b₁ ≤ f b₂ ↔ b₁ ≤ b₂) + (smul : ∀ (a : α) b, f (a • b) = a • f b) (zero : f 0 = 0) + +lemma PosSMulMono.lift [PosSMulMono α γ] : PosSMulMono α β where + elim a ha b₁ b₂ hb := by simp only [← hf, smul] at *; exact smul_le_smul_of_nonneg_left hb ha + +lemma PosSMulStrictMono.lift [PosSMulStrictMono α γ] : PosSMulStrictMono α β where + elim a ha b₁ b₂ hb := by + simp only [← lt_iff_lt_of_le_iff_le' hf hf, smul] at *; exact smul_lt_smul_of_pos_left hb ha + +lemma PosSMulReflectLE.lift [PosSMulReflectLE α γ] : PosSMulReflectLE α β where + elim a ha b₁ b₂ h := hf.1 $ le_of_smul_le_smul_left (by simpa only [smul] using hf.2 h) ha + +lemma PosSMulReflectLT.lift [PosSMulReflectLT α γ] : PosSMulReflectLT α β where + elim a ha b₁ b₂ h := by + simp only [← lt_iff_lt_of_le_iff_le' hf hf, smul] at *; exact lt_of_smul_lt_smul_left h ha + +lemma SMulPosMono.lift [SMulPosMono α γ] : SMulPosMono α β where + elim b hb a₁ a₂ ha := by + simp only [← hf, zero, smul] at *; exact smul_le_smul_of_nonneg_right ha hb + +lemma SMulPosStrictMono.lift [SMulPosStrictMono α γ] : SMulPosStrictMono α β where + elim b hb a₁ a₂ ha := by + simp only [← lt_iff_lt_of_le_iff_le' hf hf, zero, smul] at * + exact smul_lt_smul_of_pos_right ha hb + +lemma SMulPosReflectLE.lift [SMulPosReflectLE α γ] : SMulPosReflectLE α β where + elim b hb a₁ a₂ h := by + simp only [← hf, ← lt_iff_lt_of_le_iff_le' hf hf, zero, smul] at * + exact le_of_smul_le_smul_right h hb + +lemma SMulPosReflectLT.lift [SMulPosReflectLT α γ] : SMulPosReflectLT α β where + elim b hb a₁ a₂ h := by + simp only [← hf, ← lt_iff_lt_of_le_iff_le' hf hf, zero, smul] at * + exact lt_of_smul_lt_smul_right h hb + +end Lift diff --git a/Mathlib/Algebra/Order/SMul.lean b/Mathlib/Algebra/Order/SMul.lean index 099d97214c37e..3938b6e825f39 100644 --- a/Mathlib/Algebra/Order/SMul.lean +++ b/Mathlib/Algebra/Order/SMul.lean @@ -5,7 +5,7 @@ Authors: Frédéric Dupuis -/ import Mathlib.Algebra.Module.Pi import Mathlib.Algebra.Module.Prod -import Mathlib.Algebra.Order.Module.Synonym +import Mathlib.Algebra.Order.Module.Defs import Mathlib.Algebra.Order.Monoid.Prod import Mathlib.Algebra.Order.Pi import Mathlib.Data.Set.Pointwise.SMul @@ -31,6 +31,10 @@ In this file we define * To get ordered modules and ordered vector spaces, it suffices to replace the `OrderedAddCommMonoid` and the `OrderedSemiring` as desired. +## TODO + +Delete the lemmas that have been generalised by `PosSMulMono` and friends. + ## References * https://en.wikipedia.org/wiki/Ordered_vector_space @@ -66,29 +70,21 @@ section OrderedSMul variable [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] [OrderedSMul R M] {s : Set M} {a b : M} {c : R} -@[gcongr] theorem smul_lt_smul_of_pos : a < b → 0 < c → c • a < c • b := - OrderedSMul.smul_lt_smul_of_pos -#align smul_lt_smul_of_pos smul_lt_smul_of_pos +instance OrderedSMul.toPosSMulStrictMono : PosSMulStrictMono R M where + elim _a ha _b₁ _b₂ hb := OrderedSMul.smul_lt_smul_of_pos hb ha -@[gcongr] theorem smul_le_smul_of_nonneg (h₁ : a ≤ b) (h₂ : 0 ≤ c) : c • a ≤ c • b := by - rcases h₁.eq_or_lt with (rfl | hab) - · rfl - · rcases h₂.eq_or_lt with (rfl | hc) - · rw [zero_smul, zero_smul] - · exact (smul_lt_smul_of_pos hab hc).le -#align smul_le_smul_of_nonneg smul_le_smul_of_nonneg +instance OrderedSMul.toPosSMulReflectLT : PosSMulReflectLT R M := + PosSMulReflectLT.of_pos $ fun _a ha _b₁ _b₂ h ↦ OrderedSMul.lt_of_smul_lt_smul_of_pos h ha + +@[gcongr] theorem smul_lt_smul_of_pos : a < b → 0 < c → c • a < c • b := smul_lt_smul_of_pos_left +#align smul_lt_smul_of_pos smul_lt_smul_of_pos -- TODO: Remove `smul_le_smul_of_nonneg` completely -alias smul_le_smul_of_nonneg_left := smul_le_smul_of_nonneg +@[gcongr] theorem smul_le_smul_of_nonneg (h₁ : a ≤ b) (h₂ : 0 ≤ c) : c • a ≤ c • b := + smul_le_smul_of_nonneg_left h₁ h₂ +#align smul_le_smul_of_nonneg smul_le_smul_of_nonneg -theorem smul_nonneg (hc : 0 ≤ c) (ha : 0 ≤ a) : 0 ≤ c • a := - calc - (0 : M) = c • (0 : M) := (smul_zero c).symm - _ ≤ c • a := smul_le_smul_of_nonneg ha hc #align smul_nonneg smul_nonneg - -theorem smul_nonpos_of_nonneg_of_nonpos (hc : 0 ≤ c) (ha : a ≤ 0) : c • a ≤ 0 := - @smul_nonneg R Mᵒᵈ _ _ _ _ _ _ hc ha #align smul_nonpos_of_nonneg_of_nonpos smul_nonpos_of_nonneg_of_nonpos theorem eq_of_smul_eq_smul_of_pos_of_le (h₁ : c • a = c • b) (hc : 0 < c) (hle : a ≤ b) : a = b := @@ -96,30 +92,24 @@ theorem eq_of_smul_eq_smul_of_pos_of_le (h₁ : c • a = c • b) (hc : 0 < c) #align eq_of_smul_eq_smul_of_pos_of_le eq_of_smul_eq_smul_of_pos_of_le theorem lt_of_smul_lt_smul_of_nonneg (h : c • a < c • b) (hc : 0 ≤ c) : a < b := - hc.eq_or_lt.elim - (fun hc => False.elim <| lt_irrefl (0 : M) <| by rwa [← hc, zero_smul, zero_smul] at h) - (OrderedSMul.lt_of_smul_lt_smul_of_pos h) + lt_of_smul_lt_smul_of_nonneg_left h hc #align lt_of_smul_lt_smul_of_nonneg lt_of_smul_lt_smul_of_nonneg theorem smul_lt_smul_iff_of_pos (hc : 0 < c) : c • a < c • b ↔ a < b := - ⟨fun h => lt_of_smul_lt_smul_of_nonneg h hc.le, fun h => smul_lt_smul_of_pos h hc⟩ + smul_lt_smul_iff_of_pos_left hc #align smul_lt_smul_iff_of_pos smul_lt_smul_iff_of_pos -theorem smul_pos_iff_of_pos (hc : 0 < c) : 0 < c • a ↔ 0 < a := - calc - 0 < c • a ↔ c • (0 : M) < c • a := by rw [smul_zero] - _ ↔ 0 < a := smul_lt_smul_iff_of_pos hc +theorem smul_pos_iff_of_pos (hc : 0 < c) : 0 < c • a ↔ 0 < a := smul_pos_iff_of_pos_left hc #align smul_pos_iff_of_pos smul_pos_iff_of_pos -alias ⟨_, smul_pos⟩ := smul_pos_iff_of_pos #align smul_pos smul_pos -theorem monotone_smul_left (hc : 0 ≤ c) : Monotone (SMul.smul c : M → M) := fun _ _ h => - smul_le_smul_of_nonneg h hc +theorem monotone_smul_left (hc : 0 ≤ c) : Monotone (SMul.smul c : M → M) := + monotone_smul_left_of_nonneg hc #align monotone_smul_left monotone_smul_left -theorem strictMono_smul_left (hc : 0 < c) : StrictMono (SMul.smul c : M → M) := fun _ _ h => - smul_lt_smul_of_pos h hc +theorem strictMono_smul_left (hc : 0 < c) : StrictMono (SMul.smul c : M → M) := + strictMono_smul_left_of_pos hc #align strict_mono_smul_left strictMono_smul_left theorem smul_lowerBounds_subset_lowerBounds_smul (hc : 0 ≤ c) : @@ -178,11 +168,11 @@ instance LinearOrderedSemiring.toOrderedSMul : OrderedSMul R R := #align linear_ordered_semiring.to_ordered_smul LinearOrderedSemiring.toOrderedSMul theorem smul_max (ha : 0 ≤ a) (b₁ b₂ : M) : a • max b₁ b₂ = max (a • b₁) (a • b₂) := - (monotone_smul_left ha : Monotone (_ : M → M)).map_max + smul_max_of_nonneg ha _ _ #align smul_max smul_max theorem smul_min (ha : 0 ≤ a) (b₁ b₂ : M) : a • min b₁ b₂ = min (a • b₁) (a • b₂) := - (monotone_smul_left ha : Monotone (_ : M → M)).map_min + smul_min_of_nonneg ha _ _ #align smul_min smul_min end LinearOrderedSemiring @@ -231,26 +221,19 @@ instance Pi.orderedSMul'' : OrderedSMul 𝕜 (ι → 𝕜) := variable [OrderedSMul 𝕜 M] {s : Set M} {a b : M} {c : 𝕜} theorem smul_le_smul_iff_of_pos (hc : 0 < c) : c • a ≤ c • b ↔ a ≤ b := - ⟨fun h => - inv_smul_smul₀ hc.ne' a ▸ - inv_smul_smul₀ hc.ne' b ▸ smul_le_smul_of_nonneg h (inv_nonneg.2 hc.le), - fun h => smul_le_smul_of_nonneg h hc.le⟩ + smul_le_smul_iff_of_pos_left hc #align smul_le_smul_iff_of_pos smul_le_smul_iff_of_pos -theorem inv_smul_le_iff (h : 0 < c) : c⁻¹ • a ≤ b ↔ a ≤ c • b := by - rw [← smul_le_smul_iff_of_pos h, smul_inv_smul₀ h.ne'] +theorem inv_smul_le_iff (h : 0 < c) : c⁻¹ • a ≤ b ↔ a ≤ c • b := inv_smul_le_iff_of_pos h #align inv_smul_le_iff inv_smul_le_iff -theorem inv_smul_lt_iff (h : 0 < c) : c⁻¹ • a < b ↔ a < c • b := by - rw [← smul_lt_smul_iff_of_pos h, smul_inv_smul₀ h.ne'] +theorem inv_smul_lt_iff (h : 0 < c) : c⁻¹ • a < b ↔ a < c • b := inv_smul_lt_iff_of_pos h #align inv_smul_lt_iff inv_smul_lt_iff -theorem le_inv_smul_iff (h : 0 < c) : a ≤ c⁻¹ • b ↔ c • a ≤ b := by - rw [← smul_le_smul_iff_of_pos h, smul_inv_smul₀ h.ne'] +theorem le_inv_smul_iff (h : 0 < c) : a ≤ c⁻¹ • b ↔ c • a ≤ b := le_inv_smul_iff_of_pos h #align le_inv_smul_iff le_inv_smul_iff -theorem lt_inv_smul_iff (h : 0 < c) : a < c⁻¹ • b ↔ c • a < b := by - rw [← smul_lt_smul_iff_of_pos h, smul_inv_smul₀ h.ne'] +theorem lt_inv_smul_iff (h : 0 < c) : a < c⁻¹ • b ↔ c • a < b := lt_inv_smul_iff_of_pos h #align lt_inv_smul_iff lt_inv_smul_iff variable (M) From 7c98318ddb1418d129b1457cb2eeb7fa18423d79 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Dec 2023 09:33:21 +0000 Subject: [PATCH 065/353] feat(LinearAlgebra/Matrix/PosDef): integer powers preserve `PosSemidef` (#9147) --- Mathlib/LinearAlgebra/Matrix/PosDef.lean | 25 +++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Mathlib/LinearAlgebra/Matrix/PosDef.lean b/Mathlib/LinearAlgebra/Matrix/PosDef.lean index 79e48fbece6b3..a71114b77a639 100644 --- a/Mathlib/LinearAlgebra/Matrix/PosDef.lean +++ b/Mathlib/LinearAlgebra/Matrix/PosDef.lean @@ -87,6 +87,13 @@ theorem submatrix {M : Matrix n n R} (hM : M.PosSemidef) (e : m → n) : conjTranspose_mul_mul_same hM (Matrix.submatrix 1 id e) #align matrix.pos_semidef.submatrix Matrix.PosSemidef.submatrix +theorem transpose {M : Matrix n n R} (hM : M.PosSemidef) : Mᵀ.PosSemidef := by + refine ⟨IsHermitian.transpose hM.1, fun x => ?_⟩ + convert hM.2 (star x) using 1 + rw [mulVec_transpose, Matrix.dotProduct_mulVec, star_star, dotProduct_comm] + +theorem conjTranspose {M : Matrix n n R} (hM : M.PosSemidef) : Mᴴ.PosSemidef := hM.1.symm ▸ hM + protected lemma zero : PosSemidef (0 : Matrix n n R) := ⟨isHermitian_zero, by simp⟩ @@ -103,16 +110,24 @@ protected lemma pow [DecidableEq n] {M : Matrix n n R} (hM : M.PosSemidef) (k : rw [pow_succ', pow_succ] simpa only [hM.isHermitian.eq] using (hM.pow k).mul_mul_conjTranspose_same M +protected lemma inv [DecidableEq n] {M : Matrix n n R} (hM : M.PosSemidef) : M⁻¹.PosSemidef := by + by_cases h : IsUnit M.det + · have := (conjTranspose_mul_mul_same hM M⁻¹).conjTranspose + rwa [mul_nonsing_inv_cancel_right _ _ h, conjTranspose_conjTranspose] at this + · rw [nonsing_inv_apply_not_isUnit _ h] + exact .zero + +protected lemma zpow [DecidableEq n] {M : Matrix n n R} (hM : M.PosSemidef) (z : ℤ) : + (M ^ z).PosSemidef := by + obtain ⟨n, rfl | rfl⟩ := z.eq_nat_or_neg + · simpa using hM.pow n + · simpa using (hM.pow n).inv + /-- The eigenvalues of a positive semi-definite matrix are non-negative -/ lemma eigenvalues_nonneg [DecidableEq n] {A : Matrix n n 𝕜} (hA : Matrix.PosSemidef A) (i : n) : 0 ≤ hA.1.eigenvalues i := (hA.re_dotProduct_nonneg _).trans_eq (hA.1.eigenvalues_eq _).symm -theorem transpose {M : Matrix n n R} (hM : M.PosSemidef) : Mᵀ.PosSemidef := by - refine ⟨IsHermitian.transpose hM.1, fun x => ?_⟩ - convert hM.2 (star x) using 1 - rw [mulVec_transpose, Matrix.dotProduct_mulVec, star_star, dotProduct_comm] - section sqrt variable [DecidableEq n] {A : Matrix n n 𝕜} (hA : PosSemidef A) From fdcf8b6684792c86c4384ee818a0eb168962f9a4 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 19 Dec 2023 09:58:07 +0000 Subject: [PATCH 066/353] feat: Relation between `IsSuccLimit` and `iSup`. (#8842) Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 1 + .../Order/SuccPred/CompleteLinearOrder.lean | 123 ++++++++++++++++++ Mathlib/SetTheory/Cardinal/Basic.lean | 33 ++++- 3 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 Mathlib/Order/SuccPred/CompleteLinearOrder.lean diff --git a/Mathlib.lean b/Mathlib.lean index c2ae7d7b47ca2..bfb455393d050 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2926,6 +2926,7 @@ import Mathlib.Order.RelSeries import Mathlib.Order.SemiconjSup import Mathlib.Order.Sublattice import Mathlib.Order.SuccPred.Basic +import Mathlib.Order.SuccPred.CompleteLinearOrder import Mathlib.Order.SuccPred.IntervalSucc import Mathlib.Order.SuccPred.Limit import Mathlib.Order.SuccPred.LinearLocallyFinite diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean new file mode 100644 index 0000000000000..3496364a6b58f --- /dev/null +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -0,0 +1,123 @@ +/- +Copyright (c) 2023 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.Order.SuccPred.Limit +import Mathlib.Order.ConditionallyCompleteLattice.Basic + +/-! + +# Relation between `IsSuccLimit` and `iSup` in (conditionally) complete linear orders. + +-/ + +open Order + +variable {ι α : Type*} + +section ConditionallyCompleteLinearOrder +variable [ConditionallyCompleteLinearOrder α] [Nonempty ι] {f : ι → α} {s : Set α} {x : α} + +lemma csSup_mem_of_not_isSuccLimit + (hne : s.Nonempty) (hbdd : BddAbove s) (hlim : ¬ IsSuccLimit (sSup s)) : + sSup s ∈ s := by + obtain ⟨y, hy⟩ := not_forall_not.mp hlim + obtain ⟨i, his, hi⟩ := exists_lt_of_lt_csSup hne hy.lt + exact eq_of_le_of_not_lt (le_csSup hbdd his) (hy.2 hi) ▸ his + +lemma csInf_mem_of_not_isPredLimit + (hne : s.Nonempty) (hbdd : BddBelow s) (hlim : ¬ IsPredLimit (sInf s)) : + sInf s ∈ s := by + obtain ⟨y, hy⟩ := not_forall_not.mp hlim + obtain ⟨i, his, hi⟩ := exists_lt_of_csInf_lt hne hy.lt + exact eq_of_le_of_not_lt (csInf_le hbdd his) (hy.2 · hi) ▸ his + +lemma exists_eq_ciSup_of_not_isSuccLimit + (hf : BddAbove (Set.range f)) (hf' : ¬ IsSuccLimit (⨆ i, f i)) : + ∃ i, f i = ⨆ i, f i := + csSup_mem_of_not_isSuccLimit (Set.range_nonempty f) hf hf' + +lemma exists_eq_ciInf_of_not_isPredLimit + (hf : BddBelow (Set.range f)) (hf' : ¬ IsPredLimit (⨅ i, f i)) : + ∃ i, f i = ⨅ i, f i := + csInf_mem_of_not_isPredLimit (Set.range_nonempty f) hf hf' + +lemma IsLUB.mem_of_nonempty_of_not_isSuccLimit + (hs : IsLUB s x) (hne : s.Nonempty) (hx : ¬ IsSuccLimit x) : x ∈ s := + hs.csSup_eq hne ▸ csSup_mem_of_not_isSuccLimit hne hs.bddAbove (hs.csSup_eq hne ▸ hx) + +lemma IsGLB.mem_of_nonempty_of_not_isPredLimit + (hs : IsGLB s x) (hne : s.Nonempty) (hx : ¬ IsPredLimit x) : x ∈ s := + hs.csInf_eq hne ▸ csInf_mem_of_not_isPredLimit hne hs.bddBelow (hs.csInf_eq hne ▸ hx) + +lemma IsLUB.exists_of_nonempty_of_not_isSuccLimit + (hf : IsLUB (Set.range f) x) (hx : ¬ IsSuccLimit x) : + ∃ i, f i = x := hf.mem_of_nonempty_of_not_isSuccLimit (Set.range_nonempty f) hx + +lemma IsGLB.exists_of_nonempty_of_not_isPredLimit + (hf : IsGLB (Set.range f) x) (hx : ¬ IsPredLimit x) : + ∃ i, f i = x := hf.mem_of_nonempty_of_not_isPredLimit (Set.range_nonempty f) hx + +end ConditionallyCompleteLinearOrder + +section ConditionallyCompleteLinearOrderBot +variable [ConditionallyCompleteLinearOrderBot α] {f : ι → α} {s : Set α} {x : α} + +/-- See `csSup_mem_of_not_isSuccLimit` for the `ConditionallyCompleteLinearOrder` version. -/ +lemma csSup_mem_of_not_isSuccLimit' + (hbdd : BddAbove s) (hlim : ¬ IsSuccLimit (sSup s)) : + sSup s ∈ s := by + obtain (rfl|hs) := s.eq_empty_or_nonempty + · simp [isSuccLimit_bot] at hlim + · exact csSup_mem_of_not_isSuccLimit hs hbdd hlim + +/-- See `exists_eq_ciSup_of_not_isSuccLimit` for the +`ConditionallyCompleteLinearOrder` version. -/ +lemma exists_eq_ciSup_of_not_isSuccLimit' + (hf : BddAbove (Set.range f)) (hf' : ¬ IsSuccLimit (⨆ i, f i)) : + ∃ i, f i = ⨆ i, f i := + csSup_mem_of_not_isSuccLimit' hf hf' + +lemma IsLUB.mem_of_not_isSuccLimit (hs : IsLUB s x) (hx : ¬ IsSuccLimit x) : + x ∈ s := by + obtain (rfl|hs') := s.eq_empty_or_nonempty + · simp [show x = ⊥ by simpa using hs, isSuccLimit_bot] at hx + · exact hs.mem_of_nonempty_of_not_isSuccLimit hs' hx + +lemma IsLUB.exists_of_not_isSuccLimit (hf : IsLUB (Set.range f) x) (hx : ¬ IsSuccLimit x) : + ∃ i, f i = x := hf.mem_of_not_isSuccLimit hx + +end ConditionallyCompleteLinearOrderBot + +section CompleteLinearOrder +variable [CompleteLinearOrder α] {s : Set α} {f : ι → α} {x : α} + +lemma sSup_mem_of_not_isSuccLimit (hlim : ¬ IsSuccLimit (sSup s)) : + sSup s ∈ s := by + obtain ⟨y, hy⟩ := not_forall_not.mp hlim + obtain ⟨i, his, hi⟩ := lt_sSup_iff.mp hy.lt + exact eq_of_le_of_not_lt (le_sSup his) (hy.2 hi) ▸ his + +lemma sInf_mem_of_not_isPredLimit (hlim : ¬ IsPredLimit (sInf s)) : + sInf s ∈ s := by + obtain ⟨y, hy⟩ := not_forall_not.mp hlim + obtain ⟨i, his, hi⟩ := sInf_lt_iff.mp hy.lt + exact eq_of_le_of_not_lt (sInf_le his) (hy.2 · hi) ▸ his + +lemma exists_eq_iSup_of_not_isSuccLimit (hf : ¬ IsSuccLimit (⨆ i, f i)) : + ∃ i, f i = ⨆ i, f i := + sSup_mem_of_not_isSuccLimit hf + +lemma exists_eq_iInf_of_not_isPredLimit (hf : ¬ IsPredLimit (⨅ i, f i)) : + ∃ i, f i = ⨅ i, f i := + sInf_mem_of_not_isPredLimit hf + +lemma IsGLB.mem_of_not_isPredLimit (hs : IsGLB s x) (hx : ¬ IsPredLimit x) : + x ∈ s := + hs.sInf_eq ▸ sInf_mem_of_not_isPredLimit (hs.sInf_eq ▸ hx) + +lemma IsGLB.exists_of_not_isPredLimit (hf : IsGLB (Set.range f) x) (hx : ¬ IsPredLimit x) : + ∃ i, f i = x := hf.mem_of_not_isPredLimit hx + +end CompleteLinearOrder diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index e5295e1cb16d4..8c3e3617af161 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -10,7 +10,7 @@ import Mathlib.Data.Nat.PartENat import Mathlib.Data.Set.Countable import Mathlib.Logic.Small.Basic import Mathlib.Order.ConditionallyCompleteLattice.Basic -import Mathlib.Order.SuccPred.Limit +import Mathlib.Order.SuccPred.CompleteLinearOrder import Mathlib.SetTheory.Cardinal.SchroederBernstein import Mathlib.Tactic.Positivity import Mathlib.Tactic.PPWithUniv @@ -1012,6 +1012,22 @@ protected theorem iSup_of_empty {ι} (f : ι → Cardinal) [IsEmpty ι] : iSup f ciSup_of_empty f #align cardinal.supr_of_empty Cardinal.iSup_of_empty +lemma exists_eq_of_iSup_eq_of_not_isSuccLimit + {ι : Type u} (f : ι → Cardinal.{max u v}) (ω : Cardinal.{max u v}) + (hω : ¬ Order.IsSuccLimit ω) + (h : ⨆ i : ι, f i = ω) : ∃ i, f i = ω := + IsLUB.exists_of_not_isSuccLimit (h ▸ isLUB_csSup' (bddAbove_range.{u, v} f)) hω + +lemma exists_eq_of_iSup_eq_of_not_isLimit + {ι : Type u} [hι : Nonempty ι] (f : ι → Cardinal.{max u v}) (ω : Cardinal.{max u v}) + (hω : ¬ ω.IsLimit) + (h : ⨆ i : ι, f i = ω) : ∃ i, f i = ω := by + refine (not_and_or.mp hω).elim (fun e ↦ ⟨hι.some, ?_⟩) + (Cardinal.exists_eq_of_iSup_eq_of_not_isSuccLimit.{u, v} f ω · h) + cases not_not.mp e + rw [← le_zero_iff] at h ⊢ + exact (le_ciSup (Cardinal.bddAbove_range.{u, v} f) _).trans h + -- Portin note: simpNF is not happy with universe levels. @[simp, nolint simpNF] theorem lift_mk_shrink (α : Type u) [Small.{v} α] : @@ -1450,13 +1466,18 @@ theorem isLimit_aleph0 : IsLimit ℵ₀ := ⟨aleph0_ne_zero, isSuccLimit_aleph0⟩ #align cardinal.is_limit_aleph_0 Cardinal.isLimit_aleph0 +lemma not_isLimit_natCast : (n : ℕ) → ¬ IsLimit (n : Cardinal.{u}) + | 0, e => e.1 rfl + | Nat.succ n, e => Order.not_isSuccLimit_succ _ (nat_succ n ▸ e.2) + theorem IsLimit.aleph0_le {c : Cardinal} (h : IsLimit c) : ℵ₀ ≤ c := by by_contra! h' - rcases lt_aleph0.1 h' with ⟨_ | n, rfl⟩ - · exact h.ne_zero.irrefl - · rw [nat_succ] at h - exact not_isSuccLimit_succ _ h.isSuccLimit -#align cardinal.is_limit.aleph_0_le Cardinal.IsLimit.aleph0_le + rcases lt_aleph0.1 h' with ⟨n, rfl⟩ + exact not_isLimit_natCast n h + +lemma exists_eq_natCast_of_iSup_eq {ι : Type u} [Nonempty ι] (f : ι → Cardinal.{max u v}) + (n : ℕ) (h : ⨆ i, f i = n) : ∃ i, f i = n := + exists_eq_of_iSup_eq_of_not_isLimit.{u, v} f _ (not_isLimit_natCast n) h @[simp] theorem range_natCast : range ((↑) : ℕ → Cardinal) = Iio ℵ₀ := From cdd553fb7a16e843664f90a549965b2c20bc8539 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Tue, 19 Dec 2023 10:02:55 +0000 Subject: [PATCH 067/353] chore: bump to nightly-2023-12-19 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 05e3a626b95b7..2dfbd8295af30 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-18 +leanprover/lean4:nightly-2023-12-19 From 7d208e649ff0dceb1b6e2764e4b931947652e956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Dec 2023 12:00:10 +0000 Subject: [PATCH 068/353] feat: Preimage of pointwise multiplication (#8956) From PFR Co-authored-by: Patrick Massot --- Mathlib/Data/Finset/Pointwise.lean | 44 ++++++++++++++++ Mathlib/Data/Nat/Totient.lean | 2 +- Mathlib/Data/Set/Finite.lean | 34 +++++++++---- Mathlib/Data/Set/Pointwise/Basic.lean | 36 ++++++++++++- Mathlib/Data/Set/Pointwise/Finite.lean | 5 ++ Mathlib/NumberTheory/MaricaSchoenheim.lean | 2 +- Mathlib/SetTheory/Cardinal/Finite.lean | 59 ++++++++++++++++++++-- 7 files changed, 164 insertions(+), 18 deletions(-) diff --git a/Mathlib/Data/Finset/Pointwise.lean b/Mathlib/Data/Finset/Pointwise.lean index 9d3ab9242823f..7feea71720368 100644 --- a/Mathlib/Data/Finset/Pointwise.lean +++ b/Mathlib/Data/Finset/Pointwise.lean @@ -8,6 +8,7 @@ import Mathlib.Data.Finset.Preimage import Mathlib.Data.Set.Pointwise.Finite import Mathlib.Data.Set.Pointwise.SMul import Mathlib.Data.Set.Pointwise.ListOfFn +import Mathlib.SetTheory.Cardinal.Finite #align_import data.finset.pointwise from "leanprover-community/mathlib"@"eba7871095e834365616b5e43c8c7bb0b37058d0" @@ -2309,4 +2310,47 @@ theorem Finite.toFinset_vsub (hs : s.Finite) (ht : t.Finite) (hf := hs.vsub ht) end VSub +section MulAction +variable [Group α] [MulAction α β] + +@[to_additive (attr := simp)] +lemma card_smul_set (a : α) (s : Set β) : Nat.card ↥(a • s) = Nat.card s := + Nat.card_image_of_injective (MulAction.injective a) _ + +end MulAction + +section IsCancelMul +variable [Mul α] [IsCancelMul α] {s t : Set α} + +@[to_additive] +lemma card_mul_le : Nat.card (s * t) ≤ Nat.card s * Nat.card t := by + classical + obtain h | h := (s * t).infinite_or_finite + · simp [Set.Infinite.card_eq_zero h] + obtain ⟨hs, ht⟩ | rfl | rfl := finite_mul.1 h + · lift s to Finset α using hs + lift t to Finset α using ht + rw [← Finset.coe_mul] + simpa [-Finset.coe_mul] using Finset.card_mul_le + all_goals simp + +end IsCancelMul + +section InvolutiveInv +variable [InvolutiveInv α] {s t : Set α} + +@[to_additive (attr := simp)] +lemma card_inv (s : Set α) : Nat.card ↥(s⁻¹) = Nat.card s := by + rw [← image_inv, Nat.card_image_of_injective inv_injective] + +end InvolutiveInv + +section Group +variable [Group α] {s t : Set α} + +@[to_additive] +lemma card_div_le : Nat.card (s / t) ≤ Nat.card s * Nat.card t := by + rw [div_eq_mul_inv, ← card_inv t]; exact card_mul_le + +end Group end Set diff --git a/Mathlib/Data/Nat/Totient.lean b/Mathlib/Data/Nat/Totient.lean index 76e663eda5af8..3cee8ceb16f2d 100644 --- a/Mathlib/Data/Nat/Totient.lean +++ b/Mathlib/Data/Nat/Totient.lean @@ -213,7 +213,7 @@ theorem totient_prime_pow_succ {p : ℕ} (hp : p.Prime) (n : ℕ) : φ (p ^ (n + rintro b ⟨h, rfl⟩ rw [pow_succ] exact (mul_lt_mul_right hp.pos).2 h - rw [card_sdiff h2, card_image_of_injOn (h1.injOn _), card_range, card_range, ← + rw [card_sdiff h2, Finset.card_image_of_injective _ h1, card_range, card_range, ← one_mul (p ^ n), pow_succ', ← tsub_mul, one_mul, mul_comm] #align nat.totient_prime_pow_succ Nat.totient_prime_pow_succ diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index db3d3aaf1aaf2..9484aa9de1cf5 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -785,6 +785,10 @@ theorem Finite.subset {s : Set α} (hs : s.Finite) {t : Set α} (ht : t ⊆ s) : apply toFinite #align set.finite.subset Set.Finite.subset +protected lemma Infinite.mono {s t : Set α} (h : s ⊆ t) : s.Infinite → t.Infinite := + mt fun ht ↦ ht.subset h +#align set.infinite.mono Set.Infinite.mono + theorem Finite.diff {s : Set α} (hs : s.Finite) (t : Set α) : (s \ t).Finite := by cases hs apply toFinite @@ -905,26 +909,34 @@ theorem Finite.of_finite_image {s : Set α} {f : α → β} (h : (f '' s).Finite Subtype.eq <| hi a.2 b.2 <| Subtype.ext_iff_val.1 eq⟩ #align set.finite.of_finite_image Set.Finite.of_finite_image -theorem finite_of_finite_preimage {f : α → β} {s : Set β} (h : (f ⁻¹' s).Finite) - (hs : s ⊆ range f) : s.Finite := by +section preimage +variable {f : α → β} {s : Set β} + +theorem finite_of_finite_preimage (h : (f ⁻¹' s).Finite) (hs : s ⊆ range f) : s.Finite := by rw [← image_preimage_eq_of_subset hs] exact Finite.image f h #align set.finite_of_finite_preimage Set.finite_of_finite_preimage -theorem Finite.of_preimage {f : α → β} {s : Set β} (h : (f ⁻¹' s).Finite) (hf : Surjective f) : - s.Finite := +theorem Finite.of_preimage (h : (f ⁻¹' s).Finite) (hf : Surjective f) : s.Finite := hf.image_preimage s ▸ h.image _ #align set.finite.of_preimage Set.Finite.of_preimage -theorem Finite.preimage {s : Set β} {f : α → β} (I : Set.InjOn f (f ⁻¹' s)) (h : s.Finite) : - (f ⁻¹' s).Finite := +theorem Finite.preimage (I : Set.InjOn f (f ⁻¹' s)) (h : s.Finite) : (f ⁻¹' s).Finite := (h.subset (image_preimage_subset f s)).of_finite_image I #align set.finite.preimage Set.Finite.preimage +protected lemma Infinite.preimage (hs : s.Infinite) (hf : s ⊆ range f) : (f ⁻¹' s).Infinite := + fun h ↦ hs $ finite_of_finite_preimage h hf + +lemma Infinite.preimage' (hs : (s ∩ range f).Infinite) : (f ⁻¹' s).Infinite := + (hs.preimage $ inter_subset_right _ _).mono $ preimage_mono $ inter_subset_left _ _ + theorem Finite.preimage_embedding {s : Set β} (f : α ↪ β) (h : s.Finite) : (f ⁻¹' s).Finite := h.preimage fun _ _ _ _ h' => f.injective h' #align set.finite.preimage_embedding Set.Finite.preimage_embedding +end preimage + theorem finite_lt_nat (n : ℕ) : Set.Finite { i | i < n } := toFinite _ #align set.finite_lt_nat Set.finite_lt_nat @@ -1360,10 +1372,6 @@ theorem Finite.infinite_compl [Infinite α] {s : Set α} (hs : s.Finite) : sᶜ. Set.infinite_univ (by simpa using hs.union h) #align set.finite.infinite_compl Set.Finite.infinite_compl -protected theorem Infinite.mono {s t : Set α} (h : s ⊆ t) : s.Infinite → t.Infinite := - mt fun ht => ht.subset h -#align set.infinite.mono Set.Infinite.mono - theorem Infinite.diff {s t : Set α} (hs : s.Infinite) (ht : t.Finite) : (s \ t).Infinite := fun h => hs <| h.of_diff ht #align set.infinite.diff Set.Infinite.diff @@ -1412,6 +1420,12 @@ theorem infinite_image2 (hfs : ∀ b ∈ t, InjOn (fun a => f a b) s) (hft : ∀ · exact ht.image2_right ha (hft _ ha) #align set.infinite_image2 Set.infinite_image2 +lemma finite_image2 (hfs : ∀ b ∈ t, InjOn (f · b) s) (hft : ∀ a ∈ s, InjOn (f a) t) : + (image2 f s t).Finite ↔ s.Finite ∧ t.Finite ∨ s = ∅ ∨ t = ∅ := by + rw [← not_infinite, infinite_image2 hfs hft] + simp [not_or, -not_and, not_and_or, not_nonempty_iff_eq_empty] + aesop + end Image2 theorem infinite_of_injOn_mapsTo {s : Set α} {t : Set β} {f : α → β} (hi : InjOn f s) diff --git a/Mathlib/Data/Set/Pointwise/Basic.lean b/Mathlib/Data/Set/Pointwise/Basic.lean index 7b88c72a59cad..207ccd9f79f16 100644 --- a/Mathlib/Data/Set/Pointwise/Basic.lean +++ b/Mathlib/Data/Set/Pointwise/Basic.lean @@ -344,7 +344,6 @@ theorem mul_mem_mul : a ∈ s → b ∈ t → a * b ∈ s * t := #align set.mul_mem_mul Set.mul_mem_mul #align set.add_mem_add Set.add_mem_add -/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/ @[to_additive add_image_prod] theorem image_mul_prod : (fun x : α × α => x.fst * x.snd) '' s ×ˢ t = s * t := image_prod _ @@ -611,7 +610,6 @@ theorem div_mem_div : a ∈ s → b ∈ t → a / b ∈ s / t := #align set.div_mem_div Set.div_mem_div #align set.sub_mem_sub Set.sub_mem_sub -/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/ @[to_additive sub_image_prod] theorem image_div_prod : (fun x : α × α => x.fst / x.snd) '' s ×ˢ t = s / t := image_prod _ @@ -1297,6 +1295,13 @@ theorem image_mul : m '' (s * t) = m '' s * m '' t := #align set.image_mul Set.image_mul #align set.image_add Set.image_add +@[to_additive] +lemma mul_subset_range {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) : s * t ⊆ range m := by + rintro _ ⟨a, b, ha, hb, rfl⟩; + obtain ⟨a, rfl⟩ := hs ha + obtain ⟨b, rfl⟩ := ht hb + exact ⟨a * b, map_mul _ _ _⟩ + @[to_additive] theorem preimage_mul_preimage_subset {s t : Set β} : m ⁻¹' s * m ⁻¹' t ⊆ m ⁻¹' (s * t) := by rintro _ ⟨_, _, _, _, rfl⟩ @@ -1304,6 +1309,16 @@ theorem preimage_mul_preimage_subset {s t : Set β} : m ⁻¹' s * m ⁻¹' t #align set.preimage_mul_preimage_subset Set.preimage_mul_preimage_subset #align set.preimage_add_preimage_subset Set.preimage_add_preimage_subset +@[to_additive] +lemma preimage_mul (hm : Injective m) {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) : + m ⁻¹' (s * t) = m ⁻¹' s * m ⁻¹' t := by + refine subset_antisymm ?_ (preimage_mul_preimage_subset m) + rintro a ⟨b, c, hb, hc, ha⟩ + obtain ⟨b, rfl⟩ := hs hb + obtain ⟨c, rfl⟩ := ht hc + simp only [← map_mul, hm.eq_iff] at ha + exact ⟨b, c, hb, hc, ha⟩ + end Mul section Group @@ -1316,6 +1331,13 @@ theorem image_div : m '' (s / t) = m '' s / m '' t := #align set.image_div Set.image_div #align set.image_sub Set.image_sub +@[to_additive] +lemma div_subset_range {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) : s / t ⊆ range m := by + rintro _ ⟨a, b, ha, hb, rfl⟩; + obtain ⟨a, rfl⟩ := hs ha + obtain ⟨b, rfl⟩ := ht hb + exact ⟨a / b, map_div _ _ _⟩ + @[to_additive] theorem preimage_div_preimage_subset {s t : Set β} : m ⁻¹' s / m ⁻¹' t ⊆ m ⁻¹' (s / t) := by rintro _ ⟨_, _, _, _, rfl⟩ @@ -1323,6 +1345,16 @@ theorem preimage_div_preimage_subset {s t : Set β} : m ⁻¹' s / m ⁻¹' t #align set.preimage_div_preimage_subset Set.preimage_div_preimage_subset #align set.preimage_sub_preimage_subset Set.preimage_sub_preimage_subset +@[to_additive] +lemma preimage_div (hm : Injective m) {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) : + m ⁻¹' (s / t) = m ⁻¹' s / m ⁻¹' t := by + refine subset_antisymm ?_ (preimage_div_preimage_subset m) + rintro a ⟨b, c, hb, hc, ha⟩ + obtain ⟨b, rfl⟩ := hs hb + obtain ⟨c, rfl⟩ := ht hc + simp only [← map_div, hm.eq_iff] at ha + exact ⟨b, c, hb, hc, ha⟩ + end Group @[to_additive] diff --git a/Mathlib/Data/Set/Pointwise/Finite.lean b/Mathlib/Data/Set/Pointwise/Finite.lean index b0d9811cfa2bd..f65d3b16657bb 100644 --- a/Mathlib/Data/Set/Pointwise/Finite.lean +++ b/Mathlib/Data/Set/Pointwise/Finite.lean @@ -135,6 +135,11 @@ theorem infinite_mul : (s * t).Infinite ↔ s.Infinite ∧ t.Nonempty ∨ t.Infi #align set.infinite_mul Set.infinite_mul #align set.infinite_add Set.infinite_add +@[to_additive] +lemma finite_mul : (s * t).Finite ↔ s.Finite ∧ t.Finite ∨ s = ∅ ∨ t = ∅ := + finite_image2 (fun _ _ ↦ (mul_left_injective _).injOn _) + fun _ _ ↦ (mul_right_injective _).injOn _ + end Cancel section Group diff --git a/Mathlib/NumberTheory/MaricaSchoenheim.lean b/Mathlib/NumberTheory/MaricaSchoenheim.lean index 805b31d94ae71..a9d9220e50076 100644 --- a/Mathlib/NumberTheory/MaricaSchoenheim.lean +++ b/Mathlib/NumberTheory/MaricaSchoenheim.lean @@ -45,7 +45,7 @@ lemma grahamConjecture_of_squarefree {n : ℕ} (f : ℕ → ℕ) (hf' : ∀ k < _ ≤ (Ioo 0 n).card := card_le_card_of_inj_on (fun s ↦ ∏ p in s, p) ?_ ?_ _ = n - 1 := by rw [card_Ioo, tsub_zero] _ < n := tsub_lt_self hn.bot_lt zero_lt_one - · rw [card_image_of_injOn, card_Iio] + · rw [Finset.card_image_of_injOn, card_Iio] simpa using prod_primeFactors_invOn_squarefree.2.injOn.comp hf.injOn hf' · simp only [forall_mem_diffs, forall_image, mem_Ioo, mem_Iio] rintro i hi j hj diff --git a/Mathlib/SetTheory/Cardinal/Finite.lean b/Mathlib/SetTheory/Cardinal/Finite.lean index b3792c298db08..9c7c41fae7c48 100644 --- a/Mathlib/SetTheory/Cardinal/Finite.lean +++ b/Mathlib/SetTheory/Cardinal/Finite.lean @@ -42,6 +42,18 @@ theorem card_eq_fintype_card [Fintype α] : Nat.card α = Fintype.card α := mk_toNat_eq_card #align nat.card_eq_fintype_card Nat.card_eq_fintype_card +lemma card_eq_finsetCard (s : Finset α) : Nat.card s = s.card := by + simp only [Nat.card_eq_fintype_card, Fintype.card_coe] + +lemma card_eq_card_toFinset (s : Set α) [Fintype s] : Nat.card s = s.toFinset.card := by + simp only [← Nat.card_eq_finsetCard, s.mem_toFinset] + +lemma card_eq_card_finite_toFinset {s : Set α} (hs : s.Finite) : Nat.card s = hs.toFinset.card := by + simp only [← Nat.card_eq_finsetCard, hs.mem_toFinset] + +@[simp] theorem card_of_isEmpty [IsEmpty α] : Nat.card α = 0 := by simp [Nat.card] +#align nat.card_of_is_empty Nat.card_of_isEmpty + @[simp] lemma card_eq_zero_of_infinite [Infinite α] : Nat.card α = 0 := mk_toNat_of_infinite #align nat.card_eq_zero_of_infinite Nat.card_eq_zero_of_infinite @@ -83,9 +95,41 @@ theorem card_eq_of_equiv_fin {α : Type*} {n : ℕ} (f : α ≃ Fin n) : Nat.car simpa only [card_eq_fintype_card, Fintype.card_fin] using card_congr f #align nat.card_eq_of_equiv_fin Nat.card_eq_of_equiv_fin -lemma card_mono {s t : Set α} (ht : t.Finite) (h : s ⊆ t) : Nat.card s ≤ Nat.card t := +section Set +open Set +variable {s t : Set α} + +lemma card_mono (ht : t.Finite) (h : s ⊆ t) : Nat.card s ≤ Nat.card t := toNat_le_of_le_of_lt_aleph0 ht.lt_aleph0 <| mk_le_mk_of_subset h +lemma card_image_le (hs : s.Finite) : Nat.card (f '' s) ≤ Nat.card s := + have := hs.to_subtype; card_le_card_of_surjective (imageFactorization f s) surjective_onto_image + +lemma card_image_of_injOn (hf : s.InjOn f) : Nat.card (f '' s) = Nat.card s := by + classical + obtain hs | hs := s.finite_or_infinite + · have := hs.fintype + have := fintypeImage s f + simp_rw [Nat.card_eq_fintype_card, Set.card_image_of_inj_on hf] + · have := hs.to_subtype + have := (hs.image hf).to_subtype + simp [Nat.card_eq_zero_of_infinite] + +lemma card_image_of_injective (hf : Injective f) (s : Set α) : + Nat.card (f '' s) = Nat.card s := card_image_of_injOn $ hf.injOn _ + +lemma card_image_equiv (e : α ≃ β) : Nat.card (e '' s) = Nat.card s := + Nat.card_congr (e.image s).symm + +lemma card_preimage_of_injOn {s : Set β} (hf : (f ⁻¹' s).InjOn f) (hsf : s ⊆ range f) : + Nat.card (f ⁻¹' s) = Nat.card s := by + rw [← Nat.card_image_of_injOn hf, image_preimage_eq_iff.2 hsf] + +lemma card_preimage_of_injective {s : Set β} (hf : Injective f) (hsf : s ⊆ range f) : + Nat.card (f ⁻¹' s) = Nat.card s := card_preimage_of_injOn (hf.injOn _) hsf + +end Set + /-- If the cardinality is positive, that means it is a finite type, so there is an equivalence between `α` and `Fin (Nat.card α)`. See also `Finite.equivFin`. -/ def equivFinOfCardPos {α : Type*} (h : Nat.card α ≠ 0) : α ≃ Fin (Nat.card α) := by @@ -116,9 +160,6 @@ theorem card_eq_two_iff' (x : α) : Nat.card α = 2 ↔ ∃! y, y ≠ x := toNat_eq_ofNat.trans (mk_eq_two_iff' x) #align nat.card_eq_two_iff' Nat.card_eq_two_iff' -@[simp] theorem card_of_isEmpty [IsEmpty α] : Nat.card α = 0 := by simp [Nat.card] -#align nat.card_of_is_empty Nat.card_of_isEmpty - @[simp] theorem card_sum [Finite α] [Finite β] : Nat.card (α ⊕ β) = Nat.card α + Nat.card β := by have := Fintype.ofFinite α @@ -158,6 +199,16 @@ theorem card_zmod (n : ℕ) : Nat.card (ZMod n) = n := by end Nat +namespace Set + +lemma card_singleton_prod (a : α) (t : Set β) : Nat.card ({a} ×ˢ t) = Nat.card t := by + rw [singleton_prod, Nat.card_image_of_injective (Prod.mk.inj_left a)] + +lemma card_prod_singleton (s : Set α) (b : β) : Nat.card (s ×ˢ {b}) = Nat.card s := by + rw [prod_singleton, Nat.card_image_of_injective (Prod.mk.inj_right b)] + +end Set + namespace PartENat /-- `PartENat.card α` is the cardinality of `α` as an extended natural number. From 1150c07e0f052641602800a07122d7c6cb6f964d Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 19 Dec 2023 12:55:30 +0000 Subject: [PATCH 069/353] feat: interior and boundary of a manifold (#8624) We use the standard definition, with respect to the preferred charts at each point. Open-ness of the interior is non-trivial, hence left to a future PR: - for instance, in finite dimensions this requires e.g. knowing the homology of spheres, which mathlib doesn't yet have. Co-authored-by: Winston Yin --- Mathlib.lean | 1 + .../Geometry/Manifold/InteriorBoundary.lean | 127 ++++++++++++++++++ .../Manifold/SmoothManifoldWithCorners.lean | 17 +++ Mathlib/Topology/Basic.lean | 5 + 4 files changed, 150 insertions(+) create mode 100644 Mathlib/Geometry/Manifold/InteriorBoundary.lean diff --git a/Mathlib.lean b/Mathlib.lean index bfb455393d050..cf5613827a4b8 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2118,6 +2118,7 @@ import Mathlib.Geometry.Manifold.Diffeomorph import Mathlib.Geometry.Manifold.Instances.Real import Mathlib.Geometry.Manifold.Instances.Sphere import Mathlib.Geometry.Manifold.Instances.UnitsOfNormedAlgebra +import Mathlib.Geometry.Manifold.InteriorBoundary import Mathlib.Geometry.Manifold.LocalInvariantProperties import Mathlib.Geometry.Manifold.MFDeriv import Mathlib.Geometry.Manifold.Metrizable diff --git a/Mathlib/Geometry/Manifold/InteriorBoundary.lean b/Mathlib/Geometry/Manifold/InteriorBoundary.lean new file mode 100644 index 0000000000000..e8f1d22de97be --- /dev/null +++ b/Mathlib/Geometry/Manifold/InteriorBoundary.lean @@ -0,0 +1,127 @@ +/- +Copyright (c) 2023 Michael Rothgang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Michael Rothgang +-/ + +import Mathlib.Geometry.Manifold.SmoothManifoldWithCorners + +/-! +# Interior and boundary of a manifold +Define the interior and boundary of a manifold. + +## Main definitions +- **IsInteriorPoint x**: `p ∈ M` is an interior point if, for `φ` being the preferred chart at `x`, + `φ x` is an interior point of `φ.target`. +- **IsBoundaryPoint x**: `p ∈ M` is a boundary point if, `(extChartAt I x) x ∈ frontier (range I)`. +- **interior I M** is the **interior** of `M`, the set of its interior points. +- **boundary I M** is the **boundary** of `M`, the set of its boundary points. + +## Main results +- `univ_eq_interior_union_boundary`: `M` is the union of its interior and boundary +- `interior_boundary_disjoint`: interior and boundary of `M` are disjoint +- if `M` is boundaryless, every point is an interior point + +## Tags +manifold, interior, boundary + +## TODO +- `x` is an interior point iff *any* chart around `x` maps it to `interior (range I)`; +similarly for the boundary. +- the interior of `M` is open, hence the boundary is closed (and nowhere dense) + In finite dimensions, this requires e.g. the homology of spheres. +- the interior of `M` is a smooth manifold without boundary +- `boundary M` is a smooth submanifold (possibly with boundary and corners): +follows from the corresponding statement for the model with corners `I`; +this requires a definition of submanifolds +- if `M` is finite-dimensional, its boundary has measure zero + +-/ + +open Set + +-- Let `M` be a manifold with corners over the pair `(E, H)`. +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + {M : Type*} [TopologicalSpace M] [ChartedSpace H M] + +namespace ModelWithCorners +/-- `p ∈ M` is an interior point of a manifold `M` iff its image in the extended chart +lies in the interior of the model space. -/ +def IsInteriorPoint (x : M) := extChartAt I x x ∈ interior (range I) + +/-- `p ∈ M` is a boundary point of a manifold `M` iff its image in the extended chart +lies on the boundary of the model space. -/ +def IsBoundaryPoint (x : M) := extChartAt I x x ∈ frontier (range I) + +variable (M) in +/-- The **interior** of a manifold `M` is the set of its interior points. -/ +protected def interior : Set M := { x : M | I.IsInteriorPoint x } + +lemma isInteriorPoint_iff {x : M} : + I.IsInteriorPoint x ↔ extChartAt I x x ∈ interior (extChartAt I x).target := + ⟨fun h ↦ (chartAt H x).mem_interior_extend_target _ (mem_chart_target H x) h, + fun h ↦ PartialHomeomorph.interior_extend_target_subset_interior_range _ _ h⟩ + +variable (M) in +/-- The **boundary** of a manifold `M` is the set of its boundary points. -/ +protected def boundary : Set M := { x : M | I.IsBoundaryPoint x } + +lemma isBoundaryPoint_iff {x : M} : I.IsBoundaryPoint x ↔ extChartAt I x x ∈ frontier (range I) := + Iff.rfl + +/-- Every point is either an interior or a boundary point. -/ +lemma isInteriorPoint_or_isBoundaryPoint (x : M) : I.IsInteriorPoint x ∨ I.IsBoundaryPoint x := by + by_cases h : extChartAt I x x ∈ interior (range I) + · exact Or.inl h + · right -- Otherwise, we have a boundary point. + rw [I.isBoundaryPoint_iff, ← closure_diff_interior, I.closed_range.closure_eq] + exact ⟨mem_range_self _, h⟩ + +/-- A manifold decomposes into interior and boundary. -/ +lemma interior_union_boundary_eq_univ : (I.interior M) ∪ (I.boundary M) = (univ : Set M) := + le_antisymm (fun _ _ ↦ trivial) (fun x _ ↦ I.isInteriorPoint_or_isBoundaryPoint x) + +/-- The interior and boundary of a manifold `M` are disjoint. -/ +lemma disjoint_interior_boundary : Disjoint (I.interior M) (I.boundary M) := by + by_contra h + -- Choose some x in the intersection of interior and boundary. + choose x hx using not_disjoint_iff.mp h + rcases hx with ⟨h1, h2⟩ + show (extChartAt I x) x ∈ (∅ : Set E) + rw [← disjoint_iff_inter_eq_empty.mp (disjoint_interior_frontier (s := range I))] + exact ⟨h1, h2⟩ + +/-- The boundary is the complement of the interior. -/ +lemma boundary_eq_complement_interior : I.boundary M = (I.interior M)ᶜ := by + apply (compl_unique ?_ I.interior_union_boundary_eq_univ).symm + exact disjoint_iff_inter_eq_empty.mp (I.disjoint_interior_boundary) + +lemma _root_.range_mem_nhds_isInteriorPoint {x : M} (h : I.IsInteriorPoint x) : + range I ∈ nhds (extChartAt I x x) := by + rw [mem_nhds_iff] + exact ⟨interior (range I), interior_subset, isOpen_interior, h⟩ + +section boundaryless +variable [I.Boundaryless] + +/-- If `I` is boundaryless, every point of `M` is an interior point. -/ +lemma isInteriorPoint {x : M} : I.IsInteriorPoint x := by + let r := ((chartAt H x).isOpen_extend_target I).interior_eq + have : extChartAt I x = (chartAt H x).extend I := rfl + rw [← this] at r + rw [ModelWithCorners.isInteriorPoint_iff, r] + exact PartialEquiv.map_source _ (mem_extChartAt_source _ _) + +/-- If `I` is boundaryless, `M` has full interior. -/ +lemma interior_eq_univ : I.interior M = univ := by + ext + refine ⟨fun _ ↦ trivial, fun _ ↦ I.isInteriorPoint⟩ + +/-- If `I` is boundaryless, `M` has empty boundary. -/ +lemma Boundaryless.boundary_eq_empty : I.boundary M = ∅ := by + rw [I.boundary_eq_complement_interior, I.interior_eq_univ, compl_empty_iff] + +end boundaryless +end ModelWithCorners diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index 000615ba8de8d..198dab83bd691 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -976,6 +976,10 @@ theorem extend_target : (f.extend I).target = I.symm ⁻¹' f.target ∩ range I simp_rw [extend, PartialEquiv.trans_target, I.target_eq, I.toPartialEquiv_coe_symm, inter_comm] #align local_homeomorph.extend_target PartialHomeomorph.extend_target +lemma isOpen_extend_target [I.Boundaryless] : IsOpen (f.extend I).target := by + rw [extend_target, I.range_eq_univ, inter_univ] + exact I.continuous_symm.isOpen_preimage _ f.open_target + theorem mapsTo_extend (hs : s ⊆ f.source) : MapsTo (f.extend I) s ((f.extend I).symm ⁻¹' s ∩ range I) := by rw [mapsTo', extend_coe, extend_coe_symm, preimage_comp, ← I.image_eq, image_comp, @@ -1023,6 +1027,19 @@ theorem extend_target_mem_nhdsWithin {y : M} (hy : y ∈ f.source) : theorem extend_target_subset_range : (f.extend I).target ⊆ range I := by simp only [mfld_simps] #align local_homeomorph.extend_target_subset_range PartialHomeomorph.extend_target_subset_range +lemma interior_extend_target_subset_interior_range : + interior (f.extend I).target ⊆ interior (range I) := by + rw [f.extend_target, interior_inter, (f.open_target.preimage I.continuous_symm).interior_eq] + exact inter_subset_right _ _ + +/-- If `y ∈ f.target` and `I y ∈ interior (range I)`, + then `I y` is an interior point of `(I ∘ f).target`. -/ +lemma mem_interior_extend_target {y : H} (hy : y ∈ f.target) + (hy' : I y ∈ interior (range I)) : I y ∈ interior (f.extend I).target := by + rw [f.extend_target, interior_inter, (f.open_target.preimage I.continuous_symm).interior_eq, + mem_inter_iff, mem_preimage] + exact ⟨mem_of_eq_of_mem (I.left_inv (y)) hy, hy'⟩ + theorem nhdsWithin_extend_target_eq {y : M} (hy : y ∈ f.source) : 𝓝[(f.extend I).target] f.extend I y = 𝓝[range I] f.extend I y := (nhdsWithin_mono _ (extend_target_subset_range _ _)).antisymm <| diff --git a/Mathlib/Topology/Basic.lean b/Mathlib/Topology/Basic.lean index b81a2a4d7c5bb..5c2b5736e149c 100644 --- a/Mathlib/Topology/Basic.lean +++ b/Mathlib/Topology/Basic.lean @@ -709,6 +709,11 @@ theorem closure_diff_interior (s : Set α) : closure s \ interior s = frontier s rfl #align closure_diff_interior closure_diff_interior +/-- Interior and frontier are disjoint. -/ +lemma disjoint_interior_frontier : Disjoint (interior s) (frontier s) := by + rw [disjoint_iff_inter_eq_empty, ← closure_diff_interior, diff_eq, + ← inter_assoc, inter_comm, ← inter_assoc, compl_inter_self, empty_inter] + @[simp] theorem closure_diff_frontier (s : Set α) : closure s \ frontier s = interior s := by rw [frontier, diff_diff_right_self, inter_eq_self_of_subset_right interior_subset_closure] From 5e71f8d00fa818ab9d68e8ddbc24862a8f0be7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Dec 2023 12:55:31 +0000 Subject: [PATCH 070/353] feat: Ruzsa covering for sets (#8916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a version covering for `Set α` and `Nat.card`. From PFR Co-authored-by: Eric Wieser --- .../Combinatorics/Additive/RuzsaCovering.lean | 21 +++++++++++++++++++ Mathlib/Data/Set/Card.lean | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean index eb813b4bb3210..b0551f599bb24 100644 --- a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean +++ b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Data.Finset.Pointwise +import Mathlib.SetTheory.Cardinal.Finite #align_import combinatorics.additive.ruzsa_covering from "leanprover-community/mathlib"@"b363547b3113d350d053abdf2884e9850a56b205" @@ -54,3 +55,23 @@ theorem exists_subset_mul_div (ht : t.Nonempty) : #align finset.exists_subset_add_sub Finset.exists_subset_add_sub end Finset + +namespace Set +variable {α : Type*} [CommGroup α] {s t : Set α} + +/-- **Ruzsa's covering lemma** for sets. See also `Finset.exists_subset_mul_div`. -/ +@[to_additive "**Ruzsa's covering lemma**. Version for sets. For finsets, +see `Finset.exists_subset_add_sub`."] +lemma exists_subset_mul_div (hs : s.Finite) (ht' : t.Finite) (ht : t.Nonempty) : + ∃ u : Set α, Nat.card u * Nat.card t ≤ Nat.card (s * t) ∧ s ⊆ u * t / t ∧ u.Finite := by + lift s to Finset α using hs + lift t to Finset α using ht' + classical + obtain ⟨u, hu, hsut⟩ := Finset.exists_subset_mul_div s ht + refine ⟨u, ?_⟩ + -- `norm_cast` would find these automatically, but breaks `to_additive` when it does so + rw [← Finset.coe_mul, ← Finset.coe_mul, ← Finset.coe_div] + norm_cast + simp [*] + +end Set diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index d61cf4bc106c3..9664197605460 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -476,7 +476,7 @@ theorem ncard_def (s : Set α) : s.ncard = ENat.toNat s.encard := rfl theorem Finite.cast_ncard_eq (hs : s.Finite) : s.ncard = s.encard := by rwa [ncard, ENat.coe_toNat_eq_self, ne_eq, encard_eq_top_iff, Set.Infinite, not_not] -@[simp] theorem Nat.card_coe_set_eq (s : Set α) : Nat.card s = s.ncard := by +theorem Nat.card_coe_set_eq (s : Set α) : Nat.card s = s.ncard := by obtain (h | h) := s.finite_or_infinite · have := h.fintype rw [ncard, h.encard_eq_coe_toFinset_card, Nat.card_eq_fintype_card, From 98fe17fdecd8106f4167ee04d05297c975b86a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Dec 2023 12:55:32 +0000 Subject: [PATCH 071/353] feat: `MeasurableSpace` instance for `ULift` (#8967) Co-authored-by: Eric Wieser Co-authored-by: sgouezel --- .../Constructions/BorelSpace/Basic.lean | 13 ++++++++++++ .../MeasureTheory/MeasurableSpace/Basic.lean | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index 45958c43a77d1..3a0489aaaa9b7 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -1107,6 +1107,19 @@ instance Prod.borelSpace [SecondCountableTopologyEither α β] : ⟨le_antisymm prod_le_borel_prod OpensMeasurableSpace.borel_le⟩ #align prod.borel_space Prod.borelSpace +/-- Given a measurable embedding to a Borel space which is also a topological embedding, then the +source space is also a Borel space. -/ +lemma MeasurableEmbedding.borelSpace {α β : Type*} [MeasurableSpace α] [TopologicalSpace α] + [MeasurableSpace β] [TopologicalSpace β] [hβ : BorelSpace β] {e : α → β} + (h'e : MeasurableEmbedding e) (h''e : Inducing e) : + BorelSpace α := by + constructor + have : MeasurableSpace.comap e (borel β) = ‹_› := by simpa [hβ.measurable_eq] using h'e.comap_eq + rw [← this, ← borel_comap, h''e.induced] + +instance _root_.ULift.instBorelSpace [BorelSpace α] : BorelSpace (ULift α) := + MeasurableEquiv.ulift.measurableEmbedding.borelSpace Homeomorph.ulift.inducing + instance DiscreteMeasurableSpace.toBorelSpace {α : Type*} [TopologicalSpace α] [DiscreteTopology α] [MeasurableSpace α] [DiscreteMeasurableSpace α] : BorelSpace α := by constructor; ext; simp [MeasurableSpace.measurableSet_generateFrom, measurableSet_discrete] diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean index 1a4cbb71b804b..b26484b265459 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean @@ -449,6 +449,22 @@ theorem measurable_unit [MeasurableSpace α] (f : Unit → α) : Measurable f := measurable_from_top #align measurable_unit measurable_unit +section ULift +variable [MeasurableSpace α] + +instance _root_.ULift.instMeasurableSpace : MeasurableSpace (ULift α) := + ‹MeasurableSpace α›.map ULift.up + +lemma measurable_down : Measurable (ULift.down : ULift α → α) := fun _ ↦ id +lemma measurable_up : Measurable (ULift.up : α → ULift α) := fun _ ↦ id + +@[simp] lemma measurableSet_preimage_down {s : Set α} : + MeasurableSet (ULift.down ⁻¹' s) ↔ MeasurableSet s := Iff.rfl +@[simp] lemma measurableSet_preimage_up {s : Set (ULift α)} : + MeasurableSet (ULift.up ⁻¹' s) ↔ MeasurableSet s := Iff.rfl + +end ULift + section Nat variable [MeasurableSpace α] @@ -1541,6 +1557,10 @@ protected def cast {α β} [i₁ : MeasurableSpace α] [i₂ : MeasurableSpace exact measurable_id #align measurable_equiv.cast MeasurableEquiv.cast +/-- Measurable equivalence between `ULift α` and `α`. -/ +def ulift.{u, v} {α : Type u} [MeasurableSpace α] : ULift.{v, u} α ≃ᵐ α := + ⟨Equiv.ulift, measurable_down, measurable_up⟩ + protected theorem measurable_comp_iff {f : β → γ} (e : α ≃ᵐ β) : Measurable (f ∘ e) ↔ Measurable f := Iff.intro From a369b3d6c9ebfa634af75b22cd75d55653909b92 Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 19 Dec 2023 13:41:21 +0000 Subject: [PATCH 072/353] feat(Data/Set/Function): add MapsTo.map_nonempty (#9093) Extracted from #8160. Co-authored-by: grunweg --- Mathlib/Data/Set/Function.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean index 7e4ea6308ce1a..344381d7f7b9b 100644 --- a/Mathlib/Data/Set/Function.lean +++ b/Mathlib/Data/Set/Function.lean @@ -428,6 +428,10 @@ theorem mapsTo_empty (f : α → β) (t : Set β) : MapsTo f ∅ t := empty_subset _ #align set.maps_to_empty Set.mapsTo_empty +/-- If `f` maps `s` to `t` and `s` is non-empty, `t` is non-empty. -/ +theorem MapsTo.nonempty (h : MapsTo f s t) (hs : s.Nonempty) : t.Nonempty := + (hs.image f).mono (mapsTo'.mp h) + theorem MapsTo.image_subset (h : MapsTo f s t) : f '' s ⊆ t := mapsTo'.1 h #align set.maps_to.image_subset Set.MapsTo.image_subset From deb0c4a512473796b27755d7668a58c5dd4e69ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Dec 2023 13:41:23 +0000 Subject: [PATCH 073/353] =?UTF-8?q?feat:=20Monotonicity=20of=20`=E2=80=A2`?= =?UTF-8?q?=20on=20`Finsupp`=20(#9148)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/Data/DFinsupp/Order.lean | 37 +++++++++++++++++++++++++++++++ Mathlib/Data/Finsupp/Order.lean | 38 ++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/Mathlib/Data/DFinsupp/Order.lean b/Mathlib/Data/DFinsupp/Order.lean index fa58b58413fd1..f0c4c51158c53 100644 --- a/Mathlib/Data/DFinsupp/Order.lean +++ b/Mathlib/Data/DFinsupp/Order.lean @@ -3,6 +3,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 -/ +import Mathlib.Algebra.Order.Module.Defs import Mathlib.Data.DFinsupp.Basic #align_import data.dfinsupp.order from "leanprover-community/mathlib"@"1d29de43a5ba4662dd33b5cfeecfc2a27a5a8a29" @@ -150,6 +151,42 @@ instance [∀ i, OrderedAddCommMonoid (α i)] [∀ i, ContravariantClass (α i) ContravariantClass (Π₀ i, α i) (Π₀ i, α i) (· + ·) (· ≤ ·) := ⟨fun _ _ _ H i ↦ le_of_add_le_add_left (H i)⟩ +section Module +variable {α : Type*} {β : ι → Type*} [Semiring α] [Preorder α] [∀ i, AddCommMonoid (β i)] + [∀ i, Preorder (β i)] [∀ i, Module α (β i)] + +instance instPosSMulMono [∀ i, PosSMulMono α (β i)] : PosSMulMono α (Π₀ i, β i) := + PosSMulMono.lift _ coe_le_coe coe_smul + +instance instSMulPosMono [∀ i, SMulPosMono α (β i)] : SMulPosMono α (Π₀ i, β i) := + SMulPosMono.lift _ coe_le_coe coe_smul coe_zero + +instance instPosSMulReflectLE [∀ i, PosSMulReflectLE α (β i)] : PosSMulReflectLE α (Π₀ i, β i) := + PosSMulReflectLE.lift _ coe_le_coe coe_smul + +instance instSMulPosReflectLE [∀ i, SMulPosReflectLE α (β i)] : SMulPosReflectLE α (Π₀ i, β i) := + SMulPosReflectLE.lift _ coe_le_coe coe_smul coe_zero + +end Module + +section Module +variable {α : Type*} {β : ι → Type*} [Semiring α] [PartialOrder α] [∀ i, AddCommMonoid (β i)] + [∀ i, PartialOrder (β i)] [∀ i, Module α (β i)] + +instance instPosSMulStrictMono [∀ i, PosSMulStrictMono α (β i)] : PosSMulStrictMono α (Π₀ i, β i) := + PosSMulStrictMono.lift _ coe_le_coe coe_smul + +instance instSMulPosStrictMono [∀ i, SMulPosStrictMono α (β i)] : SMulPosStrictMono α (Π₀ i, β i) := + SMulPosStrictMono.lift _ coe_le_coe coe_smul coe_zero + +-- Note: There is no interesting instance for `PosSMulReflectLT α (Π₀ i, β i)` that's not already +-- implied by the other instances + +instance instSMulPosReflectLT [∀ i, SMulPosReflectLT α (β i)] : SMulPosReflectLT α (Π₀ i, β i) := + SMulPosReflectLT.lift _ coe_le_coe coe_smul coe_zero + +end Module + section CanonicallyOrderedAddCommMonoid -- porting note: Split into 2 lines to satisfy the unusedVariables linter. diff --git a/Mathlib/Data/Finsupp/Order.lean b/Mathlib/Data/Finsupp/Order.lean index 9bed6cd3e4157..baa09ec25ec16 100644 --- a/Mathlib/Data/Finsupp/Order.lean +++ b/Mathlib/Data/Finsupp/Order.lean @@ -3,7 +3,8 @@ Copyright (c) 2021 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Aaron Anderson -/ -import Mathlib.Data.Finsupp.Defs +import Mathlib.Algebra.Order.Module.Defs +import Mathlib.Data.Finsupp.Basic #align_import data.finsupp.order from "leanprover-community/mathlib"@"1d29de43a5ba4662dd33b5cfeecfc2a27a5a8a29" @@ -30,7 +31,7 @@ open BigOperators open Finset -variable {ι α : Type*} +variable {ι α β : Type*} namespace Finsupp @@ -149,6 +150,39 @@ instance contravariantClass [OrderedAddCommMonoid α] [ContravariantClass α α ContravariantClass (ι →₀ α) (ι →₀ α) (· + ·) (· ≤ ·) := ⟨fun _f _g _h H x => le_of_add_le_add_left <| H x⟩ +section SMulZeroClass +variable [Zero α] [Preorder α] [Zero β] [Preorder β] [SMulZeroClass α β] + +instance instPosSMulMono [PosSMulMono α β] : PosSMulMono α (ι →₀ β) := + PosSMulMono.lift _ coe_le_coe coe_smul + +instance instSMulPosMono [SMulPosMono α β] : SMulPosMono α (ι →₀ β) := + SMulPosMono.lift _ coe_le_coe coe_smul coe_zero + +instance instPosSMulReflectLE [PosSMulReflectLE α β] : PosSMulReflectLE α (ι →₀ β) := + PosSMulReflectLE.lift _ coe_le_coe coe_smul + +instance instSMulPosReflectLE [SMulPosReflectLE α β] : SMulPosReflectLE α (ι →₀ β) := + SMulPosReflectLE.lift _ coe_le_coe coe_smul coe_zero + +end SMulZeroClass + +section SMulWithZero +variable [Zero α] [PartialOrder α] [Zero β] [PartialOrder β] [SMulWithZero α β] + +instance instPosSMulStrictMono [PosSMulStrictMono α β] : PosSMulStrictMono α (ι →₀ β) := + PosSMulStrictMono.lift _ coe_le_coe coe_smul + +instance instSMulPosStrictMono [SMulPosStrictMono α β] : SMulPosStrictMono α (ι →₀ β) := + SMulPosStrictMono.lift _ coe_le_coe coe_smul coe_zero + +-- `PosSMulReflectLT α (ι →₀ β)` already follows from the other instances + +instance instSMulPosReflectLT [SMulPosReflectLT α β] : SMulPosReflectLT α (ι →₀ β) := + SMulPosReflectLT.lift _ coe_le_coe coe_smul coe_zero + +end SMulWithZero + section CanonicallyOrderedAddCommMonoid variable [CanonicallyOrderedAddCommMonoid α] {f g : ι →₀ α} From 45a5e1b4a6326b3ee087442e8165020cbbea9ec3 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 19 Dec 2023 15:21:11 +0000 Subject: [PATCH 074/353] feat: Define the different ideal. (#9063) --- Mathlib/FieldTheory/Separable.lean | 13 ++ .../RingTheory/DedekindDomain/Different.lean | 168 +++++++++++++++--- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 11 +- Mathlib/RingTheory/Finiteness.lean | 13 ++ Mathlib/RingTheory/IntegrallyClosed.lean | 14 +- 5 files changed, 193 insertions(+), 26 deletions(-) diff --git a/Mathlib/FieldTheory/Separable.lean b/Mathlib/FieldTheory/Separable.lean index 948a244ba1467..d84753e080e0c 100644 --- a/Mathlib/FieldTheory/Separable.lean +++ b/Mathlib/FieldTheory/Separable.lean @@ -595,6 +595,19 @@ theorem IsSeparable.of_algHom (E' : Type*) [Field E'] [Algebra F E'] (f : E → exact isSeparable_tower_bot_of_isSeparable F E E' #align is_separable.of_alg_hom IsSeparable.of_algHom +lemma IsSeparable.of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁] + [Field A₂] [Field B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂) + (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁)) + [IsSeparable A₁ B₁] : IsSeparable A₂ B₂ := by + letI := e₁.toRingHom.toAlgebra + letI := ((algebraMap A₁ B₁).comp e₁.symm.toRingHom).toAlgebra + haveI : IsScalarTower A₁ A₂ B₁ := IsScalarTower.of_algebraMap_eq + (fun x ↦ by simp [RingHom.algebraMap_toAlgebra]) + let e : B₁ ≃ₐ[A₂] B₂ := { e₂ with commutes' := fun r ↦ by simpa [RingHom.algebraMap_toAlgebra] + using FunLike.congr_fun he.symm (e₁.symm r) } + haveI := isSeparable_tower_top_of_isSeparable A₁ A₂ B₁ + exact IsSeparable.of_algHom _ _ e.symm.toAlgHom + end IsSeparableTower section CardAlgHom diff --git a/Mathlib/RingTheory/DedekindDomain/Different.lean b/Mathlib/RingTheory/DedekindDomain/Different.lean index 7b66f8c57ab53..145c346ce267b 100644 --- a/Mathlib/RingTheory/DedekindDomain/Different.lean +++ b/Mathlib/RingTheory/DedekindDomain/Different.lean @@ -13,9 +13,9 @@ import Mathlib.RingTheory.DedekindDomain.IntegralClosure ## Main definition - `Submodule.traceDual`: The dual `L`-sub `B`-module under the trace form. - `FractionalIdeal.dual`: The dual fractional ideal under the trace form. +- `differentIdeal`: The different ideal of an extension of integral domains. ## TODO -- Define the relative different ideal - Show properties of the different ideal -/ @@ -153,6 +153,35 @@ lemma isIntegral_discr_mul_of_mem_traceDual variable (A K) +lemma map_equiv_traceDual [NoZeroSMulDivisors A B] (I : Submodule B (FractionRing B)) : + (traceDual A (FractionRing A) I).map (FractionRing.algEquiv B L) = + traceDual A K (I.map (FractionRing.algEquiv B L)) := by + show Submodule.map (FractionRing.algEquiv B L).toLinearEquiv.toLinearMap _ = + traceDual A K (I.map (FractionRing.algEquiv B L).toLinearEquiv.toLinearMap) + rw [Submodule.map_equiv_eq_comap_symm, Submodule.map_equiv_eq_comap_symm] + ext x + simp only [AlgEquiv.toLinearEquiv_symm, AlgEquiv.toLinearEquiv_toLinearMap, + traceDual, traceForm_apply, Submodule.mem_comap, AlgEquiv.toLinearMap_apply, + Submodule.mem_mk, AddSubmonoid.mem_mk, AddSubsemigroup.mem_mk, Set.mem_setOf_eq] + apply (FractionRing.algEquiv B L).forall_congr + simp only [restrictScalars_mem, traceForm_apply, AlgEquiv.toEquiv_eq_coe, + EquivLike.coe_coe, mem_comap, AlgEquiv.toLinearMap_apply, AlgEquiv.symm_apply_apply] + refine fun {y} ↦ (forall_congr' $ fun hy ↦ ?_) + rw [Algebra.trace_eq_of_equiv_equiv (FractionRing.algEquiv A K).toRingEquiv + (FractionRing.algEquiv B L).toRingEquiv] + swap + · apply IsLocalization.ringHom_ext (M := A⁰); ext + simp only [AlgEquiv.toRingEquiv_eq_coe, AlgEquiv.toRingEquiv_toRingHom, RingHom.coe_comp, + RingHom.coe_coe, Function.comp_apply, AlgEquiv.commutes, ← IsScalarTower.algebraMap_apply] + rw [IsScalarTower.algebraMap_apply A B (FractionRing B), AlgEquiv.commutes, + ← IsScalarTower.algebraMap_apply] + simp only [AlgEquiv.toRingEquiv_eq_coe, _root_.map_mul, AlgEquiv.coe_ringEquiv, + AlgEquiv.apply_symm_apply] + show (FractionRing.algEquiv A K).symm _ ∈ (algebraMap A (FractionRing A)).range ↔ _ + rw [← (FractionRing.algEquiv A K).symm.toAlgHom.comp_algebraMap, ← RingHom.map_range, + AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_ringHom_commutes, Subring.mem_map_equiv] + simp + open scoped Classical namespace FractionalIdeal @@ -176,11 +205,13 @@ def dual (I : FractionalIdeal B⁰ L) : · ext w; exact (IsIntegralClosure.isIntegral_iff (A := B)).symm · rw [Algebra.smul_def, RingHom.map_mul, hy, ← Algebra.smul_def]⟩ -variable [IsDedekindDomain B] {A K} {I J : FractionalIdeal B⁰ L} (hI : I ≠ 0) (hJ : J ≠ 0) +variable [IsDedekindDomain B] {I J : FractionalIdeal B⁰ L} (hI : I ≠ 0) (hJ : J ≠ 0) lemma coe_dual : (dual A K I : Submodule B L) = Iᵛ := by rw [dual, dif_neg hI]; rfl +variable (B L) + @[simp] lemma coe_dual_one : (dual A K (1 : FractionalIdeal B⁰ L) : Submodule B L) = 1ᵛ := by @@ -191,10 +222,14 @@ lemma coe_dual_one : lemma dual_zero : dual A K (0 : FractionalIdeal B⁰ L) = 0 := by rw [dual, dif_pos rfl] +variable {A K L B} + lemma mem_dual {x} : x ∈ dual A K I ↔ ∀ a ∈ I, traceForm K L x a ∈ (algebraMap A K).range := by rw [dual, dif_neg hI]; rfl +variable (A K) + lemma dual_ne_zero : dual A K I ≠ 0 := by obtain ⟨b, hb, hb'⟩ := I.prop @@ -213,13 +248,18 @@ lemma dual_ne_zero : exact IsIntegralClosure.isIntegral_iff (A := B) · exact (Algebra.smul_def _ _).symm +variable {A K} + @[simp] lemma dual_eq_zero_iff : - dual A K I = 0 ↔ I = 0 := ⟨not_imp_not.mp dual_ne_zero, fun e ↦ e.symm ▸ dual_zero⟩ + dual A K I = 0 ↔ I = 0 := + ⟨not_imp_not.mp (dual_ne_zero A K), fun e ↦ e.symm ▸ dual_zero A K L B⟩ lemma dual_ne_zero_iff : dual A K I ≠ 0 ↔ I ≠ 0 := dual_eq_zero_iff.not +variable (A K) + lemma le_dual_inv_aux (hIJ : I * J ≤ 1) : J ≤ dual A K I := by rw [dual, dif_neg hI] @@ -233,27 +273,27 @@ lemma le_dual_inv_aux (hIJ : I * J ≤ 1) : lemma one_le_dual_one : 1 ≤ dual A K (1 : FractionalIdeal B⁰ L) := - le_dual_inv_aux one_ne_zero (by rw [one_mul]) + le_dual_inv_aux A K one_ne_zero (by rw [one_mul]) lemma le_dual_iff : I ≤ dual A K J ↔ I * J ≤ dual A K 1 := by by_cases hI : I = 0 · simp [hI, zero_le] - rw [← coe_le_coe, ← coe_le_coe, coe_mul, coe_dual hJ, coe_dual_one, le_traceDual] + rw [← coe_le_coe, ← coe_le_coe, coe_mul, coe_dual A K hJ, coe_dual_one, le_traceDual] variable (I) lemma inv_le_dual : I⁻¹ ≤ dual A K I := - if hI : I = 0 then by simp [hI] else le_dual_inv_aux hI (le_of_eq (mul_inv_cancel hI)) + if hI : I = 0 then by simp [hI] else le_dual_inv_aux A K hI (le_of_eq (mul_inv_cancel hI)) lemma dual_inv_le : (dual A K I)⁻¹ ≤ I := by by_cases hI : I = 0; · simp [hI] convert mul_right_mono ((dual A K I)⁻¹) - (mul_left_mono I (inv_le_dual (A := A) (K := K) I)) using 1 + (mul_left_mono I (inv_le_dual A K I)) using 1 · simp only [mul_inv_cancel hI, one_mul] - · simp only [mul_inv_cancel (dual_ne_zero (hI := hI)), mul_assoc, mul_one] + · simp only [mul_inv_cancel (dual_ne_zero A K (hI := hI)), mul_assoc, mul_one] lemma dual_eq_mul_inv : dual A K I = dual A K 1 * I⁻¹ := by @@ -261,14 +301,14 @@ lemma dual_eq_mul_inv : apply le_antisymm · suffices : dual A K I * I ≤ dual A K 1 · convert mul_right_mono I⁻¹ this using 1; simp only [mul_inv_cancel hI, mul_one, mul_assoc] - rw [← le_dual_iff hI] - rw [le_dual_iff hI, mul_assoc, inv_mul_cancel hI, mul_one] + rw [← le_dual_iff A K hI] + rw [le_dual_iff A K hI, mul_assoc, inv_mul_cancel hI, mul_one] variable {I} lemma dual_div_dual : dual A K J / dual A K I = I / J := by - rw [dual_eq_mul_inv J, dual_eq_mul_inv I, mul_div_mul_comm, div_self, one_mul] + rw [dual_eq_mul_inv A K J, dual_eq_mul_inv A K I, mul_div_mul_comm, div_self, one_mul] exact inv_div_inv J I simp only [ne_eq, dual_eq_zero_iff, one_ne_zero, not_false_eq_true] @@ -278,7 +318,7 @@ lemma dual_mul_self : lemma self_mul_dual : I * dual A K I = dual A K 1 := by - rw [mul_comm, dual_mul_self hI] + rw [mul_comm, dual_mul_self A K hI] lemma dual_inv : dual A K I⁻¹ = dual A K 1 * I := by rw [dual_eq_mul_inv, inv_inv] @@ -288,25 +328,107 @@ variable (I) @[simp] lemma dual_dual : dual A K (dual A K I) = I := by - rw [dual_eq_mul_inv, dual_eq_mul_inv (I := I), mul_inv, inv_inv, ← mul_assoc, mul_inv_cancel, + rw [dual_eq_mul_inv, dual_eq_mul_inv A K (I := I), mul_inv, inv_inv, ← mul_assoc, mul_inv_cancel, one_mul] rw [dual_ne_zero_iff] exact one_ne_zero -lemma dual_involutive : - Function.Involutive (dual A K : FractionalIdeal B⁰ L → FractionalIdeal B⁰ L) := dual_dual - -lemma dual_injective : - Function.Injective (dual A K : FractionalIdeal B⁰ L → FractionalIdeal B⁰ L) := - dual_involutive.injective - variable {I} @[simp] lemma dual_le_dual : dual A K I ≤ dual A K J ↔ J ≤ I := by - nth_rewrite 2 [← dual_dual (A := A) (K := K) I] - rw [le_dual_iff hJ, le_dual_iff (I := J), mul_comm] - rwa [dual_ne_zero_iff] + nth_rewrite 2 [← dual_dual A K I] + rw [le_dual_iff A K hJ, le_dual_iff A K (I := J) (by rwa [dual_ne_zero_iff]), mul_comm] + +variable {A K} + +lemma dual_involutive : + Function.Involutive (dual A K : FractionalIdeal B⁰ L → FractionalIdeal B⁰ L) := dual_dual A K + +lemma dual_injective : + Function.Injective (dual A K : FractionalIdeal B⁰ L → FractionalIdeal B⁰ L) := + dual_involutive.injective end FractionalIdeal + +variable (B) +variable [IsDedekindDomain B] + +/-- The different ideal of an extension of integral domains `B/A` is the inverse of the dual of `A` +as an ideal of `B`. See `coeIdeal_differentIdeal` and `coeSubmodule_differentIdeal`. -/ +def differentIdeal [NoZeroSMulDivisors A B] : Ideal B := + (1 / Submodule.traceDual A (FractionRing A) 1 : Submodule B (FractionRing B)).comap + (Algebra.linearMap B (FractionRing B)) + +lemma coeSubmodule_differentIdeal_fractionRing + [NoZeroSMulDivisors A B] (hAB : Algebra.IsIntegral A B) + [IsSeparable (FractionRing A) (FractionRing B)] + [FiniteDimensional (FractionRing A) (FractionRing B)] : + coeSubmodule (FractionRing B) (differentIdeal A B) = + 1 / Submodule.traceDual A (FractionRing A) 1 := by + have : IsIntegralClosure B A (FractionRing B) := + IsIntegralClosure.of_isIntegrallyClosed _ _ _ hAB + rw [coeSubmodule, differentIdeal, Submodule.map_comap_eq, inf_eq_right] + have := FractionalIdeal.dual_inv_le (A := A) (K := FractionRing A) + (1 : FractionalIdeal B⁰ (FractionRing B)) + have : _ ≤ ((1 : FractionalIdeal B⁰ (FractionRing B)) : Submodule B (FractionRing B)) := this + simp only [← one_div, FractionalIdeal.val_eq_coe] at this + rw [FractionalIdeal.coe_div (FractionalIdeal.dual_ne_zero _ _ _), + FractionalIdeal.coe_dual] at this + simpa only [FractionalIdeal.coe_one] using this + · exact one_ne_zero + · exact one_ne_zero + +lemma coeSubmodule_differentIdeal [NoZeroSMulDivisors A B] : + coeSubmodule L (differentIdeal A B) = 1 / Submodule.traceDual A K 1 := by + have : (FractionRing.algEquiv B L).toLinearEquiv.comp (Algebra.linearMap B (FractionRing B)) = + Algebra.linearMap B L := by ext; simp + rw [coeSubmodule, ← this] + have H : RingHom.comp (algebraMap (FractionRing A) (FractionRing B)) + ↑(FractionRing.algEquiv A K).symm.toRingEquiv = + RingHom.comp ↑(FractionRing.algEquiv B L).symm.toRingEquiv (algebraMap K L) + · apply IsLocalization.ringHom_ext A⁰ + ext + simp only [AlgEquiv.toRingEquiv_eq_coe, RingHom.coe_comp, RingHom.coe_coe, + AlgEquiv.coe_ringEquiv, Function.comp_apply, AlgEquiv.commutes, + ← IsScalarTower.algebraMap_apply] + rw [IsScalarTower.algebraMap_apply A B L, AlgEquiv.commutes, ← IsScalarTower.algebraMap_apply] + have : IsSeparable (FractionRing A) (FractionRing B) := IsSeparable.of_equiv_equiv _ _ H + have : FiniteDimensional (FractionRing A) (FractionRing B) := Module.Finite.of_equiv_equiv _ _ H + simp only [AlgEquiv.toLinearEquiv_toLinearMap, Submodule.map_comp] + rw [← coeSubmodule, coeSubmodule_differentIdeal_fractionRing _ _ + (IsIntegralClosure.isIntegral_algebra _ L), + Submodule.map_div, ← AlgEquiv.toAlgHom_toLinearMap, Submodule.map_one] + congr 1 + refine (map_equiv_traceDual A K _).trans ?_ + congr 1 + ext + simp + +variable (L) + +lemma coeIdeal_differentIdeal [NoZeroSMulDivisors A B] : + ↑(differentIdeal A B) = (FractionalIdeal.dual A K (1 : FractionalIdeal B⁰ L))⁻¹ := by + apply FractionalIdeal.coeToSubmodule_injective + simp only [FractionalIdeal.coe_div + (FractionalIdeal.dual_ne_zero _ _ (@one_ne_zero (FractionalIdeal B⁰ L) _ _ _)), + FractionalIdeal.coe_coeIdeal, coeSubmodule_differentIdeal A K, inv_eq_one_div, + FractionalIdeal.coe_dual_one, FractionalIdeal.coe_one] + +variable {A K B L} + +lemma differentialIdeal_le_fractionalIdeal_iff + {I : FractionalIdeal B⁰ L} (hI : I ≠ 0) [NoZeroSMulDivisors A B] : + differentIdeal A B ≤ I ↔ (((I⁻¹ : _) : Submodule B L).restrictScalars A).map + ((Algebra.trace K L).restrictScalars A) ≤ 1 := by + rw [coeIdeal_differentIdeal A K L B, FractionalIdeal.inv_le_comm (by simp) hI, + ← FractionalIdeal.coe_le_coe, FractionalIdeal.coe_dual_one] + refine le_traceDual_iff_map_le_one.trans ?_ + simp + +lemma differentialIdeal_le_iff {I : Ideal B} (hI : I ≠ ⊥) [NoZeroSMulDivisors A B] : + differentIdeal A B ≤ I ↔ (((I⁻¹ : FractionalIdeal B⁰ L) : Submodule B L).restrictScalars A).map + ((Algebra.trace K L).restrictScalars A) ≤ 1 := + (FractionalIdeal.coeIdeal_le_coeIdeal _).symm.trans + (differentialIdeal_le_fractionalIdeal_iff (I := (I : FractionalIdeal B⁰ L)) (by simpa)) diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index f17a8d550da72..9c16f152210c5 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -768,9 +768,18 @@ theorem Associates.le_singleton_iff (x : A) (n : ℕ) (I : Ideal A) : Ideal.dvd_span_singleton] #align associates.le_singleton_iff Associates.le_singleton_iff +variable {K} + +lemma FractionalIdeal.le_inv_comm {I J : FractionalIdeal A⁰ K} (hI : I ≠ 0) (hJ : J ≠ 0) : + I ≤ J⁻¹ ↔ J ≤ I⁻¹ := by + rw [inv_eq, inv_eq, le_div_iff_mul_le hI, le_div_iff_mul_le hJ, mul_comm] + +lemma FractionalIdeal.inv_le_comm {I J : FractionalIdeal A⁰ K} (hI : I ≠ 0) (hJ : J ≠ 0) : + I⁻¹ ≤ J ↔ J⁻¹ ≤ I := by + simpa using le_inv_comm (A := A) (K := K) (inv_ne_zero hI) (inv_ne_zero hJ) + open FractionalIdeal -variable {K} /-- Strengthening of `IsLocalization.exist_integer_multiples`: Let `J ≠ ⊤` be an ideal in a Dedekind domain `A`, and `f ≠ 0` a finite collection diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index 4cb5b954b4aad..38eaa127af764 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -657,6 +657,19 @@ theorem trans {R : Type*} (A M : Type*) [CommSemiring R] [Semiring A] [Algebra R Submodule.restrictScalars_top]⟩⟩ #align module.finite.trans Module.Finite.trans +lemma of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [CommRing A₁] [CommRing B₁] + [CommRing A₂] [CommRing B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂) + (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁)) + [Module.Finite A₁ B₁] : Module.Finite A₂ B₂ := by + letI := e₁.toRingHom.toAlgebra + letI := ((algebraMap A₁ B₁).comp e₁.symm.toRingHom).toAlgebra + haveI : IsScalarTower A₁ A₂ B₁ := IsScalarTower.of_algebraMap_eq + (fun x ↦ by simp [RingHom.algebraMap_toAlgebra]) + let e : B₁ ≃ₐ[A₂] B₂ := { e₂ with commutes' := fun r ↦ by simpa [RingHom.algebraMap_toAlgebra] + using FunLike.congr_fun he.symm (e₁.symm r) } + haveI := Module.Finite.of_restrictScalars_finite A₁ A₂ B₁ + exact Module.Finite.equiv e.toLinearEquiv + end Algebra end Finite diff --git a/Mathlib/RingTheory/IntegrallyClosed.lean b/Mathlib/RingTheory/IntegrallyClosed.lean index fcb3d0700c6e0..2c2ec88419b13 100644 --- a/Mathlib/RingTheory/IntegrallyClosed.lean +++ b/Mathlib/RingTheory/IntegrallyClosed.lean @@ -79,7 +79,7 @@ end Iff namespace IsIntegrallyClosed -variable {R : Type*} [CommRing R] [id : IsDomain R] [iic : IsIntegrallyClosed R] +variable {R S : Type*} [CommRing R] [CommRing S] [id : IsDomain R] [iic : IsIntegrallyClosed R] variable {K : Type*} [CommRing K] [Algebra R K] [ifr : IsFractionRing R K] @@ -101,7 +101,17 @@ theorem exists_algebraMap_eq_of_pow_mem_subalgebra {K : Type*} [CommRing K] [Alg exists_algebraMap_eq_of_isIntegral_pow hn <| isIntegral_iff.mpr ⟨⟨x ^ n, hx⟩, rfl⟩ #align is_integrally_closed.exists_algebra_map_eq_of_pow_mem_subalgebra IsIntegrallyClosed.exists_algebraMap_eq_of_pow_mem_subalgebra -variable (K) +variable (R S K) + +lemma _root_.IsIntegralClosure.of_isIntegrallyClosed + [Algebra S R] [Algebra S K] [IsScalarTower S R K] (hRS : Algebra.IsIntegral S R) : + IsIntegralClosure R S K := by + refine ⟨IsLocalization.injective _ le_rfl, fun {x} ↦ + ⟨fun hx ↦ IsIntegralClosure.isIntegral_iff.mp (IsIntegral.tower_top (A := R) hx), ?_⟩⟩ + rintro ⟨y, rfl⟩ + exact IsIntegral.map (IsScalarTower.toAlgHom S R K) (hRS y) + +variable {R} theorem integralClosure_eq_bot_iff : integralClosure R K = ⊥ ↔ IsIntegrallyClosed R := by refine' eq_bot_iff.trans _ From ea02b9e2f48c3b5d2d9bd8208f25276ad4af7915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Dec 2023 15:21:13 +0000 Subject: [PATCH 075/353] feat: More `rpow` lemmas (#9108) A bunch of easy lemmas about `Real.pow` and the golf of existing lemmas with them. Also rename `log_le_log` to `log_le_log_iff` and `log_le_log'` to `log_le_log`. Those misnames caused several proofs to bother with side conditions they didn't need. From LeanAPAP --- Archive/Imo/Imo2001Q2.lean | 2 +- .../Analysis/SpecialFunctions/CompareExp.lean | 2 +- .../Analysis/SpecialFunctions/Log/Base.lean | 4 +- .../Analysis/SpecialFunctions/Log/Basic.lean | 18 +- .../Analysis/SpecialFunctions/Pow/NNReal.lean | 12 +- .../Analysis/SpecialFunctions/Pow/Real.lean | 248 +++++++++++------- .../Analysis/SpecialFunctions/Stirling.lean | 5 +- Mathlib/Combinatorics/Additive/Behrend.lean | 42 +-- .../Computability/AkraBazzi/AkraBazzi.lean | 2 +- Mathlib/Data/Complex/Exponential.lean | 6 + 10 files changed, 194 insertions(+), 147 deletions(-) diff --git a/Archive/Imo/Imo2001Q2.lean b/Archive/Imo/Imo2001Q2.lean index 619eb77abdf50..2276168242724 100644 --- a/Archive/Imo/Imo2001Q2.lean +++ b/Archive/Imo/Imo2001Q2.lean @@ -67,7 +67,7 @@ open Imo2001Q2 theorem imo2001_q2 (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : ↑1 ≤ a / sqrt (a ^ 2 + ↑8 * b * c) + b / sqrt (b ^ 2 + ↑8 * c * a) + c / sqrt (c ^ 2 + ↑8 * a * b) := have h3 : ∀ {x : ℝ}, 0 < x → (x ^ (3 : ℝ)⁻¹) ^ 3 = x := fun hx => - show ↑3 = (3 : ℝ) by norm_num ▸ rpow_nat_inv_pow_nat hx.le three_ne_zero + show ↑3 = (3 : ℝ) by norm_num ▸ rpow_inv_natCast_pow hx.le three_ne_zero calc 1 ≤ _ := imo2001_q2' (rpow_pos_of_pos ha _) (rpow_pos_of_pos hb _) (rpow_pos_of_pos hc _) _ = _ := by rw [h3 ha, h3 hb, h3 hc] diff --git a/Mathlib/Analysis/SpecialFunctions/CompareExp.lean b/Mathlib/Analysis/SpecialFunctions/CompareExp.lean index 09612131c4d31..7e6bae15b2529 100644 --- a/Mathlib/Analysis/SpecialFunctions/CompareExp.lean +++ b/Mathlib/Analysis/SpecialFunctions/CompareExp.lean @@ -136,7 +136,7 @@ theorem isLittleO_log_abs_re (hl : IsExpCmpFilter l) : (fun z => Real.log (abs z have hm₀ : 0 < max z.re |z.im| := lt_max_iff.2 (Or.inl <| one_pos.trans_le hz) rw [one_mul, Real.norm_eq_abs, _root_.abs_of_nonneg (Real.log_nonneg hz')] refine' le_trans _ (le_abs_self _) - rw [← Real.log_mul, Real.log_le_log, ← _root_.abs_of_nonneg (le_trans zero_le_one hz)] + rw [← Real.log_mul, Real.log_le_log_iff, ← _root_.abs_of_nonneg (le_trans zero_le_one hz)] exacts [abs_le_sqrt_two_mul_max z, one_pos.trans_le hz', mul_pos h2 hm₀, h2.ne', hm₀.ne'] _ =o[l] re := IsLittleO.add (isLittleO_const_left.2 <| Or.inr <| hl.tendsto_abs_re) <| diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Base.lean b/Mathlib/Analysis/SpecialFunctions/Log/Base.lean index c5a2600b595db..e51f3d6dfe94e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Base.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Base.lean @@ -182,7 +182,7 @@ private theorem b_ne_one' : b ≠ 1 := by linarith @[simp] theorem logb_le_logb (h : 0 < x) (h₁ : 0 < y) : logb b x ≤ logb b y ↔ x ≤ y := by - rw [logb, logb, div_le_div_right (log_pos hb), log_le_log h h₁] + rw [logb, logb, div_le_div_right (log_pos hb), log_le_log_iff h h₁] #align real.logb_le_logb Real.logb_le_logb @[gcongr] @@ -295,7 +295,7 @@ private theorem b_ne_one : b ≠ 1 := by linarith @[simp] theorem logb_le_logb_of_base_lt_one (h : 0 < x) (h₁ : 0 < y) : logb b x ≤ logb b y ↔ y ≤ x := by - rw [logb, logb, div_le_div_right_of_neg (log_neg b_pos b_lt_one), log_le_log h₁ h] + rw [logb, logb, div_le_div_right_of_neg (log_neg b_pos b_lt_one), log_le_log_iff h₁ h] #align real.logb_le_logb_of_base_lt_one Real.logb_le_logb_of_base_lt_one theorem logb_lt_logb_of_base_lt_one (hx : 0 < x) (hxy : x < y) : logb b y < logb b x := by diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean index 9fe491de8e2d9..24ba679fa2b05 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean @@ -141,22 +141,18 @@ theorem log_inv (x : ℝ) : log x⁻¹ = -log x := by rw [← exp_eq_exp, exp_log_eq_abs (inv_ne_zero hx), exp_neg, exp_log_eq_abs hx, abs_inv] #align real.log_inv Real.log_inv -theorem log_le_log (h : 0 < x) (h₁ : 0 < y) : log x ≤ log y ↔ x ≤ y := by +theorem log_le_log_iff (h : 0 < x) (h₁ : 0 < y) : log x ≤ log y ↔ x ≤ y := by rw [← exp_le_exp, exp_log h, exp_log h₁] -#align real.log_le_log Real.log_le_log +#align real.log_le_log Real.log_le_log_iff @[gcongr] -theorem log_lt_log (hx : 0 < x) : x < y → log x < log y := by - intro h - rwa [← exp_lt_exp, exp_log hx, exp_log (lt_trans hx h)] -#align real.log_lt_log Real.log_lt_log +lemma log_le_log (hx : 0 < x) (hxy : x ≤ y) : log x ≤ log y := + (log_le_log_iff hx (hx.trans_le hxy)).2 hxy @[gcongr] -theorem log_le_log' (hx : 0 < x) : x ≤ y → log x ≤ log y := by - intro hxy - cases hxy.eq_or_lt with - | inl h_eq => simp [h_eq] - | inr hlt => exact le_of_lt <| log_lt_log hx hlt +theorem log_lt_log (hx : 0 < x) (h : x < y) : log x < log y := by + rwa [← exp_lt_exp, exp_log hx, exp_log (lt_trans hx h)] +#align real.log_lt_log Real.log_lt_log theorem log_lt_log_iff (hx : 0 < x) (hy : 0 < y) : log x < log y ↔ x < y := by rw [← exp_lt_exp, exp_log hx, exp_log hy] diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean b/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean index 920e9ce3a48f8..9a4f0606447eb 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean @@ -320,15 +320,15 @@ theorem rpow_one_div_eq_iff {x y : ℝ≥0} {z : ℝ} (hz : z ≠ 0) : x ^ (1 / rw [← rpow_eq_rpow_iff hz, rpow_self_rpow_inv hz] #align nnreal.rpow_one_div_eq_iff NNReal.rpow_one_div_eq_iff -theorem pow_nat_rpow_nat_inv (x : ℝ≥0) {n : ℕ} (hn : n ≠ 0) : (x ^ n) ^ (n⁻¹ : ℝ) = x := by +theorem pow_rpow_inv_natCast (x : ℝ≥0) {n : ℕ} (hn : n ≠ 0) : (x ^ n) ^ (n⁻¹ : ℝ) = x := by rw [← NNReal.coe_eq, coe_rpow, NNReal.coe_pow] - exact Real.pow_nat_rpow_nat_inv x.2 hn -#align nnreal.pow_nat_rpow_nat_inv NNReal.pow_nat_rpow_nat_inv + exact Real.pow_rpow_inv_natCast x.2 hn +#align nnreal.pow_nat_rpow_nat_inv NNReal.pow_rpow_inv_natCast -theorem rpow_nat_inv_pow_nat (x : ℝ≥0) {n : ℕ} (hn : n ≠ 0) : (x ^ (n⁻¹ : ℝ)) ^ n = x := by +theorem rpow_inv_natCast_pow (x : ℝ≥0) {n : ℕ} (hn : n ≠ 0) : (x ^ (n⁻¹ : ℝ)) ^ n = x := by rw [← NNReal.coe_eq, NNReal.coe_pow, coe_rpow] - exact Real.rpow_nat_inv_pow_nat x.2 hn -#align nnreal.rpow_nat_inv_pow_nat NNReal.rpow_nat_inv_pow_nat + exact Real.rpow_inv_natCast_pow x.2 hn +#align nnreal.rpow_nat_inv_pow_nat NNReal.rpow_inv_natCast_pow theorem _root_.Real.toNNReal_rpow_of_nonneg {x y : ℝ} (hx : 0 ≤ x) : Real.toNNReal (x ^ y) = Real.toNNReal x ^ y := by diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean index b4dff8e01d1ef..58b55feae704e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean @@ -26,6 +26,7 @@ open Finset Set ## Definitions -/ namespace Real +variable {x y z : ℝ} /-- The real power function `x ^ y`, defined as the real part of the complex power function. For `x > 0`, it is equal to `exp (y log x)`. For `x = 0`, one sets `0 ^ 0=1` and `0 ^ y=0` for @@ -58,15 +59,31 @@ theorem rpow_def_of_pos {x : ℝ} (hx : 0 < x) (y : ℝ) : x ^ y = exp (log x * theorem exp_mul (x y : ℝ) : exp (x * y) = exp x ^ y := by rw [rpow_def_of_pos (exp_pos _), log_exp] #align real.exp_mul Real.exp_mul +@[simp, norm_cast] +theorem rpow_int_cast (x : ℝ) (n : ℤ) : x ^ (n : ℝ) = x ^ n := by + simp only [rpow_def, ← Complex.ofReal_zpow, Complex.cpow_int_cast, Complex.ofReal_int_cast, + Complex.ofReal_re] +#align real.rpow_int_cast Real.rpow_int_cast + +@[simp, norm_cast] +theorem rpow_nat_cast (x : ℝ) (n : ℕ) : x ^ (n : ℝ) = x ^ n := by simpa using rpow_int_cast x n +#align real.rpow_nat_cast Real.rpow_nat_cast + @[simp] theorem exp_one_rpow (x : ℝ) : exp 1 ^ x = exp x := by rw [← exp_mul, one_mul] #align real.exp_one_rpow Real.exp_one_rpow -theorem rpow_eq_zero_iff_of_nonneg {x y : ℝ} (hx : 0 ≤ x) : x ^ y = 0 ↔ x = 0 ∧ y ≠ 0 := by +@[simp] lemma exp_one_pow (n : ℕ) : exp 1 ^ n = exp n := by rw [← rpow_nat_cast, exp_one_rpow] + +theorem rpow_eq_zero_iff_of_nonneg (hx : 0 ≤ x) : x ^ y = 0 ↔ x = 0 ∧ y ≠ 0 := by simp only [rpow_def_of_nonneg hx] split_ifs <;> simp [*, exp_ne_zero] #align real.rpow_eq_zero_iff_of_nonneg Real.rpow_eq_zero_iff_of_nonneg +@[simp] +lemma rpow_eq_zero (hx : 0 ≤ x) (hy : y ≠ 0) : x ^ y = 0 ↔ x = 0 := by + simp [rpow_eq_zero_iff_of_nonneg, *] + open Real theorem rpow_def_of_neg {x : ℝ} (hx : x < 0) (y : ℝ) : x ^ y = exp (log x * y) * cos (y * π) := by @@ -315,6 +332,39 @@ theorem abs_cpow_eq_rpow_re_of_nonneg {x : ℝ} (hx : 0 ≤ x) {y : ℂ} (hy : r end Complex +/-! ### Positivity extension -/ + +namespace Mathlib.Meta.Positivity +open Lean Meta Qq + +/-- Extension for the `positivity` tactic: exponentiation by a real number is positive (namely 1) +when the exponent is zero. The other cases are done in `evalRpow`. -/ +@[positivity (_ : ℝ) ^ (0 : ℝ), Pow.pow (_ : ℝ) (0 : ℝ), Real.rpow (_ : ℝ) (0 : ℝ)] +def evalRpowZero : Mathlib.Meta.Positivity.PositivityExt where eval {_ _} _ _ e := do + let .app (.app (f : Q(ℝ → ℝ → ℝ)) (a : Q(ℝ))) (_ : Q(ℝ)) ← withReducible (whnf e) + | throwError "not Real.rpow" + guard <|← withDefault <| withNewMCtxDepth <| isDefEq f q(Real.rpow) + pure (.positive (q(Real.rpow_zero_pos $a) : Expr)) + +/-- Extension for the `positivity` tactic: exponentiation by a real number is nonnegative when +the base is nonnegative and positive when the base is positive. -/ +@[positivity (_ : ℝ) ^ (_ : ℝ), Pow.pow (_ : ℝ) (_ : ℝ), Real.rpow (_ : ℝ) (_ : ℝ)] +def evalRpow : Mathlib.Meta.Positivity.PositivityExt where eval {_ _} zα pα e := do + let .app (.app (f : Q(ℝ → ℝ → ℝ)) (a : Q(ℝ))) (b : Q(ℝ)) ← withReducible (whnf e) + | throwError "not Real.rpow" + guard <| ← withDefault <| withNewMCtxDepth <| isDefEq f q(Real.rpow) + let ra ← core zα pα a + match ra with + | .positive pa => + have pa' : Q(0 < $a) := pa + pure (.positive (q(Real.rpow_pos_of_pos $pa' $b) : Expr)) + | .nonnegative pa => + have pa' : Q(0 ≤ $a) := pa + pure (.nonnegative (q(Real.rpow_nonneg_of_nonneg $pa' $b) : Expr)) + | _ => pure .none + +end Mathlib.Meta.Positivity + /-! ## Further algebraic properties of `rpow` -/ @@ -322,7 +372,7 @@ end Complex namespace Real -variable {x y z : ℝ} +variable {x y z : ℝ} {n : ℕ} theorem rpow_mul {x : ℝ} (hx : 0 ≤ x) (y z : ℝ) : x ^ (y * z) = (x ^ y) ^ z := by rw [← Complex.ofReal_inj, Complex.ofReal_cpow (rpow_nonneg_of_nonneg hx _), @@ -349,6 +399,18 @@ theorem rpow_sub_nat {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y - n) by simpa using rpow_sub_int hx y n #align real.rpow_sub_nat Real.rpow_sub_nat +lemma rpow_add_int' (hx : 0 ≤ x) {n : ℤ} (h : y + n ≠ 0) : x ^ (y + n) = x ^ y * x ^ n := by + rw [rpow_add' hx h, rpow_int_cast] + +lemma rpow_add_nat' (hx : 0 ≤ x) (h : y + n ≠ 0) : x ^ (y + n) = x ^ y * x ^ n := by + rw [rpow_add' hx h, rpow_nat_cast] + +lemma rpow_sub_int' (hx : 0 ≤ x) {n : ℤ} (h : y - n ≠ 0) : x ^ (y - n) = x ^ y / x ^ n := by + rw [rpow_sub' hx h, rpow_int_cast] + +lemma rpow_sub_nat' (hx : 0 ≤ x) (h : y - n ≠ 0) : x ^ (y - n) = x ^ y / x ^ n := by + rw [rpow_sub' hx h, rpow_nat_cast] + theorem rpow_add_one {x : ℝ} (hx : x ≠ 0) (y : ℝ) : x ^ (y + 1) = x ^ y * x := by simpa using rpow_add_nat hx y 1 #align real.rpow_add_one Real.rpow_add_one @@ -357,16 +419,17 @@ theorem rpow_sub_one {x : ℝ} (hx : x ≠ 0) (y : ℝ) : x ^ (y - 1) = x ^ y / simpa using rpow_sub_nat hx y 1 #align real.rpow_sub_one Real.rpow_sub_one -@[simp, norm_cast] -theorem rpow_int_cast (x : ℝ) (n : ℤ) : x ^ (n : ℝ) = x ^ n := by - simp only [rpow_def, ← Complex.ofReal_zpow, Complex.cpow_int_cast, Complex.ofReal_int_cast, - Complex.ofReal_re] -#align real.rpow_int_cast Real.rpow_int_cast +lemma rpow_add_one' (hx : 0 ≤ x) (h : y + 1 ≠ 0) : x ^ (y + 1) = x ^ y * x := by + rw [rpow_add' hx h, rpow_one] -@[simp, norm_cast] -theorem rpow_nat_cast (x : ℝ) (n : ℕ) : x ^ (n : ℝ) = x ^ n := - by simpa using rpow_int_cast x n -#align real.rpow_nat_cast Real.rpow_nat_cast +lemma rpow_one_add' (hx : 0 ≤ x) (h : 1 + y ≠ 0) : x ^ (1 + y) = x * x ^ y := by + rw [rpow_add' hx h, rpow_one] + +lemma rpow_sub_one' (hx : 0 ≤ x) (h : y - 1 ≠ 0) : x ^ (y - 1) = x ^ y / x := by + rw [rpow_sub' hx h, rpow_one] + +lemma rpow_one_sub' (hx : 0 ≤ x) (h : 1 - y ≠ 0) : x ^ (1 - y) = x / x ^ y := by + rw [rpow_sub' hx h, rpow_one] @[simp] theorem rpow_two (x : ℝ) : x ^ (2 : ℝ) = x ^ 2 := by @@ -379,25 +442,10 @@ theorem rpow_neg_one (x : ℝ) : x ^ (-1 : ℝ) = x⁻¹ := by simp only [rpow_int_cast, zpow_one, zpow_neg] #align real.rpow_neg_one Real.rpow_neg_one -theorem mul_rpow {x y z : ℝ} (h : 0 ≤ x) (h₁ : 0 ≤ y) : (x * y) ^ z = x ^ z * y ^ z := by +theorem mul_rpow (hx : 0 ≤ x) (hy : 0 ≤ y) : (x * y) ^ z = x ^ z * y ^ z := by iterate 2 rw [Real.rpow_def_of_nonneg]; split_ifs with h_ifs <;> simp_all - · exact h - · rw [not_or] at h_ifs - have hx : 0 < x := by - cases' lt_or_eq_of_le h with h₂ h₂ - · exact h₂ - exfalso - apply h_ifs.1 - exact Eq.symm h₂ - have hy : 0 < y := by - cases' lt_or_eq_of_le h₁ with h₂ h₂ - · exact h₂ - exfalso - apply h_ifs.2 - exact Eq.symm h₂ - rw [log_mul (ne_of_gt hx) (ne_of_gt hy), add_mul, exp_add, rpow_def_of_pos hx, - rpow_def_of_pos hy] - · exact mul_nonneg h h₁ + · rw [log_mul ‹_› ‹_›, add_mul, exp_add, rpow_def_of_pos (hy.lt_of_ne' ‹_›)] + all_goals positivity #align real.mul_rpow Real.mul_rpow theorem inv_rpow (hx : 0 ≤ x) (y : ℝ) : x⁻¹ ^ y = (x ^ y)⁻¹ := by @@ -418,6 +466,34 @@ theorem mul_log_eq_log_iff {x y z : ℝ} (hx : 0 < x) (hz : 0 < z) : ⟨fun h ↦ log_injOn_pos (rpow_pos_of_pos hx _) hz <| log_rpow hx _ |>.trans h, by rintro rfl; rw [log_rpow hx]⟩ +@[simp] lemma rpow_rpow_inv (hx : 0 ≤ x) (hy : y ≠ 0) : (x ^ y) ^ y⁻¹ = x := by + rw [← rpow_mul hx, mul_inv_cancel hy, rpow_one] + +@[simp] lemma rpow_inv_rpow (hx : 0 ≤ x) (hy : y ≠ 0) : (x ^ y⁻¹) ^ y = x := by + rw [← rpow_mul hx, inv_mul_cancel hy, rpow_one] + +theorem pow_rpow_inv_natCast (hx : 0 ≤ x) (hn : n ≠ 0) : (x ^ n) ^ (n⁻¹ : ℝ) = x := by + have hn0 : (n : ℝ) ≠ 0 := Nat.cast_ne_zero.2 hn + rw [← rpow_nat_cast, ← rpow_mul hx, mul_inv_cancel hn0, rpow_one] +#align real.pow_nat_rpow_nat_inv Real.pow_rpow_inv_natCast + +theorem rpow_inv_natCast_pow (hx : 0 ≤ x) (hn : n ≠ 0) : (x ^ (n⁻¹ : ℝ)) ^ n = x := by + have hn0 : (n : ℝ) ≠ 0 := Nat.cast_ne_zero.2 hn + rw [← rpow_nat_cast, ← rpow_mul hx, inv_mul_cancel hn0, rpow_one] +#align real.rpow_nat_inv_pow_nat Real.rpow_inv_natCast_pow + +lemma rpow_natCast_mul (hx : 0 ≤ x) (n : ℕ) (z : ℝ) : x ^ (n * z) = (x ^ n) ^ z := by + rw [rpow_mul hx, rpow_nat_cast] + +lemma rpow_mul_natCast (hx : 0 ≤ x) (y : ℝ) (n : ℕ) : x ^ (y * n) = (x ^ y) ^ n := by + rw [rpow_mul hx, rpow_nat_cast] + +lemma rpow_intCast_mul (hx : 0 ≤ x) (n : ℤ) (z : ℝ) : x ^ (n * z) = (x ^ n) ^ z := by + rw [rpow_mul hx, rpow_int_cast] + +lemma rpow_mul_intCast (hx : 0 ≤ x) (y : ℝ) (n : ℤ) : x ^ (y * n) = (x ^ y) ^ n := by + rw [rpow_mul hx, rpow_int_cast] + /-! Note: lemmas about `(∏ i in s, f i ^ r)` such as `Real.finset_prod_rpow` are proved in `Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean` instead. -/ @@ -450,6 +526,18 @@ theorem monotoneOn_rpow_Ici_of_exponent_nonneg {r : ℝ} (hr : 0 ≤ r) : MonotoneOn (fun (x : ℝ) => x ^ r) (Set.Ici 0) := fun _ ha _ _ hab => rpow_le_rpow ha hab hr +lemma rpow_lt_rpow_of_neg (hx : 0 < x) (hxy : x < y) (hz : z < 0) : y ^ z < x ^ z := by + have := hx.trans hxy + rw [← inv_lt_inv, ← rpow_neg, ← rpow_neg] + refine rpow_lt_rpow ?_ hxy (neg_pos.2 hz) + all_goals positivity + +lemma rpow_le_rpow_of_nonpos (hx : 0 < x) (hxy : x ≤ y) (hz : z ≤ 0) : y ^ z ≤ x ^ z := by + have := hx.trans_le hxy + rw [← inv_le_inv, ← rpow_neg, ← rpow_neg] + refine rpow_le_rpow ?_ hxy (neg_nonneg.2 hz) + all_goals positivity + theorem rpow_lt_rpow_iff (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : 0 < z) : x ^ z < y ^ z ↔ x < y := ⟨lt_imp_lt_of_le_imp_le fun h => rpow_le_rpow hy h (le_of_lt hz), fun h => rpow_lt_rpow hx h hz⟩ #align real.rpow_lt_rpow_iff Real.rpow_lt_rpow_iff @@ -458,38 +546,43 @@ theorem rpow_le_rpow_iff (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : 0 < z) : x ^ z ≤ le_iff_le_iff_lt_iff_lt.2 <| rpow_lt_rpow_iff hy hx hz #align real.rpow_le_rpow_iff Real.rpow_le_rpow_iff +lemma rpow_lt_rpow_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ^ z < y ^ z ↔ y < x := + ⟨lt_imp_lt_of_le_imp_le fun h ↦ rpow_le_rpow_of_nonpos hx h hz.le, + fun h ↦ rpow_lt_rpow_of_neg hy h hz⟩ + +lemma rpow_le_rpow_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ^ z ≤ y ^ z ↔ y ≤ x := + le_iff_le_iff_lt_iff_lt.2 $ rpow_lt_rpow_iff_of_neg hy hx hz + +lemma le_rpow_inv_iff_of_pos (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : 0 < z) : x ≤ y ^ z⁻¹ ↔ x ^ z ≤ y := by + rw [← rpow_le_rpow_iff hx _ hz, rpow_inv_rpow] <;> positivity + +lemma rpow_inv_le_iff_of_pos (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : 0 < z) : x ^ z⁻¹ ≤ y ↔ x ≤ y ^ z := by + rw [← rpow_le_rpow_iff _ hy hz, rpow_inv_rpow] <;> positivity + +lemma lt_rpow_inv_iff_of_pos (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : 0 < z) : x < y ^ z⁻¹ ↔ x ^ z < y := + lt_iff_lt_of_le_iff_le $ rpow_inv_le_iff_of_pos hy hx hz + +lemma rpow_inv_lt_iff_of_pos (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : 0 < z) : x ^ z⁻¹ < y ↔ x < y ^ z := + lt_iff_lt_of_le_iff_le $ le_rpow_inv_iff_of_pos hy hx hz + theorem le_rpow_inv_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ≤ y ^ z⁻¹ ↔ y ≤ x ^ z := by - have hz' : 0 < -z := by rwa [lt_neg, neg_zero] - have hxz : 0 < x ^ (-z) := Real.rpow_pos_of_pos hx _ - have hyz : 0 < y ^ z⁻¹ := Real.rpow_pos_of_pos hy _ - rw [← Real.rpow_le_rpow_iff hx.le hyz.le hz', ← Real.rpow_mul hy.le] - simp only [ne_of_lt hz, Real.rpow_neg_one, mul_neg, inv_mul_cancel, Ne.def, not_false_iff] - rw [le_inv hxz hy, ← Real.rpow_neg_one, ← Real.rpow_mul hx.le] - simp + rw [← rpow_le_rpow_iff_of_neg _ hx hz, rpow_inv_rpow _ hz.ne] <;> positivity #align real.le_rpow_inv_iff_of_neg Real.le_rpow_inv_iff_of_neg theorem lt_rpow_inv_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x < y ^ z⁻¹ ↔ y < x ^ z := by - have hz' : 0 < -z := by rwa [lt_neg, neg_zero] - have hxz : 0 < x ^ (-z) := Real.rpow_pos_of_pos hx _ - have hyz : 0 < y ^ z⁻¹ := Real.rpow_pos_of_pos hy _ - rw [← Real.rpow_lt_rpow_iff hx.le hyz.le hz', ← Real.rpow_mul hy.le] - simp only [ne_of_lt hz, Real.rpow_neg_one, mul_neg, inv_mul_cancel, Ne.def, not_false_iff] - rw [lt_inv hxz hy, ← Real.rpow_neg_one, ← Real.rpow_mul hx.le] - simp + rw [← rpow_lt_rpow_iff_of_neg _ hx hz, rpow_inv_rpow _ hz.ne] <;> positivity #align real.lt_rpow_inv_iff_of_neg Real.lt_rpow_inv_iff_of_neg theorem rpow_inv_lt_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ^ z⁻¹ < y ↔ y ^ z < x := by - convert lt_rpow_inv_iff_of_neg (Real.rpow_pos_of_pos hx z⁻¹) (Real.rpow_pos_of_pos hy z) hz <;> - simp [← Real.rpow_mul hx.le, ← Real.rpow_mul hy.le, ne_of_lt hz] + rw [← rpow_lt_rpow_iff_of_neg hy _ hz, rpow_inv_rpow _ hz.ne] <;> positivity #align real.rpow_inv_lt_iff_of_neg Real.rpow_inv_lt_iff_of_neg theorem rpow_inv_le_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ^ z⁻¹ ≤ y ↔ y ^ z ≤ x := by - convert le_rpow_inv_iff_of_neg (Real.rpow_pos_of_pos hx z⁻¹) (Real.rpow_pos_of_pos hy z) hz <;> - simp [← Real.rpow_mul hx.le, ← Real.rpow_mul hy.le, ne_of_lt hz] + rw [← rpow_le_rpow_iff_of_neg hy _ hz, rpow_inv_rpow _ hz.ne] <;> positivity #align real.rpow_inv_le_iff_of_neg Real.rpow_inv_le_iff_of_neg theorem rpow_lt_rpow_of_exponent_lt (hx : 1 < x) (hyz : y < z) : x ^ y < x ^ z := by @@ -532,7 +625,7 @@ theorem antitoneOn_rpow_Ioi_of_exponent_nonpos {r : ℝ} (hr : r ≤ 0) : @[simp] theorem rpow_le_rpow_left_iff (hx : 1 < x) : x ^ y ≤ x ^ z ↔ y ≤ z := by have x_pos : 0 < x := lt_trans zero_lt_one hx - rw [← log_le_log (rpow_pos_of_pos x_pos y) (rpow_pos_of_pos x_pos z), log_rpow x_pos, + rw [← log_le_log_iff (rpow_pos_of_pos x_pos y) (rpow_pos_of_pos x_pos z), log_rpow x_pos, log_rpow x_pos, mul_le_mul_right (log_pos hx)] #align real.rpow_le_rpow_left_iff Real.rpow_le_rpow_left_iff @@ -554,7 +647,7 @@ theorem rpow_le_rpow_of_exponent_ge (hx0 : 0 < x) (hx1 : x ≤ 1) (hyz : z ≤ y @[simp] theorem rpow_le_rpow_left_iff_of_base_lt_one (hx0 : 0 < x) (hx1 : x < 1) : x ^ y ≤ x ^ z ↔ z ≤ y := by - rw [← log_le_log (rpow_pos_of_pos hx0 y) (rpow_pos_of_pos hx0 z), log_rpow hx0, log_rpow hx0, + rw [← log_le_log_iff (rpow_pos_of_pos hx0 y) (rpow_pos_of_pos hx0 z), log_rpow hx0, log_rpow hx0, mul_le_mul_right_of_neg (log_neg hx0 hx1)] #align real.rpow_le_rpow_left_iff_of_base_lt_one Real.rpow_le_rpow_left_iff_of_base_lt_one @@ -644,8 +737,17 @@ theorem rpow_left_injOn {x : ℝ} (hx : x ≠ 0) : InjOn (fun y : ℝ => y ^ x) rw [← rpow_one y, ← rpow_one z, ← _root_.mul_inv_cancel hx, rpow_mul hy, rpow_mul hz, hyz] #align real.rpow_left_inj_on Real.rpow_left_injOn +lemma rpow_left_inj (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : z ≠ 0) : x ^ z = y ^ z ↔ x = y := + (rpow_left_injOn hz).eq_iff hx hy + +lemma rpow_inv_eq (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : z ≠ 0) : x ^ z⁻¹ = y ↔ x = y ^ z := by + rw [← rpow_left_inj _ hy hz, rpow_inv_rpow hx hz]; positivity + +lemma eq_rpow_inv (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : z ≠ 0) : x = y ^ z⁻¹ ↔ x ^ z = y := by + rw [← rpow_left_inj hx _ hz, rpow_inv_rpow hy hz]; positivity + theorem le_rpow_iff_log_le (hx : 0 < x) (hy : 0 < y) : x ≤ y ^ z ↔ Real.log x ≤ z * Real.log y := by - rw [← Real.log_le_log hx (Real.rpow_pos_of_pos hy z), Real.log_rpow hy] + rw [← Real.log_le_log_iff hx (Real.rpow_pos_of_pos hy z), Real.log_rpow hy] #align real.le_rpow_iff_log_le Real.le_rpow_iff_log_le theorem le_rpow_of_log_le (hx : 0 ≤ x) (hy : 0 < y) (h : Real.log x ≤ z * Real.log y) : @@ -678,18 +780,6 @@ theorem abs_log_mul_self_rpow_lt (x t : ℝ) (h1 : 0 < x) (h2 : x ≤ 1) (ht : 0 rwa [log_rpow h1, mul_assoc, abs_mul, abs_of_pos ht, mul_comm] at this #align real.abs_log_mul_self_rpow_lt Real.abs_log_mul_self_rpow_lt -theorem pow_nat_rpow_nat_inv {x : ℝ} (hx : 0 ≤ x) {n : ℕ} (hn : n ≠ 0) : - (x ^ n) ^ (n⁻¹ : ℝ) = x := by - have hn0 : (n : ℝ) ≠ 0 := Nat.cast_ne_zero.2 hn - rw [← rpow_nat_cast, ← rpow_mul hx, mul_inv_cancel hn0, rpow_one] -#align real.pow_nat_rpow_nat_inv Real.pow_nat_rpow_nat_inv - -theorem rpow_nat_inv_pow_nat {x : ℝ} (hx : 0 ≤ x) {n : ℕ} (hn : n ≠ 0) : - (x ^ (n⁻¹ : ℝ)) ^ n = x := by - have hn0 : (n : ℝ) ≠ 0 := Nat.cast_ne_zero.2 hn - rw [← rpow_nat_cast, ← rpow_mul hx, inv_mul_cancel hn0, rpow_one] -#align real.rpow_nat_inv_pow_nat Real.rpow_nat_inv_pow_nat - lemma strictMono_rpow_of_base_gt_one {b : ℝ} (hb : 1 < b) : StrictMono (rpow b) := by show StrictMono (fun (x:ℝ) => b ^ x) @@ -756,7 +846,7 @@ theorem exists_rat_pow_btwn_rat_aux (hn : n ≠ 0) (x y : ℝ) (h : x < y) (hy : have hq := this.trans_lt hxq replace hxq := rpow_lt_rpow this hxq hn' replace hqy := rpow_lt_rpow hq.le hqy hn' - rw [rpow_nat_cast, rpow_nat_cast, rpow_nat_inv_pow_nat _ hn] at hxq hqy + rw [rpow_nat_cast, rpow_nat_cast, rpow_inv_natCast_pow _ hn] at hxq hqy · exact ⟨q, mod_cast hq, (le_max_right _ _).trans_lt hxq, hqy⟩ · exact hy.le · exact le_max_left _ _ @@ -866,36 +956,4 @@ section Tactics -- end NormNum -namespace Mathlib.Meta.Positivity - -open Lean Meta Qq - -/-- Extension for the `positivity` tactic: exponentiation by a real number is positive (namely 1) -when the exponent is zero. The other cases are done in `evalRpow`. -/ -@[positivity (_ : ℝ) ^ (0 : ℝ), Pow.pow (_ : ℝ) (0 : ℝ), Real.rpow (_ : ℝ) (0 : ℝ)] -def evalRpowZero : Mathlib.Meta.Positivity.PositivityExt where eval {_ _} _ _ e := do - let .app (.app (f : Q(ℝ → ℝ → ℝ)) (a : Q(ℝ))) (_ : Q(ℝ)) ← withReducible (whnf e) - | throwError "not Real.rpow" - guard <|← withDefault <| withNewMCtxDepth <| isDefEq f q(Real.rpow) - pure (.positive (q(Real.rpow_zero_pos $a) : Expr)) - -/-- Extension for the `positivity` tactic: exponentiation by a real number is nonnegative when -the base is nonnegative and positive when the base is positive. -/ -@[positivity (_ : ℝ) ^ (_ : ℝ), Pow.pow (_ : ℝ) (_ : ℝ), Real.rpow (_ : ℝ) (_ : ℝ)] -def evalRpow : Mathlib.Meta.Positivity.PositivityExt where eval {_ _} zα pα e := do - let .app (.app (f : Q(ℝ → ℝ → ℝ)) (a : Q(ℝ))) (b : Q(ℝ)) ← withReducible (whnf e) - | throwError "not Real.rpow" - guard <|← withDefault <| withNewMCtxDepth <| isDefEq f q(Real.rpow) - let ra ← core zα pα a - match ra with - | .positive pa => - have pa' : Q(0 < $a) := pa - pure (.positive (q(Real.rpow_pos_of_pos $pa' $b) : Expr)) - | .nonnegative pa => - have pa' : Q(0 ≤ $a) := pa - pure (.nonnegative (q(Real.rpow_nonneg_of_nonneg $pa' $b) : Expr)) - | _ => pure .none - -end Mathlib.Meta.Positivity - end Tactics diff --git a/Mathlib/Analysis/SpecialFunctions/Stirling.lean b/Mathlib/Analysis/SpecialFunctions/Stirling.lean index 73b4b04f4e010..695e5114d1e7c 100644 --- a/Mathlib/Analysis/SpecialFunctions/Stirling.lean +++ b/Mathlib/Analysis/SpecialFunctions/Stirling.lean @@ -188,7 +188,7 @@ theorem stirlingSeq'_bounded_by_pos_constant : ∃ a, 0 < a ∧ ∀ n : ℕ, a /-- The sequence `stirlingSeq ∘ succ` is monotone decreasing -/ theorem stirlingSeq'_antitone : Antitone (stirlingSeq ∘ succ) := fun n m h => - (log_le_log (stirlingSeq'_pos m) (stirlingSeq'_pos n)).mp (log_stirlingSeq'_antitone h) + (log_le_log_iff (stirlingSeq'_pos m) (stirlingSeq'_pos n)).mp (log_stirlingSeq'_antitone h) #align stirling.stirling_seq'_antitone Stirling.stirlingSeq'_antitone /-- The limit `a` of the sequence `stirlingSeq` satisfies `0 < a` -/ @@ -229,7 +229,8 @@ theorem stirlingSeq_pow_four_div_stirlingSeq_pow_two_eq (n : ℕ) (hn : n ≠ 0) simp_rw [div_pow, mul_pow] rw [sq_sqrt, sq_sqrt] any_goals positivity - field_simp; ring + field_simp [← exp_nsmul] + ring_nf #align stirling.stirling_seq_pow_four_div_stirling_seq_pow_two_eq Stirling.stirlingSeq_pow_four_div_stirlingSeq_pow_two_eq /-- Suppose the sequence `stirlingSeq` (defined above) has the limit `a ≠ 0`. diff --git a/Mathlib/Combinatorics/Additive/Behrend.lean b/Mathlib/Combinatorics/Additive/Behrend.lean index 2aaf38f36d47b..247a9d984680f 100644 --- a/Mathlib/Combinatorics/Additive/Behrend.lean +++ b/Mathlib/Combinatorics/Additive/Behrend.lean @@ -305,15 +305,11 @@ theorem two_div_one_sub_two_div_e_le_eight : 2 / (1 - 2 / exp 1) ≤ 8 := by #align behrend.two_div_one_sub_two_div_e_le_eight Behrend.two_div_one_sub_two_div_e_le_eight theorem le_sqrt_log (hN : 4096 ≤ N) : log (2 / (1 - 2 / exp 1)) * (69 / 50) ≤ sqrt (log ↑N) := by - have : ((12 : ℕ) : ℝ) * log 2 ≤ log N := by - rw [← log_rpow zero_lt_two, log_le_log, rpow_nat_cast] - · norm_num1 - exact mod_cast hN - · exact rpow_pos_of_pos zero_lt_two _ - rw [cast_pos] - exact hN.trans_lt' (by norm_num1) - refine' (mul_le_mul_of_nonneg_right ((log_le_log _ <| by norm_num1).2 - two_div_one_sub_two_div_e_le_eight) <| by norm_num1).trans _ + have : (12 : ℕ) * log 2 ≤ log N := by + rw [← log_rpow zero_lt_two, rpow_nat_cast] + exact log_le_log (by positivity) (mod_cast hN) + refine (mul_le_mul_of_nonneg_right (log_le_log ?_ two_div_one_sub_two_div_e_le_eight) <| by + norm_num1).trans ?_ · refine' div_pos zero_lt_two _ rw [sub_pos, div_lt_one (exp_pos _)] exact exp_one_gt_d9.trans_le' (by norm_num1) @@ -386,17 +382,15 @@ theorem three_le_nValue (hN : 64 ≤ N) : 3 ≤ nValue N := by have : (2 : ℝ) ^ ((6 : ℕ) : ℝ) ≤ N := by rw [rpow_nat_cast] exact (cast_le.2 hN).trans' (by norm_num1) - apply lt_of_lt_of_le _ ((log_le_log (rpow_pos_of_pos zero_lt_two _) _).2 this) + apply lt_of_lt_of_le _ (log_le_log (rpow_pos_of_pos zero_lt_two _) this) rw [log_rpow zero_lt_two, ← div_lt_iff'] · exact log_two_gt_d9.trans_le' (by norm_num1) · norm_num1 - rw [cast_pos] - exact hN.trans_lt' (by norm_num1) #align behrend.three_le_n_value Behrend.three_le_nValue theorem dValue_pos (hN₃ : 8 ≤ N) : 0 < dValue N := by have hN₀ : 0 < (N : ℝ) := cast_pos.2 (succ_pos'.trans_le hN₃) - rw [dValue, floor_pos, ← log_le_log zero_lt_one, log_one, log_div _ two_ne_zero, log_rpow hN₀, + rw [dValue, floor_pos, ← log_le_log_iff zero_lt_one, log_one, log_div _ two_ne_zero, log_rpow hN₀, inv_mul_eq_div, sub_nonneg, le_div_iff] · have : (nValue N : ℝ) ≤ 2 * sqrt (log N) := by apply (ceil_lt_add_one <| sqrt_nonneg _).le.trans @@ -408,9 +402,7 @@ theorem dValue_pos (hN₃ : 8 ≤ N) : 0 < dValue N := by rw [← mul_assoc, ← le_div_iff (Real.sqrt_pos.2 <| log_pos <| one_lt_cast.2 _), div_sqrt] · apply log_two_mul_two_le_sqrt_log_eight.trans apply Real.sqrt_le_sqrt - rw [log_le_log _ hN₀] - · exact mod_cast hN₃ - · norm_num + exact log_le_log (by norm_num) (mod_cast hN₃) exact hN₃.trans_lt' (by norm_num) · exact cast_pos.2 (nValue_pos <| hN₃.trans' <| by norm_num) · exact (rpow_pos_of_pos hN₀ _).ne' @@ -436,7 +428,7 @@ set_option linter.uppercaseLean3 false in theorem bound (hN : 4096 ≤ N) : (N : ℝ) ^ (nValue N : ℝ)⁻¹ / exp 1 < dValue N := by apply div_lt_floor _ - rw [← log_le_log, log_rpow, mul_comm, ← div_eq_mul_inv] + rw [← log_le_log_iff, log_rpow, mul_comm, ← div_eq_mul_inv] · apply le_trans _ (div_le_div_of_le_left _ _ (ceil_lt_mul _).le) rw [mul_comm, ← div_div, div_sqrt, le_div_iff] · norm_num; exact le_sqrt_log hN @@ -449,13 +441,9 @@ theorem bound (hN : 4096 ≤ N) : (N : ℝ) ^ (nValue N : ℝ)⁻¹ / exp 1 < dV rw [one_lt_cast] exact hN.trans_lt' (by norm_num1) apply le_sqrt_of_sq_le - have : ((12 : ℕ) : ℝ) * log 2 ≤ log N := by - rw [← log_rpow zero_lt_two, log_le_log, rpow_nat_cast] - · norm_num1 - exact mod_cast hN - · exact rpow_pos_of_pos zero_lt_two _ - rw [cast_pos] - exact hN.trans_lt' (by norm_num1) + have : (12 : ℕ) * log 2 ≤ log N := by + rw [← log_rpow zero_lt_two, rpow_nat_cast] + exact log_le_log (by positivity) (mod_cast hN) refine' le_trans _ this rw [← div_le_iff'] · exact log_two_gt_d9.le.trans' (by norm_num1) @@ -465,9 +453,7 @@ theorem bound (hN : 4096 ≤ N) : (N : ℝ) ^ (nValue N : ℝ)⁻¹ / exp 1 < dV · refine' div_pos zero_lt_two _ rw [sub_pos, div_lt_one (exp_pos _)] exact lt_of_le_of_lt (by norm_num1) exp_one_gt_d9 - apply rpow_pos_of_pos - rw [cast_pos] - exact hN.trans_lt' (by norm_num1) + positivity #align behrend.bound Behrend.bound theorem roth_lower_bound_explicit (hN : 4096 ≤ N) : @@ -520,7 +506,7 @@ theorem four_zero_nine_six_lt_exp_sixteen : 4096 < exp 16 := by theorem lower_bound_le_one' (hN : 2 ≤ N) (hN' : N ≤ 4096) : (N : ℝ) * exp (-4 * sqrt (log N)) ≤ 1 := by - rw [← log_le_log (mul_pos (cast_pos.2 (zero_lt_two.trans_le hN)) (exp_pos _)) zero_lt_one, + rw [← log_le_log_iff (mul_pos (cast_pos.2 (zero_lt_two.trans_le hN)) (exp_pos _)) zero_lt_one, log_one, log_mul (cast_pos.2 (zero_lt_two.trans_le hN)).ne' (exp_pos _).ne', log_exp, neg_mul, ← sub_eq_add_neg, sub_nonpos, ← div_le_iff (Real.sqrt_pos.2 <| log_pos <| one_lt_cast.2 <| one_lt_two.trans_le hN), div_sqrt, diff --git a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean index 191629749c7b8..8a595d5a9522b 100644 --- a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean +++ b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean @@ -302,7 +302,7 @@ lemma one_add_smoothingFn_le_two {x : ℝ} (hx : exp 1 ≤ x) : 1 + ε x ≤ 2 : _ ≤ x := hx rw [div_le_one (log_pos this)] calc 1 = log (exp 1) := by simp - _ ≤ log x := log_le_log' (exp_pos _) hx + _ ≤ log x := log_le_log (exp_pos _) hx lemma isLittleO_smoothingFn_one : ε =o[atTop] (fun _ => (1:ℝ)) := by unfold smoothingFn diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index 5c3bddf507301..dd362c906dc7a 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -541,6 +541,9 @@ theorem exp_sum {α : Type*} (s : Finset α) (f : α → ℂ) : @map_prod (Multiplicative ℂ) α ℂ _ _ _ _ expMonoidHom f s #align complex.exp_sum Complex.exp_sum +lemma exp_nsmul (x : ℂ) (n : ℕ) : exp (n • x) = exp x ^ n := + @MonoidHom.map_pow (Multiplicative ℂ) ℂ _ _ expMonoidHom _ _ + theorem exp_nat_mul (x : ℂ) : ∀ n : ℕ, exp (n * x) = exp x ^ n | 0 => by rw [Nat.cast_zero, zero_mul, exp_zero, pow_zero] | Nat.succ n => by rw [pow_succ', Nat.cast_add_one, add_mul, exp_add, ← exp_nat_mul _ n, one_mul] @@ -1159,6 +1162,9 @@ theorem exp_sum {α : Type*} (s : Finset α) (f : α → ℝ) : @map_prod (Multiplicative ℝ) α ℝ _ _ _ _ expMonoidHom f s #align real.exp_sum Real.exp_sum +lemma exp_nsmul (x : ℝ) (n : ℕ) : exp (n • x) = exp x ^ n := + @MonoidHom.map_pow (Multiplicative ℝ) ℝ _ _ expMonoidHom _ _ + nonrec theorem exp_nat_mul (x : ℝ) (n : ℕ) : exp (n * x) = exp x ^ n := ofReal_injective (by simp [exp_nat_mul]) #align real.exp_nat_mul Real.exp_nat_mul From ef00edadfeb7fc4653f8a8b3e5c218fc5cd1a228 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Dec 2023 16:45:05 +0000 Subject: [PATCH 076/353] feat(LinearAlgebra/CliffordAlgebra): invertibility of quadratic form elements (#9076) This also includes a lemma about transferring invertibility of the base ring between algebras. --- Mathlib/Algebra/Algebra/Basic.lean | 24 +++++++++++++++++++ .../CliffordAlgebra/Inversion.lean | 21 +++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Mathlib/Algebra/Algebra/Basic.lean b/Mathlib/Algebra/Algebra/Basic.lean index 98887d9eb5146..65c7c472ed9ec 100644 --- a/Mathlib/Algebra/Algebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Basic.lean @@ -924,3 +924,27 @@ end Module example {R A} [CommSemiring R] [Semiring A] [Module R A] [SMulCommClass R A A] [IsScalarTower R A A] : Algebra R A := Algebra.ofModule smul_mul_assoc mul_smul_comm + +section invertibility + +variable {R A B : Type*} +variable [CommSemiring R] [Semiring A] [Semiring B] [Algebra R A] [Algebra R B] + +/-- If there is a linear map `f : A →ₗ[R] B` that preserves `1`, then `algebraMap R B r` is +invertible when `algebraMap R A r` is. -/ +abbrev Invertible.algebraMapOfInvertibleAlgebraMap (f : A →ₗ[R] B) (hf : f 1 = 1) {r : R} + (h : Invertible (algebraMap R A r)) : Invertible (algebraMap R B r) where + invOf := f ⅟(algebraMap R A r) + invOf_mul_self := by rw [← Algebra.commutes, ← Algebra.smul_def, ← map_smul, Algebra.smul_def, + mul_invOf_self, hf] + mul_invOf_self := by rw [← Algebra.smul_def, ← map_smul, Algebra.smul_def, mul_invOf_self, hf] + +/-- If there is a linear map `f : A →ₗ[R] B` that preserves `1`, then `algebraMap R B r` is +a unit when `algebraMap R A r` is. -/ +lemma IsUnit.algebraMap_of_algebraMap (f : A →ₗ[R] B) (hf : f 1 = 1) {r : R} + (h : IsUnit (algebraMap R A r)) : IsUnit (algebraMap R B r) := + let ⟨i⟩ := nonempty_invertible h + letI := Invertible.algebraMapOfInvertibleAlgebraMap f hf i + isUnit_of_invertible _ + +end invertibility diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Inversion.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Inversion.lean index 8e82f4defd9c4..923d4985f9062 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Inversion.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Inversion.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ -import Mathlib.LinearAlgebra.CliffordAlgebra.Basic +import Mathlib.LinearAlgebra.CliffordAlgebra.Contraction /-! # Results about inverses in Clifford algebras @@ -54,4 +54,23 @@ theorem invOf_ι_mul_ι_mul_ι (a b : M) [Invertible (ι Q a)] [Invertible (Q a) smul_smul, smul_smul, invOf_mul_self, one_smul] #align clifford_algebra.inv_of_ι_mul_ι_mul_ι CliffordAlgebra.invOf_ι_mul_ι_mul_ι +section +variable [Invertible (2 : R)] + +/-- Over a ring where `2` is invertible, `Q m` is invertible whenever `ι Q m`. -/ +def invertibleOfInvertibleι (m : M) [Invertible (ι Q m)] : Invertible (Q m) := + ExteriorAlgebra.invertibleAlgebraMapEquiv M (Q m) <| + .algebraMapOfInvertibleAlgebraMap (equivExterior Q).toLinearMap (by simp) <| + .copy (.mul ‹Invertible (ι Q m)› ‹Invertible (ι Q m)›) _ (ι_sq_scalar _ _).symm + +theorem isUnit_of_isUnit_ι {m : M} (h : IsUnit (ι Q m)) : IsUnit (Q m) := by + cases h.nonempty_invertible + letI := invertibleOfInvertibleι Q m + exact isUnit_of_invertible (Q m) + +@[simp] theorem isUnit_ι_iff {m : M} : IsUnit (ι Q m) ↔ IsUnit (Q m) := + ⟨isUnit_of_isUnit_ι Q, isUnit_ι_of_isUnit Q⟩ + +end + end CliffordAlgebra From 9bf055e57c1bfa7c2daf0be2ae10352deb79c80b Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 19 Dec 2023 16:45:06 +0000 Subject: [PATCH 077/353] refactor(Topology/IsLocalHomeomorph): various small clean-ups (#9150) - revamp and extend the module docstring - add some lemma docstrings - use EqOn where possible - use \mapsto instead of => - replace one terminal rfl by the explicit lemma invoked --- Mathlib/Topology/IsLocalHomeomorph.lean | 42 +++++++++++++++---------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/Mathlib/Topology/IsLocalHomeomorph.lean b/Mathlib/Topology/IsLocalHomeomorph.lean index 4348b9b62e049..b6445d9ad5987 100644 --- a/Mathlib/Topology/IsLocalHomeomorph.lean +++ b/Mathlib/Topology/IsLocalHomeomorph.lean @@ -15,12 +15,19 @@ This file defines local homeomorphisms. ## Main definitions -* `IsLocalHomeomorph`: A function `f : X → Y` satisfies `IsLocalHomeomorph` if for each - point `x : X`, the restriction of `f` to some open neighborhood `U` of `x` gives a homeomorphism +For a function `f : X → Y ` between topological spaces, we say +* `IsLocalHomeomorphOn f s` if `f` is a local homeomorphism around each point of `s`: for each + `x : X`, the restriction of `f` to some open neighborhood `U` of `x` gives a homeomorphism between `U` and an open subset of `Y`. +* `IsLocalHomeomorph f`: `f` is a local homeomorphism, i.e. it's a local homeomorphism on `univ`. + +Note that `IsLocalHomeomorph` is a global condition. This is in contrast to +`PartialHomeomorph`, which is a homeomorphism between specific open subsets. + +## Main results +* local homeomorphisms are locally injective open maps +* more! - Note that `IsLocalHomeomorph` is a global condition. This is in contrast to - `PartialHomeomorph`, which is a homeomorphism between specific open subsets. -/ @@ -56,24 +63,24 @@ namespace IsLocalHomeomorphOn /-- Proves that `f` satisfies `IsLocalHomeomorphOn f s`. The condition `h` is weaker than the definition of `IsLocalHomeomorphOn f s`, since it only requires `e : PartialHomeomorph X Y` to agree with `f` on its source `e.source`, as opposed to on the whole space `X`. -/ -theorem mk (h : ∀ x ∈ s, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ ∀ y ∈ e.source, f y = e y) : +theorem mk (h : ∀ x ∈ s, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ Set.EqOn f e e.source) : IsLocalHomeomorphOn f s := by intro x hx obtain ⟨e, hx, he⟩ := h x hx exact ⟨{ e with toFun := f - map_source' := fun x hx => by rw [he x hx]; exact e.map_source' hx - left_inv' := fun x hx => by rw [he x hx]; exact e.left_inv' hx - right_inv' := fun y hy => by rw [he _ (e.map_target' hy)]; exact e.right_inv' hy + map_source' := fun _x hx ↦ by rw [he hx]; exact e.map_source' hx + left_inv' := fun _x hx ↦ by rw [he hx]; exact e.left_inv' hx + right_inv' := fun _y hy ↦ by rw [he (e.map_target' hy)]; exact e.right_inv' hy continuousOn_toFun := (continuousOn_congr he).mpr e.continuousOn_toFun }, hx, rfl⟩ #align is_locally_homeomorph_on.mk IsLocalHomeomorphOn.mk variable {g f s t} -theorem mono {t : Set X} (hf : IsLocalHomeomorphOn f t) (hst : s ⊆ t) : - IsLocalHomeomorphOn f s := fun x hx ↦ hf x (hst hx) +theorem mono {t : Set X} (hf : IsLocalHomeomorphOn f t) (hst : s ⊆ t) : IsLocalHomeomorphOn f s := + fun x hx ↦ hf x (hst hx) theorem of_comp_left (hgf : IsLocalHomeomorphOn (g ∘ f) s) (hg : IsLocalHomeomorphOn g (f '' s)) (cont : ∀ x ∈ s, ContinuousAt f x) : IsLocalHomeomorphOn f s := mk f s fun x hx ↦ by @@ -84,8 +91,7 @@ theorem of_comp_left (hgf : IsLocalHomeomorphOn (g ∘ f) s) (hg : IsLocalHomeom fun y hy ↦ ?_⟩ change f y = g.symm (gf y) have : f y ∈ g.source := by apply interior_subset hy.1.2 - rw [← he, g.eq_symm_apply this (by apply g.map_source this)] - rfl + rw [← he, g.eq_symm_apply this (by apply g.map_source this), Function.comp_apply] theorem of_comp_right (hgf : IsLocalHomeomorphOn (g ∘ f) s) (hf : IsLocalHomeomorphOn f s) : IsLocalHomeomorphOn g (f '' s) := mk g _ <| by @@ -108,7 +114,7 @@ protected theorem continuousAt (hf : IsLocalHomeomorphOn f s) {x : X} (hx : x #align is_locally_homeomorph_on.continuous_at IsLocalHomeomorphOn.continuousAt protected theorem continuousOn (hf : IsLocalHomeomorphOn f s) : ContinuousOn f s := - ContinuousAt.continuousOn fun _x => hf.continuousAt + ContinuousAt.continuousOn fun _x ↦ hf.continuousAt #align is_locally_homeomorph_on.continuous_on IsLocalHomeomorphOn.continuousOn protected theorem comp (hg : IsLocalHomeomorphOn g t) (hf : IsLocalHomeomorphOn f s) @@ -157,10 +163,10 @@ namespace IsLocalHomeomorph /-- Proves that `f` satisfies `IsLocalHomeomorph f`. The condition `h` is weaker than the definition of `IsLocalHomeomorph f`, since it only requires `e : PartialHomeomorph X Y` to agree with `f` on its source `e.source`, as opposed to on the whole space `X`. -/ -theorem mk (h : ∀ x : X, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ ∀ y ∈ e.source, f y = e y) : +theorem mk (h : ∀ x : X, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ Set.EqOn f e e.source) : IsLocalHomeomorph f := isLocalHomeomorph_iff_isLocalHomeomorphOn_univ.mpr - (IsLocalHomeomorphOn.mk f Set.univ fun x _hx => h x) + (IsLocalHomeomorphOn.mk f Set.univ fun x _hx ↦ h x) #align is_locally_homeomorph.mk IsLocalHomeomorph.mk variable {g f} @@ -177,20 +183,24 @@ theorem map_nhds_eq (hf : IsLocalHomeomorph f) (x : X) : (𝓝 x).map f = 𝓝 ( hf.isLocalHomeomorphOn.map_nhds_eq (Set.mem_univ x) #align is_locally_homeomorph.map_nhds_eq IsLocalHomeomorph.map_nhds_eq +/-- A local homeomorphism is continuous. -/ protected theorem continuous (hf : IsLocalHomeomorph f) : Continuous f := continuous_iff_continuousOn_univ.mpr hf.isLocalHomeomorphOn.continuousOn #align is_locally_homeomorph.continuous IsLocalHomeomorph.continuous +/-- A local homeomorphism is an open map. -/ protected theorem isOpenMap (hf : IsLocalHomeomorph f) : IsOpenMap f := - IsOpenMap.of_nhds_le fun x => ge_of_eq (hf.map_nhds_eq x) + IsOpenMap.of_nhds_le fun x ↦ ge_of_eq (hf.map_nhds_eq x) #align is_locally_homeomorph.is_open_map IsLocalHomeomorph.isOpenMap +/-- The composition of local homeomorphisms is a local homeomorphism. -/ protected theorem comp (hg : IsLocalHomeomorph g) (hf : IsLocalHomeomorph f) : IsLocalHomeomorph (g ∘ f) := isLocalHomeomorph_iff_isLocalHomeomorphOn_univ.mpr (hg.isLocalHomeomorphOn.comp hf.isLocalHomeomorphOn (Set.univ.mapsTo_univ f)) #align is_locally_homeomorph.comp IsLocalHomeomorph.comp +/-- An injective local homeomorphism is an open embedding. -/ theorem openEmbedding_of_injective (hf : IsLocalHomeomorph f) (hi : f.Injective) : OpenEmbedding f := openEmbedding_of_continuous_injective_open hf.continuous hi hf.isOpenMap From e851153f5f010e15a4af4913d9503e622a51273b Mon Sep 17 00:00:00 2001 From: Jujian Zhang Date: Tue, 19 Dec 2023 17:29:48 +0000 Subject: [PATCH 078/353] feat(Data/Finset/Card): the number of element satisfying `P` is no greater than `n` iff every subset with more than `n` elements contains an element not satisfying `P` (#9048) --- Mathlib/Data/Finset/Card.lean | 5 +++++ Mathlib/Data/Multiset/Basic.lean | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean index eae91f1518a91..cf1d121c7c88d 100644 --- a/Mathlib/Data/Finset/Card.lean +++ b/Mathlib/Data/Finset/Card.lean @@ -267,6 +267,11 @@ theorem fiber_card_ne_zero_iff_mem_image (s : Finset α) (f : α → β) [Decida rw [← pos_iff_ne_zero, card_pos, fiber_nonempty_iff_mem_image] #align finset.fiber_card_ne_zero_iff_mem_image Finset.fiber_card_ne_zero_iff_mem_image +lemma card_filter_le_iff (s : Finset α) (P : α → Prop) [DecidablePred P] (n : ℕ) : + (s.filter P).card ≤ n ↔ ∀ s' ⊆ s, n < s'.card → ∃ a ∈ s', ¬ P a := + (s.1.card_filter_le_iff P n).trans ⟨fun H s' hs' h ↦ H s'.1 (by aesop) h, + fun H s' hs' h ↦ H ⟨s', nodup_of_le hs' s.2⟩ (fun x hx ↦ subset_of_le hs' hx) h⟩ + @[simp] theorem card_map (f : α ↪ β) : (s.map f).card = s.card := Multiset.card_map _ _ diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index f06e54b530b97..c94f2c45bc695 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -2154,6 +2154,16 @@ lemma map_filter' {f : α → β} (hf : Injective f) (s : Multiset α) simp [(· ∘ ·), map_filter, hf.eq_iff] #align multiset.map_filter' Multiset.map_filter' +lemma card_filter_le_iff (s : Multiset α) (P : α → Prop) [DecidablePred P] (n : ℕ) : + card (s.filter P) ≤ n ↔ ∀ s' ≤ s, n < card s' → ∃ a ∈ s', ¬ P a := by + fconstructor + · intro H s' hs' s'_card + by_contra! rid + have card := card_le_of_le (monotone_filter_left P hs') |>.trans H + exact s'_card.not_le (filter_eq_self.mpr rid ▸ card) + · contrapose! + exact fun H ↦ ⟨s.filter P, filter_le _ _, H, fun a ha ↦ (mem_filter.mp ha).2⟩ + /-! ### Simultaneously filter and map elements of a multiset -/ From 363e9f6e2664389844b297373e084213553574b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Dec 2023 21:09:56 +0000 Subject: [PATCH 079/353] feat: Relative Sylow's first theorems (#8944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prove variants of Sylow' first theorem relative to a subgroup. From PFR Co-authored-by: Sébastien Gouëzel --- Mathlib/GroupTheory/PGroup.lean | 2 ++ Mathlib/GroupTheory/Sylow.lean | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Mathlib/GroupTheory/PGroup.lean b/Mathlib/GroupTheory/PGroup.lean index 4b61b066635fd..261210b0e8032 100644 --- a/Mathlib/GroupTheory/PGroup.lean +++ b/Mathlib/GroupTheory/PGroup.lean @@ -67,6 +67,8 @@ theorem iff_card [Fact p.Prime] [Fintype G] : IsPGroup p G ↔ ∃ n : ℕ, card exact (hq1.pow_eq_iff.mp (hg.symm.trans hk).symm).1.symm #align is_p_group.iff_card IsPGroup.iff_card +alias ⟨exists_card_eq, _⟩ := iff_card + section GIsPGroup variable (hG : IsPGroup p G) diff --git a/Mathlib/GroupTheory/Sylow.lean b/Mathlib/GroupTheory/Sylow.lean index 830b5c9577724..3b95deaa7c007 100644 --- a/Mathlib/GroupTheory/Sylow.lean +++ b/Mathlib/GroupTheory/Sylow.lean @@ -653,6 +653,33 @@ theorem exists_subgroup_card_pow_prime [Fintype G] (p : ℕ) {n : ℕ} [Fact p.P ⟨K, hK.1⟩ #align sylow.exists_subgroup_card_pow_prime Sylow.exists_subgroup_card_pow_prime +lemma exists_subgroup_card_pow_prime_of_le_card {m p : ℕ} (hp : p.Prime) (h : IsPGroup p G) + (hm : p ^ m ≤ Nat.card G) : ∃ H : Subgroup G, Nat.card H = p ^ m := by + have : Fact p.Prime := ⟨hp⟩ + have : Finite G := Nat.finite_of_card_ne_zero $ by linarith [Nat.one_le_pow m p hp.pos] + cases nonempty_fintype G + obtain ⟨n, hn⟩ := h.exists_card_eq + simp_rw [Nat.card_eq_fintype_card] at hn hm ⊢ + refine exists_subgroup_card_pow_prime _ ?_ + rw [hn] at hm ⊢ + exact pow_dvd_pow _ $ (pow_le_pow_iff_right hp.one_lt).1 hm + +lemma exists_subgroup_le_card_pow_prime_of_le_card {m p : ℕ} (hp : p.Prime) (h : IsPGroup p G) + {H : Subgroup G} (hm : p ^ m ≤ Nat.card H) : ∃ H' ≤ H, Nat.card H' = p ^ m := by + obtain ⟨H', H'card⟩ := exists_subgroup_card_pow_prime_of_le_card hp (h.to_subgroup H) hm + refine ⟨H'.map H.subtype, map_subtype_le _, ?_⟩ + rw [← H'card] + let e : H' ≃* H'.map H.subtype := H'.equivMapOfInjective (Subgroup.subtype H) H.subtype_injective + exact Nat.card_congr e.symm.toEquiv + +lemma exists_subgroup_le_card_le {k p : ℕ} (hp : p.Prime) (h : IsPGroup p G) {H : Subgroup G} + (hk : k ≤ Nat.card H) (hk₀ : k ≠ 0) : ∃ H' ≤ H, Nat.card H' ≤ k ∧ k < p * Nat.card H' := by + obtain ⟨m, hmk, hkm⟩ : ∃ s, p ^ s ≤ k ∧ k < p ^ (s + 1) := + exists_nat_pow_near (Nat.one_le_iff_ne_zero.2 hk₀) hp.one_lt + obtain ⟨H', H'H, H'card⟩ := exists_subgroup_le_card_pow_prime_of_le_card hp h (hmk.trans hk) + refine ⟨H', H'H, ?_⟩ + simpa only [pow_succ, H'card] using And.intro hmk hkm + theorem pow_dvd_card_of_pow_dvd_card [Fintype G] {p n : ℕ} [hp : Fact p.Prime] (P : Sylow p G) (hdvd : p ^ n ∣ card G) : p ^ n ∣ card P := (hp.1.coprime_pow_of_not_dvd From b8e33bbb048dce1b1d5742c0eee4ba8bcfc032b8 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Wed, 20 Dec 2023 00:53:37 +0000 Subject: [PATCH 080/353] feat: add `ContinuousMap.compStarAlgHom`, postcomposition by a `StarAlgHom` (#8992) --- .../Topology/ContinuousFunction/Algebra.lean | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/Mathlib/Topology/ContinuousFunction/Algebra.lean b/Mathlib/Topology/ContinuousFunction/Algebra.lean index 84639edf7dd3a..7016e0cf2cff1 100644 --- a/Mathlib/Topology/ContinuousFunction/Algebra.lean +++ b/Mathlib/Topology/ContinuousFunction/Algebra.lean @@ -969,6 +969,9 @@ theorem star_apply (f : C(α, β)) (x : α) : star f x = star (f x) := rfl #align continuous_map.star_apply ContinuousMap.star_apply +instance instTrivialStar [TrivialStar β] : TrivialStar C(α, β) where + star_trivial _ := ext fun _ => star_trivial _ + end Star instance [InvolutiveStar β] [ContinuousStar β] : InvolutiveStar C(α, β) where @@ -992,12 +995,11 @@ instance [Star R] [Star β] [SMul R β] [StarModule R β] [ContinuousStar β] end StarStructure -variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] +section Precomposition +variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] variable (𝕜 : Type*) [CommSemiring 𝕜] - -variable (A : Type*) [TopologicalSpace A] [Semiring A] [TopologicalSemiring A] [StarRing A] - +variable (A : Type*) [TopologicalSpace A] [Semiring A] [TopologicalSemiring A] [Star A] variable [ContinuousStar A] [Algebra 𝕜 A] /-- The functorial map taking `f : C(X, Y)` to `C(Y, A) →⋆ₐ[𝕜] C(X, A)` given by pre-composition @@ -1028,8 +1030,47 @@ theorem compStarAlgHom'_comp (g : C(Y, Z)) (f : C(X, Y)) : StarAlgHom.ext fun _ => ContinuousMap.ext fun _ => rfl #align continuous_map.comp_star_alg_hom'_comp ContinuousMap.compStarAlgHom'_comp +end Precomposition + +section Postcomposition + +variable (X : Type*) {𝕜 A B C : Type*} [TopologicalSpace X] [CommSemiring 𝕜] +variable [TopologicalSpace A] [Semiring A] [TopologicalSemiring A] [Star A] +variable [ContinuousStar A] [Algebra 𝕜 A] +variable [TopologicalSpace B] [Semiring B] [TopologicalSemiring B] [Star B] +variable [ContinuousStar B] [Algebra 𝕜 B] +variable [TopologicalSpace C] [Semiring C] [TopologicalSemiring C] [Star C] +variable [ContinuousStar C] [Algebra 𝕜 C] + +/-- Post-composition with a continuous star algebra homomorphism is a star algebra homomorphism +between spaces of continuous maps. -/ +@[simps] +def compStarAlgHom (φ : A →⋆ₐ[𝕜] B) (hφ : Continuous φ) : + C(X, A) →⋆ₐ[𝕜] C(X, B) where + toFun f := (⟨φ, hφ⟩ : C(A, B)).comp f + map_one' := ext fun _ => map_one φ + map_mul' f g := ext fun x => map_mul φ (f x) (g x) + map_zero' := ext fun _ => map_zero φ + map_add' f g := ext fun x => map_add φ (f x) (g x) + commutes' r := ext fun _x => AlgHomClass.commutes φ r + map_star' f := ext fun x => map_star φ (f x) + +/-- `ContinuousMap.compStarAlgHom` sends the identity `StarAlgHom` on `A` to the identity +`StarAlgHom` on `C(X, A)`. -/ +lemma compStarAlgHom_id : compStarAlgHom X (.id 𝕜 A) continuous_id = .id 𝕜 C(X, A) := rfl + +/-- `ContinuousMap.compStarAlgHom` is functorial. -/ +lemma compStarAlgHom_comp (φ : A →⋆ₐ[𝕜] B) (ψ : B →⋆ₐ[𝕜] C) (hφ : Continuous φ) + (hψ : Continuous ψ) : compStarAlgHom X (ψ.comp φ) (hψ.comp hφ) = + (compStarAlgHom X ψ hψ).comp (compStarAlgHom X φ hφ) := + rfl + +end Postcomposition + section Periodicity +variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + /-! ### Summing translates of a function -/ /-- Summing the translates of `f` by `ℤ • p` gives a map which is periodic with period `p`. From aa81039c00f36b4b95f392f99749038ae24c2747 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 20 Dec 2023 13:47:32 +1100 Subject: [PATCH 081/353] fix --- Mathlib/Data/Bool/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Data/Bool/Basic.lean b/Mathlib/Data/Bool/Basic.lean index 50bddc60ebbe1..a9dfbd43d4cd1 100644 --- a/Mathlib/Data/Bool/Basic.lean +++ b/Mathlib/Data/Bool/Basic.lean @@ -47,8 +47,8 @@ theorem of_decide_iff {p : Prop} [Decidable p] : decide p ↔ p := coe_decide p #align bool.of_to_bool_iff Bool.of_decide_iff -#align bool.tt_eq_to_bool_iff Bool.true_eq_decide_iff -#align bool.ff_eq_to_bool_iff Bool.false_eq_decide_iff +#align bool.tt_eq_to_bool_iff true_eq_decide_iff +#align bool.ff_eq_to_bool_iff false_eq_decide_iff theorem decide_not (p : Prop) [Decidable p] : (decide ¬p) = !(decide p) := by by_cases p <;> simp [*] From 00e9c211d461b2ed2da0dd4c75f6421daf5ee1b8 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 20 Dec 2023 13:55:07 +1100 Subject: [PATCH 082/353] fixes --- Mathlib/Data/List/Basic.lean | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index df16f00de16cd..3e7ff55772748 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -1077,10 +1077,6 @@ section IndexOf variable [DecidableEq α] --- Porting note: simp can prove this --- @[simp] -theorem indexOf_nil (a : α) : indexOf a [] = 0 := - rfl #align list.index_of_nil List.indexOf_nil /- @@ -1111,18 +1107,16 @@ theorem indexOf_cons_ne {a b : α} (l : List α) : b ≠ a → indexOf a (b :: l | h => by simp only [indexOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq, h, ite_false] #align list.index_of_cons_ne List.indexOf_cons_ne --- rfl -theorem indexOf_cons (a b : α) (l : List α) : - indexOf a (b :: l) = if b = a then 0 else succ (indexOf a l) := by - simp only [indexOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq] #align list.index_of_cons List.indexOf_cons theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by induction' l with b l ih · exact iff_of_true rfl (not_mem_nil _) - simp only [length, mem_cons, indexOf_cons, eq_comm]; split_ifs with h - · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h - · simp only [h, false_or_iff] + simp only [length, mem_cons, indexOf_cons, eq_comm] + rw [cond_eq_if] + split_ifs with h <;> simp at h + · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm + · simp only [Ne.symm h, false_or_iff] rw [← ih] exact succ_inj' #align list.index_of_eq_length List.indexOf_eq_length @@ -1134,7 +1128,7 @@ theorem indexOf_of_not_mem {l : List α} {a : α} : a ∉ l → indexOf a l = le theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by induction' l with b l ih; · rfl - simp only [length, indexOf_cons] + simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq] by_cases h : b = a · rw [if_pos h]; exact Nat.zero_le _ · rw [if_neg h]; exact succ_le_succ ih @@ -1340,7 +1334,7 @@ theorem ext_nthLe {l₁ l₂ : List α} (hl : length l₁ = length l₂) theorem indexOf_get [DecidableEq α] {a : α} : ∀ {l : List α} (h), get l ⟨indexOf a l, h⟩ = a | b :: l, h => by by_cases h' : b = a <;> - simp only [h', if_pos, if_false, indexOf_cons, get, @indexOf_get _ _ l] + simp only [h', if_pos, if_false, indexOf_cons, get, @indexOf_get _ _ l, cond_eq_if, beq_iff_eq] @[simp, deprecated indexOf_get] theorem indexOf_nthLe [DecidableEq α] {a : α} : ∀ {l : List α} (h), nthLe l (indexOf a l) h = a := From 742b9be50fd6338c1ddc6d924dfd71da4b2ef902 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 20 Dec 2023 14:10:33 +1100 Subject: [PATCH 083/353] fix --- Mathlib/Data/List/MinMax.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index 06313430b3b7d..b83e55c766e29 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -213,6 +213,7 @@ theorem index_of_argmax : simp_all rw [h] at hm dsimp only at hm + simp only [cond_eq_if, beq_iff_eq] obtain ha | ha := ha <;> split_ifs at hm <;> injection hm with hm <;> subst hm · cases not_le_of_lt ‹_› ‹_› · rw [if_pos rfl] From 641b78156808b3ef87f52c7295f3f55a0d72cdaf Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 20 Dec 2023 14:12:56 +1100 Subject: [PATCH 084/353] fix --- Mathlib/Computability/Halting.lean | 2 +- Mathlib/Computability/Partrec.lean | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Computability/Halting.lean b/Mathlib/Computability/Halting.lean index f11bae6d30b62..755dccdae6d70 100644 --- a/Mathlib/Computability/Halting.lean +++ b/Mathlib/Computability/Halting.lean @@ -258,7 +258,7 @@ theorem computable_iff_re_compl_re {p : α → Prop} [DecidablePred p] : · refine' Partrec.of_eq pk fun n => Part.eq_some_iff.2 _ rw [hk] simp only [Part.mem_map_iff, Part.mem_assert_iff, Part.mem_some_iff, exists_prop, and_true, - Bool.true_eq_decide_iff, and_self, exists_const, Bool.false_eq_decide_iff] + true_eq_decide_iff, and_self, exists_const, false_eq_decide_iff] apply Decidable.em⟩⟩ #align computable_pred.computable_iff_re_compl_re ComputablePred.computable_iff_re_compl_re diff --git a/Mathlib/Computability/Partrec.lean b/Mathlib/Computability/Partrec.lean index 34494aed64279..44bcfcec9636f 100644 --- a/Mathlib/Computability/Partrec.lean +++ b/Mathlib/Computability/Partrec.lean @@ -225,7 +225,7 @@ theorem ppred : Partrec fun n => ppred n := simp [show 0 ≠ m.succ by intro h; injection h] at h · refine' eq_some_iff.2 _ simp only [mem_rfind, not_true, IsEmpty.forall_iff, decide_True, mem_some_iff, - Bool.false_eq_decide_iff, true_and] + false_eq_decide_iff, true_and] intro m h simp [ne_of_gt h] #align nat.partrec.ppred Nat.Partrec.ppred From c7d8e53c026257a9ec1682083edee71b773eab46 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 20 Dec 2023 14:13:42 +1100 Subject: [PATCH 085/353] fixes --- Mathlib/Computability/TMToPartrec.lean | 4 ++-- Mathlib/NumberTheory/SmoothNumbers.lean | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Computability/TMToPartrec.lean b/Mathlib/Computability/TMToPartrec.lean index 0ef38d450e7ff..4818e9c1406e8 100644 --- a/Mathlib/Computability/TMToPartrec.lean +++ b/Mathlib/Computability/TMToPartrec.lean @@ -341,9 +341,9 @@ theorem exists_code {n} {f : Vector ℕ n →. ℕ} (hf : Nat.Partrec' f) : refine' Part.ext fun x => _ simp only [rfind, Part.bind_eq_bind, Part.pure_eq_some, Part.map_eq_map, Part.bind_some, exists_prop, cons_eval, comp_eval, fix_eval, tail_eval, succ_eval, zero'_eval, - List.headI_nil, List.headI_cons, pred_eval, Part.map_some, Bool.false_eq_decide_iff, + List.headI_nil, List.headI_cons, pred_eval, Part.map_some, false_eq_decide_iff, Part.mem_bind_iff, List.length, Part.mem_map_iff, Nat.mem_rfind, List.tail_nil, - List.tail_cons, Bool.true_eq_decide_iff, Part.mem_some_iff, Part.map_bind] + List.tail_cons, true_eq_decide_iff, Part.mem_some_iff, Part.map_bind] constructor · rintro ⟨v', h1, rfl⟩ suffices ∀ v₁ : List ℕ, v' ∈ PFun.fix diff --git a/Mathlib/NumberTheory/SmoothNumbers.lean b/Mathlib/NumberTheory/SmoothNumbers.lean index 1089b4254847e..9caa0b7f660dc 100644 --- a/Mathlib/NumberTheory/SmoothNumbers.lean +++ b/Mathlib/NumberTheory/SmoothNumbers.lean @@ -152,7 +152,7 @@ def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) : have : m.factors.filter (· = p) = m.factors.filter (¬ · < p) · refine (filter_congr' <| fun q hq ↦ ?_).symm have H : ¬ p < q := fun hf ↦ Nat.lt_le_asymm hf <| lt_succ_iff.mp (hm q hq) - simp only [not_lt, le_iff_eq_or_lt, H, or_false, eq_comm, Bool.true_eq_decide_iff] + simp only [not_lt, le_iff_eq_or_lt, H, or_false, eq_comm, true_eq_decide_iff] refine prod_eq <| (filter_eq m.factors p).symm ▸ this ▸ perm_append_comm.trans ?_ convert filter_append_perm .. simp only [not_lt] From 3f93618efe0e23ebaa39b88e28a5297940088690 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 20 Dec 2023 09:20:41 +0000 Subject: [PATCH 086/353] chore: bump Std to match leanprover/std4#438 (#9157) Co-authored-by: Scott Morrison Co-authored-by: Mario Carneiro --- Mathlib/Computability/Halting.lean | 2 +- Mathlib/Computability/Partrec.lean | 2 +- Mathlib/Computability/TMToPartrec.lean | 4 ++-- Mathlib/Data/Bool/Basic.lean | 4 ++-- Mathlib/Data/List/Basic.lean | 20 +++++++------------- Mathlib/Data/List/MinMax.lean | 1 + Mathlib/NumberTheory/SmoothNumbers.lean | 2 +- lake-manifest.json | 2 +- 8 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Mathlib/Computability/Halting.lean b/Mathlib/Computability/Halting.lean index f11bae6d30b62..755dccdae6d70 100644 --- a/Mathlib/Computability/Halting.lean +++ b/Mathlib/Computability/Halting.lean @@ -258,7 +258,7 @@ theorem computable_iff_re_compl_re {p : α → Prop} [DecidablePred p] : · refine' Partrec.of_eq pk fun n => Part.eq_some_iff.2 _ rw [hk] simp only [Part.mem_map_iff, Part.mem_assert_iff, Part.mem_some_iff, exists_prop, and_true, - Bool.true_eq_decide_iff, and_self, exists_const, Bool.false_eq_decide_iff] + true_eq_decide_iff, and_self, exists_const, false_eq_decide_iff] apply Decidable.em⟩⟩ #align computable_pred.computable_iff_re_compl_re ComputablePred.computable_iff_re_compl_re diff --git a/Mathlib/Computability/Partrec.lean b/Mathlib/Computability/Partrec.lean index 34494aed64279..44bcfcec9636f 100644 --- a/Mathlib/Computability/Partrec.lean +++ b/Mathlib/Computability/Partrec.lean @@ -225,7 +225,7 @@ theorem ppred : Partrec fun n => ppred n := simp [show 0 ≠ m.succ by intro h; injection h] at h · refine' eq_some_iff.2 _ simp only [mem_rfind, not_true, IsEmpty.forall_iff, decide_True, mem_some_iff, - Bool.false_eq_decide_iff, true_and] + false_eq_decide_iff, true_and] intro m h simp [ne_of_gt h] #align nat.partrec.ppred Nat.Partrec.ppred diff --git a/Mathlib/Computability/TMToPartrec.lean b/Mathlib/Computability/TMToPartrec.lean index 0ef38d450e7ff..4818e9c1406e8 100644 --- a/Mathlib/Computability/TMToPartrec.lean +++ b/Mathlib/Computability/TMToPartrec.lean @@ -341,9 +341,9 @@ theorem exists_code {n} {f : Vector ℕ n →. ℕ} (hf : Nat.Partrec' f) : refine' Part.ext fun x => _ simp only [rfind, Part.bind_eq_bind, Part.pure_eq_some, Part.map_eq_map, Part.bind_some, exists_prop, cons_eval, comp_eval, fix_eval, tail_eval, succ_eval, zero'_eval, - List.headI_nil, List.headI_cons, pred_eval, Part.map_some, Bool.false_eq_decide_iff, + List.headI_nil, List.headI_cons, pred_eval, Part.map_some, false_eq_decide_iff, Part.mem_bind_iff, List.length, Part.mem_map_iff, Nat.mem_rfind, List.tail_nil, - List.tail_cons, Bool.true_eq_decide_iff, Part.mem_some_iff, Part.map_bind] + List.tail_cons, true_eq_decide_iff, Part.mem_some_iff, Part.map_bind] constructor · rintro ⟨v', h1, rfl⟩ suffices ∀ v₁ : List ℕ, v' ∈ PFun.fix diff --git a/Mathlib/Data/Bool/Basic.lean b/Mathlib/Data/Bool/Basic.lean index 50bddc60ebbe1..a9dfbd43d4cd1 100644 --- a/Mathlib/Data/Bool/Basic.lean +++ b/Mathlib/Data/Bool/Basic.lean @@ -47,8 +47,8 @@ theorem of_decide_iff {p : Prop} [Decidable p] : decide p ↔ p := coe_decide p #align bool.of_to_bool_iff Bool.of_decide_iff -#align bool.tt_eq_to_bool_iff Bool.true_eq_decide_iff -#align bool.ff_eq_to_bool_iff Bool.false_eq_decide_iff +#align bool.tt_eq_to_bool_iff true_eq_decide_iff +#align bool.ff_eq_to_bool_iff false_eq_decide_iff theorem decide_not (p : Prop) [Decidable p] : (decide ¬p) = !(decide p) := by by_cases p <;> simp [*] diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index df16f00de16cd..3e7ff55772748 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -1077,10 +1077,6 @@ section IndexOf variable [DecidableEq α] --- Porting note: simp can prove this --- @[simp] -theorem indexOf_nil (a : α) : indexOf a [] = 0 := - rfl #align list.index_of_nil List.indexOf_nil /- @@ -1111,18 +1107,16 @@ theorem indexOf_cons_ne {a b : α} (l : List α) : b ≠ a → indexOf a (b :: l | h => by simp only [indexOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq, h, ite_false] #align list.index_of_cons_ne List.indexOf_cons_ne --- rfl -theorem indexOf_cons (a b : α) (l : List α) : - indexOf a (b :: l) = if b = a then 0 else succ (indexOf a l) := by - simp only [indexOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq] #align list.index_of_cons List.indexOf_cons theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by induction' l with b l ih · exact iff_of_true rfl (not_mem_nil _) - simp only [length, mem_cons, indexOf_cons, eq_comm]; split_ifs with h - · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h - · simp only [h, false_or_iff] + simp only [length, mem_cons, indexOf_cons, eq_comm] + rw [cond_eq_if] + split_ifs with h <;> simp at h + · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm + · simp only [Ne.symm h, false_or_iff] rw [← ih] exact succ_inj' #align list.index_of_eq_length List.indexOf_eq_length @@ -1134,7 +1128,7 @@ theorem indexOf_of_not_mem {l : List α} {a : α} : a ∉ l → indexOf a l = le theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by induction' l with b l ih; · rfl - simp only [length, indexOf_cons] + simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq] by_cases h : b = a · rw [if_pos h]; exact Nat.zero_le _ · rw [if_neg h]; exact succ_le_succ ih @@ -1340,7 +1334,7 @@ theorem ext_nthLe {l₁ l₂ : List α} (hl : length l₁ = length l₂) theorem indexOf_get [DecidableEq α] {a : α} : ∀ {l : List α} (h), get l ⟨indexOf a l, h⟩ = a | b :: l, h => by by_cases h' : b = a <;> - simp only [h', if_pos, if_false, indexOf_cons, get, @indexOf_get _ _ l] + simp only [h', if_pos, if_false, indexOf_cons, get, @indexOf_get _ _ l, cond_eq_if, beq_iff_eq] @[simp, deprecated indexOf_get] theorem indexOf_nthLe [DecidableEq α] {a : α} : ∀ {l : List α} (h), nthLe l (indexOf a l) h = a := diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index 06313430b3b7d..b83e55c766e29 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -213,6 +213,7 @@ theorem index_of_argmax : simp_all rw [h] at hm dsimp only at hm + simp only [cond_eq_if, beq_iff_eq] obtain ha | ha := ha <;> split_ifs at hm <;> injection hm with hm <;> subst hm · cases not_le_of_lt ‹_› ‹_› · rw [if_pos rfl] diff --git a/Mathlib/NumberTheory/SmoothNumbers.lean b/Mathlib/NumberTheory/SmoothNumbers.lean index 1089b4254847e..9caa0b7f660dc 100644 --- a/Mathlib/NumberTheory/SmoothNumbers.lean +++ b/Mathlib/NumberTheory/SmoothNumbers.lean @@ -152,7 +152,7 @@ def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) : have : m.factors.filter (· = p) = m.factors.filter (¬ · < p) · refine (filter_congr' <| fun q hq ↦ ?_).symm have H : ¬ p < q := fun hf ↦ Nat.lt_le_asymm hf <| lt_succ_iff.mp (hm q hq) - simp only [not_lt, le_iff_eq_or_lt, H, or_false, eq_comm, Bool.true_eq_decide_iff] + simp only [not_lt, le_iff_eq_or_lt, H, or_false, eq_comm, true_eq_decide_iff] refine prod_eq <| (filter_eq m.factors p).symm ▸ this ▸ perm_append_comm.trans ?_ convert filter_append_perm .. simp only [not_lt] diff --git a/lake-manifest.json b/lake-manifest.json index a90df0d688464..2a1a96e4db936 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "9dd24a3493cceefa2bede383f21e4ef548990b68", + "rev": "71e11a6be0e43dabcba416e1af15b5bbbbfc9dde", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", From a82f629c8354cc57fbe427584d854543e129302e Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Wed, 20 Dec 2023 10:02:36 +0000 Subject: [PATCH 087/353] chore: bump to nightly-2023-12-20 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 2dfbd8295af30..2b934e4208fd3 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-19 +leanprover/lean4:nightly-2023-12-20 From 95ddd8942a0d4a5522b7d70738cb3e31df717be5 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Wed, 20 Dec 2023 10:04:48 +0000 Subject: [PATCH 088/353] chore: tidy various files (#9016) --- .../Computation/ApproximationCorollaries.lean | 10 +-- .../NormedSpace/Multilinear/Basic.lean | 3 +- Mathlib/Condensed/Explicit.lean | 2 +- Mathlib/FieldTheory/RatFunc.lean | 2 +- Mathlib/Logic/Equiv/Defs.lean | 2 +- .../Constructions/BorelSpace/Basic.lean | 11 +-- .../Constructions/Prod/Basic.lean | 6 +- .../Decomposition/SignedLebesgue.lean | 78 ++++++++----------- .../Measure/HasOuterApproxClosed.lean | 4 +- .../MeasureTheory/Measure/VectorMeasure.lean | 17 +++- Mathlib/NumberTheory/Divisors.lean | 5 +- Mathlib/Order/SupIndep.lean | 4 +- Mathlib/RingTheory/Finiteness.lean | 11 +-- Mathlib/RingTheory/Localization/Basic.lean | 11 +-- .../RingTheory/Localization/FractionRing.lean | 2 +- Mathlib/Testing/SlimCheck/Functions.lean | 34 ++++---- .../UniformConvergenceTopology.lean | 2 +- 17 files changed, 103 insertions(+), 101 deletions(-) diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean b/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean index 3ebe9757195df..27f58562ab426 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean @@ -99,7 +99,7 @@ open Nat theorem of_convergence_epsilon : ∀ ε > (0 : K), ∃ N : ℕ, ∀ n ≥ N, |v - (of v).convergents n| < ε := by intro ε ε_pos - -- use the archimedean property to obtian a suitable N + -- use the archimedean property to obtain a suitable N rcases (exists_nat_gt (1 / ε) : ∃ N' : ℕ, 1 / ε < N') with ⟨N', one_div_ε_lt_N'⟩ let N := max N' 5 -- set minimum to 5 to have N ≤ fib N work @@ -115,7 +115,7 @@ theorem of_convergence_epsilon : let nB := g.denominators (n + 1) have abs_v_sub_conv_le : |v - g.convergents n| ≤ 1 / (B * nB) := abs_sub_convergents_le not_terminated_at_n - suffices : 1 / (B * nB) < ε; exact lt_of_le_of_lt abs_v_sub_conv_le this + suffices 1 / (B * nB) < ε from lt_of_le_of_lt abs_v_sub_conv_le this -- show that `0 < (B * nB)` and then multiply by `B * nB` to get rid of the division have nB_ineq : (fib (n + 2) : K) ≤ nB := haveI : ¬g.TerminatedAt (n + 1 - 1) := not_terminated_at_n @@ -126,10 +126,10 @@ theorem of_convergence_epsilon : have zero_lt_B : 0 < B := B_ineq.trans_lt' $ mod_cast fib_pos.2 n.succ_pos have nB_pos : 0 < nB := nB_ineq.trans_lt' $ mod_cast fib_pos.2 $ succ_pos _ have zero_lt_mul_conts : 0 < B * nB := by positivity - suffices : 1 < ε * (B * nB); exact (div_lt_iff zero_lt_mul_conts).mpr this - -- use that `N ≥ n` was obtained from the archimedean property to show the following + suffices 1 < ε * (B * nB) from (div_lt_iff zero_lt_mul_conts).mpr this + -- use that `N' ≥ n` was obtained from the archimedean property to show the following calc 1 < ε * (N' : K) := (div_lt_iff' ε_pos).mp one_div_ε_lt_N' - _ ≤ ε * (B * nB) := ?_ + _ ≤ ε * (B * nB) := ?_ -- cancel `ε` gcongr calc diff --git a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean index 193888790ef6c..508e3a1bdf050 100644 --- a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean +++ b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean @@ -494,8 +494,7 @@ section theorem norm_ofSubsingleton [Subsingleton ι] (i : ι) (f : G →L[𝕜] G') : ‖ofSubsingleton 𝕜 G G' i f‖ = ‖f‖ := by letI : Unique ι := uniqueOfSubsingleton i - simp only [norm_def, ContinuousLinearMap.norm_def, (Equiv.funUnique _ _).symm.surjective.forall, - Fintype.prod_subsingleton _ i]; rfl + simp [norm_def, ContinuousLinearMap.norm_def, (Equiv.funUnique _ _).symm.surjective.forall] @[simp] theorem nnnorm_ofSubsingleton [Subsingleton ι] (i : ι) (f : G →L[𝕜] G') : diff --git a/Mathlib/Condensed/Explicit.lean b/Mathlib/Condensed/Explicit.lean index e83935d583441..191d57b9867c9 100644 --- a/Mathlib/Condensed/Explicit.lean +++ b/Mathlib/Condensed/Explicit.lean @@ -21,7 +21,7 @@ We give the following three explicit descriptions of condensed sets: * `Condensed.ofSheafStonean`: A finite-product-preserving presheaf on `CompHaus`, satisfying `EqualizerCondition`. -The property `EqualizerCondition` is defined in `Mathlib/CategoryTheory/Sites/RegularExtensive` +The property `EqualizerCondition` is defined in `Mathlib/CategoryTheory/Sites/RegularExtensive.lean` and it says that for any effective epi `X ⟶ B` (in this case that is equivalent to being a continuous surjection), the presheaf `F` exhibits `F(B)` as the equalizer of the two maps `F(X) ⇉ F(X ×_B X)` diff --git a/Mathlib/FieldTheory/RatFunc.lean b/Mathlib/FieldTheory/RatFunc.lean index b4edc9a70cdf7..52b7364155cc5 100644 --- a/Mathlib/FieldTheory/RatFunc.lean +++ b/Mathlib/FieldTheory/RatFunc.lean @@ -1284,7 +1284,7 @@ theorem num_denom_mul (x y : RatFunc K) : #align ratfunc.num_denom_mul RatFunc.num_denom_mul theorem num_dvd {x : RatFunc K} {p : K[X]} (hp : p ≠ 0) : - num x ∣ p ↔ ∃ (q : K[X]) (_ : q ≠ 0), x = algebraMap _ _ p / algebraMap _ _ q := by + num x ∣ p ↔ ∃ q : K[X], q ≠ 0 ∧ x = algebraMap _ _ p / algebraMap _ _ q := by constructor · rintro ⟨q, rfl⟩ obtain ⟨_hx, hq⟩ := mul_ne_zero_iff.mp hp diff --git a/Mathlib/Logic/Equiv/Defs.lean b/Mathlib/Logic/Equiv/Defs.lean index 6bf9c137dbc8a..3963650a42f8f 100644 --- a/Mathlib/Logic/Equiv/Defs.lean +++ b/Mathlib/Logic/Equiv/Defs.lean @@ -630,7 +630,7 @@ def piUnique [Unique α] (β : α → Sort*) : (∀ i, β i) ≃ β default wher right_inv x := rfl /-- If `α` has a unique term, then the type of function `α → β` is equivalent to `β`. -/ -@[simps! (config := .asFn) apply] +@[simps! (config := .asFn) apply symm_apply] def funUnique (α β) [Unique.{u} α] : (α → β) ≃ β := piUnique _ #align equiv.fun_unique Equiv.funUnique #align equiv.fun_unique_apply Equiv.funUnique_apply diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index 3a0489aaaa9b7..1859d0aabf727 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -101,11 +101,11 @@ theorem TopologicalSpace.IsTopologicalBasis.borel_eq_generateFrom [TopologicalSp borel_eq_generateFrom_of_subbasis hs.eq_generateFrom #align topological_space.is_topological_basis.borel_eq_generate_from TopologicalSpace.IsTopologicalBasis.borel_eq_generateFrom -theorem isPiSystem_isOpen [TopologicalSpace α] : IsPiSystem (IsOpen : Set α → Prop) := +theorem isPiSystem_isOpen [TopologicalSpace α] : IsPiSystem ({s : Set α | IsOpen s}) := fun _s hs _t ht _ => IsOpen.inter hs ht #align is_pi_system_is_open isPiSystem_isOpen -lemma isPiSystem_isClosed [TopologicalSpace α] : IsPiSystem (IsClosed : Set α → Prop) := +lemma isPiSystem_isClosed [TopologicalSpace α] : IsPiSystem ({s : Set α | IsClosed s}) := fun _s hs _t ht _ ↦ IsClosed.inter hs ht theorem borel_eq_generateFrom_isClosed [TopologicalSpace α] : @@ -130,7 +130,9 @@ theorem borel_eq_generateFrom_Iio : borel α = .generateFrom (range Iio) := by letI : MeasurableSpace α := MeasurableSpace.generateFrom (range Iio) have H : ∀ a : α, MeasurableSet (Iio a) := fun a => GenerateMeasurable.basic _ ⟨_, rfl⟩ refine' generateFrom_le _ - rintro _ ⟨a, rfl | rfl⟩ <;> [skip; apply H] + rintro _ ⟨a, rfl | rfl⟩ + swap + · apply H by_cases h : ∃ a', ∀ b, a < b ↔ a' ≤ b · rcases h with ⟨a', ha'⟩ rw [(_ : Ioi a = (Iio a')ᶜ)] @@ -151,7 +153,6 @@ theorem borel_eq_generateFrom_Iio : borel α = .generateFrom (range Iio) := by ⟨fun ab => le_of_not_lt fun h' => h ⟨b, ab, h'⟩, lt_of_lt_of_le ax⟩⟩) with ⟨a', h₁, h₂⟩ · exact ⟨a', h₁, le_of_lt h₂⟩ rw [this] - skip apply MeasurableSet.iUnion exact fun _ => (H _).compl · rw [forall_range_iff] @@ -1285,7 +1286,7 @@ protected theorem Monotone.measurable [LinearOrder β] [OrderClosedTopology β] theorem aemeasurable_restrict_of_monotoneOn [LinearOrder β] [OrderClosedTopology β] {μ : Measure β} {s : Set β} (hs : MeasurableSet s) {f : β → α} (hf : MonotoneOn f s) : AEMeasurable f (μ.restrict s) := - have : Monotone (f ∘ (↑) : s → α) := fun ⟨x, hx⟩ ⟨y, hy⟩=> fun (hxy : x ≤ y) => hf hx hy hxy + have : Monotone (f ∘ (↑) : s → α) := fun ⟨x, hx⟩ ⟨y, hy⟩ => fun (hxy : x ≤ y) => hf hx hy hxy aemeasurable_restrict_of_measurable_subtype hs this.measurable #align ae_measurable_restrict_of_monotone_on aemeasurable_restrict_of_monotoneOn diff --git a/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean b/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean index f4f2064acf9d4..72fb2c01d96f1 100644 --- a/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean @@ -694,7 +694,7 @@ theorem prodAssoc_prod [SFinite τ] : (sFiniteSeq μ p.1.1).prod ((sFiniteSeq ν p.1.2).prod (sFiniteSeq τ p.2))) := by ext s hs rw [sum_apply _ hs, sum_apply _ hs, ← (Equiv.prodAssoc _ _ _).tsum_eq] - rfl + simp only [Equiv.prodAssoc_apply] rw [← sum_sFiniteSeq μ, ← sum_sFiniteSeq ν, ← sum_sFiniteSeq τ, prod_sum, prod_sum, map_sum MeasurableEquiv.prodAssoc.measurable.aemeasurable, prod_sum, prod_sum, this] congr @@ -820,8 +820,8 @@ theorem skew_product [SFinite μa] [SFinite μc] {f : α → β} (hf : MeasurePr ← hf.lintegral_comp (measurable_measure_prod_mk_left hs)] apply lintegral_congr_ae filter_upwards [hg] with a ha - rw [← ha, map_apply hgm.of_uncurry_left (measurable_prod_mk_left hs)] - rfl + rw [← ha, map_apply hgm.of_uncurry_left (measurable_prod_mk_left hs), preimage_preimage, + preimage_preimage] #align measure_theory.measure_preserving.skew_product MeasureTheory.MeasurePreserving.skew_product /-- If `f : α → β` sends the measure `μa` to `μb` and `g : γ → δ` sends the measure `μc` to `μd`, diff --git a/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean b/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean index 2d7ffe0b4235d..d5d43fd1a86d3 100644 --- a/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean +++ b/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean @@ -130,8 +130,7 @@ theorem singularPart_mutuallySingular (s : SignedMeasure α) (μ : Measure α) : s.toJordanDecomposition.posPart.singularPart μ ⟂ₘ s.toJordanDecomposition.negPart.singularPart μ := by by_cases hl : s.HaveLebesgueDecomposition μ - · haveI := hl - obtain ⟨i, hi, hpos, hneg⟩ := s.toJordanDecomposition.mutuallySingular + · obtain ⟨i, hi, hpos, hneg⟩ := s.toJordanDecomposition.mutuallySingular rw [s.toJordanDecomposition.posPart.haveLebesgueDecomposition_add μ] at hpos rw [s.toJordanDecomposition.negPart.haveLebesgueDecomposition_add μ] at hneg rw [add_apply, add_eq_zero_iff] at hpos hneg @@ -153,16 +152,14 @@ theorem singularPart_totalVariation (s : SignedMeasure α) (μ : Measure α) : ⟨s.toJordanDecomposition.posPart.singularPart μ, s.toJordanDecomposition.negPart.singularPart μ, singularPart_mutuallySingular s μ⟩ := by refine' JordanDecomposition.toSignedMeasure_injective _ - rw [toSignedMeasure_toJordanDecomposition] - rfl + rw [toSignedMeasure_toJordanDecomposition, singularPart, JordanDecomposition.toSignedMeasure] · rw [totalVariation, this] #align measure_theory.signed_measure.singular_part_total_variation MeasureTheory.SignedMeasure.singularPart_totalVariation nonrec theorem mutuallySingular_singularPart (s : SignedMeasure α) (μ : Measure α) : singularPart s μ ⟂ᵥ μ.toENNRealVectorMeasure := by - rw [mutuallySingular_ennreal_iff, singularPart_totalVariation] - change _ ⟂ₘ VectorMeasure.equivMeasure.toFun (VectorMeasure.equivMeasure.invFun μ) - rw [VectorMeasure.equivMeasure.right_inv μ] + rw [mutuallySingular_ennreal_iff, singularPart_totalVariation, + VectorMeasure.ennrealToMeasure_toENNRealVectorMeasure] exact (mutuallySingular_singularPart _ _).add_left (mutuallySingular_singularPart _ _) #align measure_theory.signed_measure.mutually_singular_singular_part MeasureTheory.SignedMeasure.mutuallySingular_singularPart @@ -208,8 +205,8 @@ variable (s μ) /-- **The Lebesgue Decomposition theorem between a signed measure and a measure**: Given a signed measure `s` and a σ-finite measure `μ`, there exist a signed measure `t` and a measurable and integrable function `f`, such that `t` is mutually singular with respect to `μ` -and `s = t + μ.with_densityᵥ f`. In this case `t = s.singular_part μ` and -`f = s.rn_deriv μ`. -/ +and `s = t + μ.withDensityᵥ f`. In this case `t = s.singularPart μ` and +`f = s.rnDeriv μ`. -/ theorem singularPart_add_withDensity_rnDeriv_eq [s.HaveLebesgueDecomposition μ] : s.singularPart μ + μ.withDensityᵥ (s.rnDeriv μ) = s := by conv_rhs => @@ -239,11 +236,8 @@ theorem jordanDecomposition_add_withDensity_mutuallySingular {f : α → ℝ} (h (htμ : t ⟂ᵥ μ.toENNRealVectorMeasure) : (t.toJordanDecomposition.posPart + μ.withDensity fun x : α => ENNReal.ofReal (f x)) ⟂ₘ t.toJordanDecomposition.negPart + μ.withDensity fun x : α => ENNReal.ofReal (-f x) := by - rw [mutuallySingular_ennreal_iff, totalVariation_mutuallySingular_iff] at htμ - change - _ ⟂ₘ VectorMeasure.equivMeasure.toFun (VectorMeasure.equivMeasure.invFun μ) ∧ - _ ⟂ₘ VectorMeasure.equivMeasure.toFun (VectorMeasure.equivMeasure.invFun μ) at htμ - rw [VectorMeasure.equivMeasure.right_inv] at htμ + rw [mutuallySingular_ennreal_iff, totalVariation_mutuallySingular_iff, + VectorMeasure.ennrealToMeasure_toENNRealVectorMeasure] at htμ exact ((JordanDecomposition.mutuallySingular _).add_right (htμ.1.mono_ac (refl _) (withDensity_absolutelyContinuous _ _))).add_left @@ -308,20 +302,17 @@ private theorem eq_singularPart' (t : SignedMeasure α) {f : α → ℝ} (hf : M (hfi : Integrable f μ) (htμ : t ⟂ᵥ μ.toENNRealVectorMeasure) (hadd : s = t + μ.withDensityᵥ f) : t = s.singularPart μ := by have htμ' := htμ - rw [mutuallySingular_ennreal_iff, totalVariation_mutuallySingular_iff] at htμ - change - _ ⟂ₘ VectorMeasure.equivMeasure.toFun (VectorMeasure.equivMeasure.invFun μ) ∧ - _ ⟂ₘ VectorMeasure.equivMeasure.toFun (VectorMeasure.equivMeasure.invFun μ) at htμ - rw [VectorMeasure.equivMeasure.right_inv] at htμ - · rw [singularPart, ← t.toSignedMeasure_toJordanDecomposition, - JordanDecomposition.toSignedMeasure] - congr - · have hfpos : Measurable fun x => ENNReal.ofReal (f x) := by measurability - refine' eq_singularPart hfpos htμ.1 _ - rw [toJordanDecomposition_eq_of_eq_add_withDensity hf hfi htμ' hadd] - · have hfneg : Measurable fun x => ENNReal.ofReal (-f x) := by measurability - refine' eq_singularPart hfneg htμ.2 _ - rw [toJordanDecomposition_eq_of_eq_add_withDensity hf hfi htμ' hadd] + rw [mutuallySingular_ennreal_iff, totalVariation_mutuallySingular_iff, + VectorMeasure.ennrealToMeasure_toENNRealVectorMeasure] at htμ + rw [singularPart, ← t.toSignedMeasure_toJordanDecomposition, + JordanDecomposition.toSignedMeasure] + congr + · have hfpos : Measurable fun x => ENNReal.ofReal (f x) := by measurability + refine' eq_singularPart hfpos htμ.1 _ + rw [toJordanDecomposition_eq_of_eq_add_withDensity hf hfi htμ' hadd] + · have hfneg : Measurable fun x => ENNReal.ofReal (-f x) := by measurability + refine' eq_singularPart hfneg htμ.2 _ + rw [toJordanDecomposition_eq_of_eq_add_withDensity hf hfi htμ' hadd] /-- Given a measure `μ`, signed measures `s` and `t`, and a function `f` such that `t` is mutually singular with respect to `μ` and `s = t + μ.withDensityᵥ f`, we have @@ -371,21 +362,22 @@ theorem singularPart_smul_nnreal (s : SignedMeasure α) (μ : Measure α) (r : nonrec theorem singularPart_smul (s : SignedMeasure α) (μ : Measure α) (r : ℝ) : (r • s).singularPart μ = r • s.singularPart μ := by - by_cases hr : 0 ≤ r - · lift r to ℝ≥0 using hr + cases le_or_lt 0 r with + | inl hr => + lift r to ℝ≥0 using hr exact singularPart_smul_nnreal s μ r - · rw [singularPart, singularPart] + | inr hr => + rw [singularPart, singularPart] conv_lhs => congr · congr · rw [toJordanDecomposition_smul_real, - JordanDecomposition.real_smul_posPart_neg _ _ (not_le.1 hr), singularPart_smul] + JordanDecomposition.real_smul_posPart_neg _ _ hr, singularPart_smul] · congr · rw [toJordanDecomposition_smul_real, - JordanDecomposition.real_smul_negPart_neg _ _ (not_le.1 hr), singularPart_smul] - rw [toSignedMeasure_smul, toSignedMeasure_smul, ← neg_sub, ← smul_sub] - change -(((-r).toNNReal : ℝ) • (_ : SignedMeasure α)) = _ - rw [← neg_smul, Real.coe_toNNReal _ (le_of_lt (neg_pos.mpr (not_le.1 hr))), neg_neg] + JordanDecomposition.real_smul_negPart_neg _ _ hr, singularPart_smul] + rw [toSignedMeasure_smul, toSignedMeasure_smul, ← neg_sub, ← smul_sub, NNReal.smul_def, + ← neg_smul, Real.coe_toNNReal _ (le_of_lt (neg_pos.mpr hr)), neg_neg] #align measure_theory.signed_measure.singular_part_smul MeasureTheory.SignedMeasure.singularPart_smul theorem singularPart_add (s t : SignedMeasure α) (μ : Measure α) [s.HaveLebesgueDecomposition μ] @@ -395,8 +387,8 @@ theorem singularPart_add (s t : SignedMeasure α) (μ : Measure α) [s.HaveLebes (eq_singularPart _ (s.rnDeriv μ + t.rnDeriv μ) ((mutuallySingular_singularPart s μ).add_left (mutuallySingular_singularPart t μ)) _).symm - erw [withDensityᵥ_add (integrable_rnDeriv s μ) (integrable_rnDeriv t μ)] - rw [add_assoc, add_comm (t.singularPart μ), add_assoc, add_comm _ (t.singularPart μ), + rw [withDensityᵥ_add (integrable_rnDeriv s μ) (integrable_rnDeriv t μ), add_assoc, + add_comm (t.singularPart μ), add_assoc, add_comm _ (t.singularPart μ), singularPart_add_withDensity_rnDeriv_eq, ← add_assoc, singularPart_add_withDensity_rnDeriv_eq] #align measure_theory.signed_measure.singular_part_add MeasureTheory.SignedMeasure.singularPart_add @@ -417,7 +409,7 @@ theorem eq_rnDeriv (t : SignedMeasure α) (f : α → ℝ) (hfi : Integrable f have hadd' : s = t + μ.withDensityᵥ f' := by convert hadd using 2 exact WithDensityᵥEq.congr_ae hfi.1.ae_eq_mk.symm - haveI := haveLebesgueDecomposition_mk μ hfi.1.measurable_mk htμ hadd' + have := haveLebesgueDecomposition_mk μ hfi.1.measurable_mk htμ hadd' refine' (Integrable.ae_eq_of_withDensityᵥ_eq (integrable_rnDeriv _ _) hfi _).symm rw [← add_right_inj t, ← hadd, eq_singularPart _ f htμ hadd, singularPart_add_withDensity_rnDeriv_eq] @@ -437,11 +429,9 @@ theorem rnDeriv_smul (s : SignedMeasure α) (μ : Measure α) [s.HaveLebesgueDec refine' Integrable.ae_eq_of_withDensityᵥ_eq (integrable_rnDeriv _ _) ((integrable_rnDeriv _ _).smul r) _ - change _ = μ.withDensityᵥ ((r : ℝ) • s.rnDeriv μ) - rw [withDensityᵥ_smul (rnDeriv s μ) (r : ℝ), ← add_right_inj ((r • s).singularPart μ), - singularPart_add_withDensity_rnDeriv_eq, singularPart_smul] - change _ = _ + r • _ - rw [← smul_add, singularPart_add_withDensity_rnDeriv_eq] + rw [withDensityᵥ_smul (rnDeriv s μ) r, ← add_right_inj ((r • s).singularPart μ), + singularPart_add_withDensity_rnDeriv_eq, singularPart_smul, ← smul_add, + singularPart_add_withDensity_rnDeriv_eq] #align measure_theory.signed_measure.rn_deriv_smul MeasureTheory.SignedMeasure.rnDeriv_smul theorem rnDeriv_add (s t : SignedMeasure α) (μ : Measure α) [s.HaveLebesgueDecomposition μ] diff --git a/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean b/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean index 11f3a47892f38..6edc67e0db2ad 100644 --- a/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean +++ b/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean @@ -210,10 +210,11 @@ theorem measure_isClosed_eq_of_forall_lintegral_eq_of_isFiniteMeasure {Ω : Type (h : ∀ (f : Ω →ᵇ ℝ≥0), ∫⁻ x, f x ∂μ = ∫⁻ x, f x ∂ν) {F : Set Ω} (F_closed : IsClosed F) : μ F = ν F := by have ν_finite : IsFiniteMeasure ν := by + constructor have whole := h 1 simp only [BoundedContinuousFunction.coe_one, Pi.one_apply, coe_one, lintegral_const, one_mul] at whole - refine ⟨by simpa [← whole] using IsFiniteMeasure.measure_univ_lt_top⟩ + simpa [← whole] using IsFiniteMeasure.measure_univ_lt_top have obs_μ := HasOuterApproxClosed.tendsto_lintegral_apprSeq F_closed μ have obs_ν := HasOuterApproxClosed.tendsto_lintegral_apprSeq F_closed ν simp_rw [h] at obs_μ @@ -231,7 +232,6 @@ theorem ext_of_forall_lintegral_eq_of_IsFiniteMeasure {Ω : Type*} · exact fun F F_closed ↦ key F_closed · exact key isClosed_univ · rw [BorelSpace.measurable_eq (α := Ω), borel_eq_generateFrom_isClosed] - rfl end MeasureTheory -- namespace diff --git a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean index 69aedbea53977..32477fa432965 100644 --- a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean @@ -521,6 +521,17 @@ theorem ennrealToMeasure_apply {m : MeasurableSpace α} {v : VectorMeasure α rw [ennrealToMeasure, ofMeasurable_apply _ hs] #align measure_theory.vector_measure.ennreal_to_measure_apply MeasureTheory.VectorMeasure.ennrealToMeasure_apply +@[simp] +theorem _root_.MeasureTheory.Measure.toENNRealVectorMeasure_ennrealToMeasure + (μ : VectorMeasure α ℝ≥0∞) : + toENNRealVectorMeasure (ennrealToMeasure μ) = μ := ext fun s hs => by + rw [toENNRealVectorMeasure_apply_measurable hs, ennrealToMeasure_apply hs] + +@[simp] +theorem ennrealToMeasure_toENNRealVectorMeasure (μ : Measure α) : + ennrealToMeasure (toENNRealVectorMeasure μ) = μ := Measure.ext fun s hs => by + rw [ennrealToMeasure_apply hs, toENNRealVectorMeasure_apply_measurable hs] + /-- The equiv between `VectorMeasure α ℝ≥0∞` and `Measure α` formed by `MeasureTheory.VectorMeasure.ennrealToMeasure` and `MeasureTheory.Measure.toENNRealVectorMeasure`. -/ @@ -528,10 +539,8 @@ theorem ennrealToMeasure_apply {m : MeasurableSpace α} {v : VectorMeasure α def equivMeasure [MeasurableSpace α] : VectorMeasure α ℝ≥0∞ ≃ Measure α where toFun := ennrealToMeasure invFun := toENNRealVectorMeasure - left_inv _ := ext fun s hs => by - rw [toENNRealVectorMeasure_apply_measurable hs, ennrealToMeasure_apply hs] - right_inv _ := Measure.ext fun s hs => by - rw [ennrealToMeasure_apply hs, toENNRealVectorMeasure_apply_measurable hs] + left_inv := toENNRealVectorMeasure_ennrealToMeasure + right_inv := ennrealToMeasure_toENNRealVectorMeasure #align measure_theory.vector_measure.equiv_measure MeasureTheory.VectorMeasure.equivMeasure end diff --git a/Mathlib/NumberTheory/Divisors.lean b/Mathlib/NumberTheory/Divisors.lean index d628a349a5c8e..6aaf80c8eab22 100644 --- a/Mathlib/NumberTheory/Divisors.lean +++ b/Mathlib/NumberTheory/Divisors.lean @@ -288,8 +288,9 @@ theorem map_div_left_divisors : n.divisors.map ⟨fun d => (n / d, d), fun p₁ p₂ => congr_arg Prod.snd⟩ = n.divisorsAntidiagonal := by apply Finset.map_injective (Equiv.prodComm _ _).toEmbedding + ext rw [map_swap_divisorsAntidiagonal, ← map_div_right_divisors, Finset.map_map] - rfl + simp #align nat.map_div_left_divisors Nat.map_div_left_divisors theorem sum_divisors_eq_sum_properDivisors_add_self : @@ -344,7 +345,7 @@ theorem divisors_injective : Function.Injective divisors := @[simp] theorem divisors_inj {a b : ℕ} : a.divisors = b.divisors ↔ a = b := - ⟨fun x => divisors_injective x, congrArg divisors⟩ + divisors_injective.eq_iff theorem eq_properDivisors_of_subset_of_sum_eq_sum {s : Finset ℕ} (hsub : s ⊆ n.properDivisors) : ((∑ x in s, x) = ∑ x in n.properDivisors, x) → s = n.properDivisors := by diff --git a/Mathlib/Order/SupIndep.lean b/Mathlib/Order/SupIndep.lean index 54c5af38d5118..bebe3af33a68c 100644 --- a/Mathlib/Order/SupIndep.lean +++ b/Mathlib/Order/SupIndep.lean @@ -413,7 +413,9 @@ theorem independent_ne_bot_iff_independent : refine ⟨fun h ↦ ?_, fun h ↦ h.comp Subtype.val_injective⟩ simp only [independent_def] at h ⊢ intro i - cases' eq_or_ne (t i) ⊥ with hi hi; simp [hi] + cases eq_or_ne (t i) ⊥ with + | inl hi => simp [hi] + | inr hi => ?_ convert h ⟨i, hi⟩ have : ∀ j, ⨆ (_ : t j = ⊥), t j = ⊥ := fun j ↦ by simp only [iSup_eq_bot, imp_self] rw [iSup_split _ (fun j ↦ t j = ⊥), iSup_subtype] diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index 38eaa127af764..1bb2b2f96eafc 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -687,10 +687,11 @@ instance Module.Finite.base_change [CommSemiring R] [Semiring A] [Algebra R A] [ [Module R M] [h : Module.Finite R M] : Module.Finite A (TensorProduct R A M) := by classical obtain ⟨s, hs⟩ := h.out - refine' ⟨⟨s.image (TensorProduct.mk R A M 1), eq_top_iff.mpr fun x _ => _⟩⟩ - apply TensorProduct.induction_on (motive := _) x - · exact zero_mem _ - · intro x y + refine ⟨⟨s.image (TensorProduct.mk R A M 1), eq_top_iff.mpr ?_⟩⟩ + rintro x - + induction x using TensorProduct.induction_on with + | zero => exact zero_mem _ + | tmul x y => -- Porting note: new TC reminder haveI : IsScalarTower R A (TensorProduct R A M) := TensorProduct.isScalarTower_left rw [Finset.coe_image, ← Submodule.span_span_of_tower R, Submodule.span_image, hs, @@ -698,7 +699,7 @@ instance Module.Finite.base_change [CommSemiring R] [Semiring A] [Algebra R A] [ change _ ∈ Submodule.span A (Set.range <| TensorProduct.mk R A M 1) rw [← mul_one x, ← smul_eq_mul, ← TensorProduct.smul_tmul'] exact Submodule.smul_mem _ x (Submodule.subset_span <| Set.mem_range_self y) - · exact fun _ _ => Submodule.add_mem _ + | add x y hx hy => exact Submodule.add_mem _ hx hy #align module.finite.base_change Module.Finite.base_change instance Module.Finite.tensorProduct [CommSemiring R] [AddCommMonoid M] [Module R M] diff --git a/Mathlib/RingTheory/Localization/Basic.lean b/Mathlib/RingTheory/Localization/Basic.lean index 37893df92a30a..53992ef79332c 100644 --- a/Mathlib/RingTheory/Localization/Basic.lean +++ b/Mathlib/RingTheory/Localization/Basic.lean @@ -811,8 +811,8 @@ theorem isLocalization_iff_of_algEquiv [Algebra R P] (h : S ≃ₐ[R] P) : #align is_localization.is_localization_iff_of_alg_equiv IsLocalization.isLocalization_iff_of_algEquiv theorem isLocalization_iff_of_ringEquiv (h : S ≃+* P) : - IsLocalization M S ↔ have := (h.toRingHom.comp <| algebraMap R S).toAlgebra; - IsLocalization M P := + IsLocalization M S ↔ + haveI := (h.toRingHom.comp <| algebraMap R S).toAlgebra; IsLocalization M P := letI := (h.toRingHom.comp <| algebraMap R S).toAlgebra isLocalization_iff_of_algEquiv M { h with commutes' := fun _ => rfl } #align is_localization.is_localization_iff_of_ring_equiv IsLocalization.isLocalization_iff_of_ringEquiv @@ -820,8 +820,8 @@ theorem isLocalization_iff_of_ringEquiv (h : S ≃+* P) : variable (S) theorem isLocalization_of_base_ringEquiv [IsLocalization M S] (h : R ≃+* P) : - have := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra; - IsLocalization (M.map h.toMonoidHom) S := by + haveI := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra + IsLocalization (M.map h.toMonoidHom) S := by letI : Algebra P S := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra constructor · rintro ⟨_, ⟨y, hy, rfl⟩⟩ @@ -843,7 +843,8 @@ theorem isLocalization_of_base_ringEquiv [IsLocalization M S] (h : R ≃+* P) : #align is_localization.is_localization_of_base_ring_equiv IsLocalization.isLocalization_of_base_ringEquiv theorem isLocalization_iff_of_base_ringEquiv (h : R ≃+* P) : - IsLocalization M S ↔ haveI := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra; + IsLocalization M S ↔ + haveI := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra IsLocalization (M.map h.toMonoidHom) S := by letI : Algebra P S := ((algebraMap R S).comp h.symm.toRingHom).toAlgebra refine' ⟨fun _ => isLocalization_of_base_ringEquiv M S h, _⟩ diff --git a/Mathlib/RingTheory/Localization/FractionRing.lean b/Mathlib/RingTheory/Localization/FractionRing.lean index cfffeeaf38935..77a50b18ef731 100644 --- a/Mathlib/RingTheory/Localization/FractionRing.lean +++ b/Mathlib/RingTheory/Localization/FractionRing.lean @@ -169,7 +169,7 @@ theorem mk'_eq_div {r} (s : nonZeroDivisors A) : mk' K r s = algebraMap A K r / #align is_fraction_ring.mk'_eq_div IsFractionRing.mk'_eq_div theorem div_surjective (z : K) : - ∃ (x y : A) (_ : y ∈ nonZeroDivisors A), algebraMap _ _ x / algebraMap _ _ y = z := + ∃ x y : A, y ∈ nonZeroDivisors A ∧ algebraMap _ _ x / algebraMap _ _ y = z := let ⟨x, ⟨y, hy⟩, h⟩ := mk'_surjective (nonZeroDivisors A) z ⟨x, y, hy, by rwa [mk'_eq_div] at h⟩ #align is_fraction_ring.div_surjective IsFractionRing.div_surjective diff --git a/Mathlib/Testing/SlimCheck/Functions.lean b/Mathlib/Testing/SlimCheck/Functions.lean index 9e042dd0ef2f6..0c7104b1c3bc5 100644 --- a/Mathlib/Testing/SlimCheck/Functions.lean +++ b/Mathlib/Testing/SlimCheck/Functions.lean @@ -35,7 +35,7 @@ permutation. One has to be careful when generating the domain to make it vast enough that, when generating arguments to apply `f` to, they argument should be likely to lie in the domain of `f`. This is the reason that injective functions `f : ℤ → ℤ` are generated by -fixing the domain to the range `[-2*size .. -2*size]`, with `size` +fixing the domain to the range `[-2*size .. 2*size]`, with `size` the size parameter of the `gen` monad. Much of the machinery provided in this file is applicable to generate @@ -61,11 +61,11 @@ namespace SlimCheck and a default value returned when the input is not in the domain of the partial function. -`with_default f y` encodes `x ↦ f x` when `x ∈ f` and `x ↦ y` +`withDefault f y` encodes `x ↦ f x` when `x ∈ f` and `x ↦ y` otherwise. We use `Σ` to encode mappings instead of `×` because we -rely on the association list API defined in `data.list.sigma`. +rely on the association list API defined in `Mathlib/Data/List/Sigma.lean`. -/ inductive TotalFunction (α : Type u) (β : Type v) : Type max u v | withDefault : List (Σ _ : α, β) → β → TotalFunction α β @@ -89,7 +89,7 @@ def apply [DecidableEq α] : TotalFunction α β → α → β | TotalFunction.withDefault m y, x => (m.dlookup x).getD y #align slim_check.total_function.apply SlimCheck.TotalFunction.apply -/-- Implementation of `has_repr (total_function α β)`. +/-- Implementation of `Repr (TotalFunction α β)`. Creates a string for a given `finmap` and output, `x₀ ↦ y₀, .. xₙ ↦ yₙ` for each of the entries. The brackets are provided by the calling function. @@ -168,7 +168,7 @@ def zeroDefault : TotalFunction α β → TotalFunction α β variable [DecidableEq α] [DecidableEq β] -/-- The support of a zero default `total_function`. -/ +/-- The support of a zero default `TotalFunction`. -/ @[simp] def zeroDefaultSupp : TotalFunction α β → Finset α | withDefault A _ => @@ -259,11 +259,11 @@ namespace SlimCheck and a default value returned when the input is not in the domain of the partial function. -`map_to_self f` encodes `x ↦ f x` when `x ∈ f` and `x ↦ x`, +`mapToSelf f` encodes `x ↦ f x` when `x ∈ f` and `x ↦ x`, i.e. `x` to itself, otherwise. We use `Σ` to encode mappings instead of `×` because we -rely on the association list API defined in `data.list.sigma`. +rely on the association list API defined in `Mathlib/Data/List/Sigma.lean`. -/ inductive InjectiveFunction (α : Type u) : Type u | mapToSelf (xs : List (Σ _ : α, α)) : @@ -281,9 +281,9 @@ def apply [DecidableEq α] : InjectiveFunction α → α → α | InjectiveFunction.mapToSelf m _ _, x => (m.dlookup x).getD x #align slim_check.injective_function.apply SlimCheck.InjectiveFunction.apply -/-- Produce a string for a given `total_function`. +/-- Produce a string for a given `InjectiveFunction`. The output is of the form `[x₀ ↦ f x₀, .. xₙ ↦ f xₙ, x ↦ x]`. -Unlike for `total_function`, the default value is not a constant +Unlike for `TotalFunction`, the default value is not a constant but the identity function. -/ protected def repr [Repr α] : InjectiveFunction α → String @@ -299,7 +299,6 @@ def List.applyId [DecidableEq α] (xs : List (α × α)) (x : α) : α := ((xs.map Prod.toSigma).dlookup x).getD x #align slim_check.injective_function.list.apply_id SlimCheck.InjectiveFunction.List.applyId -/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/ @[simp] theorem List.applyId_cons [DecidableEq α] (xs : List (α × α)) (x y z : α) : List.applyId ((y, z)::xs) x = if y = x then z else List.applyId xs x := by @@ -315,9 +314,9 @@ open Nat theorem List.applyId_zip_eq [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs.length = ys.length) (x y : α) (i : ℕ) (h₂ : xs.get? i = some x) : List.applyId.{u} (xs.zip ys) x = y ↔ ys.get? i = some y := by - induction xs generalizing ys i - case nil => cases h₂ - case cons x' xs xs_ih => + induction xs generalizing ys i with + | nil => cases h₂ + | cons x' xs xs_ih => cases i · injection h₂ with h₀; subst h₀ cases ys @@ -360,7 +359,7 @@ theorem applyId_mem_iff [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs have h₆ := Nat.succ.inj h₁ specialize xs_ih h₅ h₃ h₄ h₆ simp only [Ne.symm h, xs_ih, List.mem_cons, false_or_iff] - suffices : val ∈ ys; tauto + suffices val ∈ ys by tauto erw [← Option.mem_def, List.mem_dlookup_iff] at h₃ simp only [Prod.toSigma, List.mem_map, heq_iff_eq, Prod.exists] at h₃ rcases h₃ with ⟨a, b, h₃, h₄, h₅⟩ @@ -489,10 +488,9 @@ protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Inject dsimp [id] at h₁ have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by rw [← h₀, ← h₁, List.toFinmap']; clear h₀ h₁ xs₀ xs₁ hperm hnodup - induction xs - case nil => simp only [List.zip_nil_right, List.map_nil] - case cons xs_hd xs_tl - xs_ih => + induction xs with + | nil => simp only [List.zip_nil_right, List.map_nil] + | cons xs_hd xs_tl xs_ih => simp only [true_and_iff, Prod.toSigma, eq_self_iff_true, Sigma.eta, List.zip_cons_cons, List.map, List.cons_inj] exact xs_ih diff --git a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean index 31c964e4a08ad..934011ac899ef 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean @@ -468,7 +468,7 @@ protected theorem uniformContinuous_toFun : UniformContinuous (toFun : (α → protected theorem tendsto_iff_tendstoUniformly {F : ι → α →ᵤ β} {f : α →ᵤ β} : Tendsto F p (𝓝 f) ↔ TendstoUniformly F f p := by rw [(UniformFun.hasBasis_nhds α β f).tendsto_right_iff, TendstoUniformly] - rfl + simp only [mem_setOf, UniformFun.gen] #align uniform_fun.tendsto_iff_tendsto_uniformly UniformFun.tendsto_iff_tendstoUniformly /-- The natural bijection between `α → β × γ` and `(α → β) × (α → γ)`, upgraded to a uniform From 39e18516ba145bd5e9da88063af84a82969d6df6 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 20 Dec 2023 22:14:23 +1100 Subject: [PATCH 089/353] remove unused have --- Mathlib/Data/List/Join.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Data/List/Join.lean b/Mathlib/Data/List/Join.lean index 945259133a395..4f1c1ffe1fb39 100644 --- a/Mathlib/Data/List/Join.lean +++ b/Mathlib/Data/List/Join.lean @@ -52,8 +52,7 @@ theorem join_filter_isEmpty_eq_false [DecidablePred fun l : List α => l.isEmpty | [] :: L => by simp [join_filter_isEmpty_eq_false (L := L), isEmpty_iff_eq_nil] | (a :: l) :: L => by - have cons_not_empty : isEmpty (a :: l) = false := rfl - simp [join_filter_isEmpty_eq_false (L := L), cons_not_empty] + simp [join_filter_isEmpty_eq_false (L := L)] #align list.join_filter_empty_eq_ff List.join_filter_isEmpty_eq_false @[simp] From f1c7086be3b9310ddbfc133e5d26b9d3cd7ebc67 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Wed, 20 Dec 2023 12:26:06 +0000 Subject: [PATCH 090/353] chore(LinearAlgebra): remove some StrongRankCondition (#9152) Co-authored-by: Junyan Xu --- .../LinearAlgebra/FreeModule/Finite/Rank.lean | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean index 046c7e91812e0..a05dfe14b478b 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean @@ -615,21 +615,22 @@ end DivisionRing section ZeroRank -variable [Ring R] [StrongRankCondition R] [AddCommGroup V] [Module R V] - -attribute [local instance] nontrivial_of_invariantBasisNumber +variable [Ring R] [AddCommGroup V] [Module R V] open FiniteDimensional theorem Module.finite_of_rank_eq_nat [Module.Free R V] {n : ℕ} (h : Module.rank R V = n) : Module.Finite R V := by - have := Cardinal.mk_lt_aleph0_iff.mp - (((Free.rank_eq_card_chooseBasisIndex R V).symm.trans h).trans_lt (nat_lt_aleph0 n)) - exact Module.Finite.of_basis (Free.chooseBasis R V) + nontriviality R + obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := R) (M := V) + have := mk_lt_aleph0_iff.mp <| cardinal_le_rank_of_linearIndependent + b.linearIndependent |>.trans_eq h |>.trans_lt <| nat_lt_aleph0 n + exact Module.Finite.of_basis b theorem Module.finite_of_rank_eq_zero [NoZeroSMulDivisors R V] (h : Module.rank R V = 0) : Module.Finite R V := by + nontriviality R rw [rank_zero_iff] at h infer_instance @@ -651,12 +652,14 @@ variable {R V} theorem Submodule.bot_eq_top_of_rank_eq_zero [NoZeroSMulDivisors R V] (h : Module.rank R V = 0) : (⊥ : Submodule R V) = ⊤ := by + nontriviality R rw [rank_zero_iff] at h exact Subsingleton.elim _ _ #align bot_eq_top_of_rank_eq_zero Submodule.bot_eq_top_of_rank_eq_zero +/-- See `rank_subsingleton` for the reason that `Nontrivial R` is needed. -/ @[simp] -theorem Submodule.rank_eq_zero [NoZeroSMulDivisors R V] {S : Submodule R V} : +theorem Submodule.rank_eq_zero [Nontrivial R] [NoZeroSMulDivisors R V] {S : Submodule R V} : Module.rank R S = 0 ↔ S = ⊥ := ⟨fun h => (Submodule.eq_bot_iff _).2 fun x hx => @@ -667,7 +670,8 @@ theorem Submodule.rank_eq_zero [NoZeroSMulDivisors R V] {S : Submodule R V} : #align rank_eq_zero Submodule.rank_eq_zero @[simp] -theorem Submodule.finrank_eq_zero [NoZeroSMulDivisors R V] {S : Submodule R V} [Module.Finite R S] : +theorem Submodule.finrank_eq_zero [StrongRankCondition R] [NoZeroSMulDivisors R V] + {S : Submodule R V} [Module.Finite R S] : finrank R S = 0 ↔ S = ⊥ := by rw [← Submodule.rank_eq_zero, ← finrank_eq_rank, ← @Nat.cast_zero Cardinal, Cardinal.natCast_inj] #align finrank_eq_zero Submodule.finrank_eq_zero @@ -678,7 +682,7 @@ namespace Submodule open IsNoetherian FiniteDimensional -variable [AddCommGroup V] [Ring R] [StrongRankCondition R] [Module R V] +variable [Ring R] [AddCommGroup V] [Module R V] theorem fg_iff_finite (s : Submodule R V) : s.FG ↔ Module.Finite R s := (finite_def.trans (fg_top s)).symm @@ -714,7 +718,7 @@ end Submodule section -variable [Ring R] [StrongRankCondition R] [AddCommGroup V] [Module R V] +variable [Ring R] [AddCommGroup V] [Module R V] instance Module.Finite.finsupp {ι : Type*} [_root_.Finite ι] [Module.Finite R V] : Module.Finite R (ι →₀ V) := From 905338fc510184d673712c1062b5a0c69d223e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Degenne?= Date: Wed, 20 Dec 2023 13:11:49 +0000 Subject: [PATCH 091/353] feat: projective families of measures and projective limits (#8933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Peter Pfaffelhuber Part of the formalization of the Kolmogorov Extension theorem. Co-authored-by: Rémy Degenne --- Mathlib.lean | 1 + .../Constructions/Projective.lean | 155 ++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 Mathlib/MeasureTheory/Constructions/Projective.lean diff --git a/Mathlib.lean b/Mathlib.lean index cf5613827a4b8..589ce63f12c85 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2546,6 +2546,7 @@ import Mathlib.MeasureTheory.Constructions.Pi import Mathlib.MeasureTheory.Constructions.Polish import Mathlib.MeasureTheory.Constructions.Prod.Basic import Mathlib.MeasureTheory.Constructions.Prod.Integral +import Mathlib.MeasureTheory.Constructions.Projective import Mathlib.MeasureTheory.Covering.Besicovitch import Mathlib.MeasureTheory.Covering.BesicovitchVectorSpace import Mathlib.MeasureTheory.Covering.DensityTheorem diff --git a/Mathlib/MeasureTheory/Constructions/Projective.lean b/Mathlib/MeasureTheory/Constructions/Projective.lean new file mode 100644 index 0000000000000..74f1c69477b4a --- /dev/null +++ b/Mathlib/MeasureTheory/Constructions/Projective.lean @@ -0,0 +1,155 @@ +/- +Copyright (c) 2023 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne, Peter Pfaffelhuber +-/ +import Mathlib.MeasureTheory.Constructions.Cylinders + +/-! +# Projective measure families and projective limits + +A family of measures indexed by finite sets of `ι` is projective if, for finite sets `J ⊆ I`, +the projection from `∀ i : I, α i` to `∀ i : J, α i` maps `P I` to `P J`. +A measure `μ` is the projective limit of such a family of measures if for all `I : Finset ι`, +the projection from `∀ i, α i` to `∀ i : I, α i` maps `μ` to `P I`. + +## Main definitions + +* `MeasureTheory.IsProjectiveMeasureFamily`: `P : ∀ J : Finset ι, Measure (∀ j : J, α j)` is + projective if the projection from `∀ i : I, α i` to `∀ i : J, α i` maps `P I` to `P J` + for all `J ⊆ I`. +* `MeasureTheory.IsProjectiveLimit`: `μ` is the projective limit of the measure family `P` if for + all `I : Finset ι`, the map of `μ` by the projection to `I` is `P I`. + +## Main statements + +* `MeasureTheory.IsProjectiveLimit.unique`: the projective limit of a family of finite measures + is unique. + +-/ + +open Set + +namespace MeasureTheory + +variable {ι : Type*} {α : ι → Type*} [∀ i, MeasurableSpace (α i)] + {P : ∀ J : Finset ι, Measure (∀ j : J, α j)} + +/-- A family of measures indexed by finite sets of `ι` is projective if, for finite sets `J ⊆ I`, +the projection from `∀ i : I, α i` to `∀ i : J, α i` maps `P I` to `P J`. -/ +def IsProjectiveMeasureFamily [∀ i, MeasurableSpace (α i)] + (P : ∀ J : Finset ι, Measure (∀ j : J, α j)) : Prop := + ∀ (I J : Finset ι) (hJI : J ⊆ I), + P J = (P I).map (fun (x : ∀ i : I, α i) (j : J) ↦ x ⟨j, hJI j.2⟩) + +namespace IsProjectiveMeasureFamily + +variable {I J : Finset ι} + +/-- Auxiliary lemma for `measure_univ_eq`. -/ +lemma measure_univ_eq_of_subset (hP : IsProjectiveMeasureFamily P) (hJI : J ⊆ I) : + P I univ = P J univ := by + classical + have : (univ : Set (∀ i : I, α i)) = + (fun x : ∀ i : I, α i ↦ fun i : J ↦ x ⟨i, hJI i.2⟩) ⁻¹' (univ : Set (∀ i : J, α i)) := + by rw [preimage_univ] + rw [this, ← Measure.map_apply _ MeasurableSet.univ] + · rw [hP I J hJI] + · exact measurable_pi_lambda _ (fun _ ↦ measurable_pi_apply _) + +lemma measure_univ_eq (hP : IsProjectiveMeasureFamily P) (I J : Finset ι) : + P I univ = P J univ := by + classical + rw [← hP.measure_univ_eq_of_subset (Finset.subset_union_left I J), + ← hP.measure_univ_eq_of_subset (Finset.subset_union_right I J)] + +lemma congr_cylinder_of_subset (hP : IsProjectiveMeasureFamily P) + {S : Set (∀ i : I, α i)} {T : Set (∀ i : J, α i)} (hT : MeasurableSet T) + (h_eq : cylinder I S = cylinder J T) (hJI : J ⊆ I) : + P I S = P J T := by + cases isEmpty_or_nonempty (∀ i, α i) with + | inl h => + suffices ∀ I, P I univ = 0 by + simp only [Measure.measure_univ_eq_zero] at this + simp [this] + intro I + simp only [isEmpty_pi] at h + obtain ⟨i, hi_empty⟩ := h + rw [measure_univ_eq hP I {i}] + have : (univ : Set ((j : {x // x ∈ ({i} : Finset ι)}) → α j)) = ∅ := by simp [hi_empty] + simp [this] + | inr h => + have : S = (fun f : ∀ i : I, α i ↦ fun j : J ↦ f ⟨j, hJI j.prop⟩) ⁻¹' T := + eq_of_cylinder_eq_of_subset h_eq hJI + rw [hP I J hJI, Measure.map_apply _ hT, this] + exact measurable_pi_lambda _ (fun _ ↦ measurable_pi_apply _) + +lemma congr_cylinder (hP : IsProjectiveMeasureFamily P) + {S : Set (∀ i : I, α i)} {T : Set (∀ i : J, α i)} (hS : MeasurableSet S) (hT : MeasurableSet T) + (h_eq : cylinder I S = cylinder J T) : + P I S = P J T := by + classical + let U := (fun f : ∀ i : (I ∪ J : Finset ι), α i + ↦ fun j : I ↦ f ⟨j, Finset.mem_union_left J j.prop⟩) ⁻¹' S ∩ + (fun f ↦ fun j : J ↦ f ⟨j, Finset.mem_union_right I j.prop⟩) ⁻¹' T + suffices : P (I ∪ J) U = P I S ∧ P (I ∪ J) U = P J T + exact this.1.symm.trans this.2 + constructor + · have h_eq_union : cylinder I S = cylinder (I ∪ J) U := by + rw [← inter_cylinder, h_eq, inter_self] + exact hP.congr_cylinder_of_subset hS h_eq_union.symm (Finset.subset_union_left _ _) + · have h_eq_union : cylinder J T = cylinder (I ∪ J) U := by + rw [← inter_cylinder, h_eq, inter_self] + exact hP.congr_cylinder_of_subset hT h_eq_union.symm (Finset.subset_union_right _ _) + +end IsProjectiveMeasureFamily + +/-- A measure `μ` is the projective limit of a family of measures indexed by finite sets of `ι` if +for all `I : Finset ι`, the projection from `∀ i, α i` to `∀ i : I, α i` maps `μ` to `P I`. -/ +def IsProjectiveLimit (μ : Measure (∀ i, α i)) + (P : ∀ J : Finset ι, Measure (∀ j : J, α j)) : Prop := + ∀ I : Finset ι, (μ.map fun x : ∀ i, α i ↦ fun i : I ↦ x i) = P I + +namespace IsProjectiveLimit + +variable {μ ν : Measure (∀ i, α i)} + +lemma measure_cylinder (h : IsProjectiveLimit μ P) + (I : Finset ι) {s : Set (∀ i : I, α i)} (hs : MeasurableSet s) : + μ (cylinder I s) = P I s := by + rw [cylinder, ← Measure.map_apply _ hs, h I] + exact measurable_pi_lambda _ (fun _ ↦ measurable_pi_apply _) + +lemma measure_univ_eq (hμ : IsProjectiveLimit μ P) (I : Finset ι) : + μ univ = P I univ := by + rw [← cylinder_univ I, hμ.measure_cylinder _ MeasurableSet.univ] + +lemma isFiniteMeasure [∀ i, IsFiniteMeasure (P i)] (hμ : IsProjectiveLimit μ P) : + IsFiniteMeasure μ := by + constructor + rw [hμ.measure_univ_eq (∅ : Finset ι)] + exact measure_lt_top _ _ + +lemma isProbabilityMeasure [∀ i, IsProbabilityMeasure (P i)] (hμ : IsProjectiveLimit μ P) : + IsProbabilityMeasure μ := by + constructor + rw [hμ.measure_univ_eq (∅ : Finset ι)] + exact measure_univ + +lemma measure_univ_unique (hμ : IsProjectiveLimit μ P) (hν : IsProjectiveLimit ν P) : + μ univ = ν univ := by + rw [hμ.measure_univ_eq (∅ : Finset ι), hν.measure_univ_eq (∅ : Finset ι)] + +/-- The projective limit of a family of finite measures is unique. -/ +theorem unique [∀ i, IsFiniteMeasure (P i)] + (hμ : IsProjectiveLimit μ P) (hν : IsProjectiveLimit ν P) : + μ = ν := by + haveI : IsFiniteMeasure μ := hμ.isFiniteMeasure + refine ext_of_generate_finite (measurableCylinders α) generateFrom_measurableCylinders.symm + isPiSystem_measurableCylinders (fun s hs ↦ ?_) (hμ.measure_univ_unique hν) + obtain ⟨I, S, hS, rfl⟩ := (mem_measurableCylinders _).mp hs + rw [hμ.measure_cylinder _ hS, hν.measure_cylinder _ hS] + +end IsProjectiveLimit + +end MeasureTheory From fdfe843b911ded6e258e75e7cd3ca2e4eb4c8b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Degenne?= Date: Wed, 20 Dec 2023 13:39:57 +0000 Subject: [PATCH 092/353] feat(MeasureTheory): define semi-rings of sets (#8867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A semi-ring of sets `C` (in the sense of measure theory) is a family of sets containing `∅`, stable by intersection and such that for all `s, t ∈ C`, `s \ t` is equal to a disjoint union of finitely many sets in `C`. Co-authored-by: Peter Pfaffelhuber Part of the formalization of the Kolmogorov Extension theorem. Co-authored-by: RemyDegenne Co-authored-by: sgouezel --- Mathlib.lean | 1 + Mathlib/MeasureTheory/SetSemiring.lean | 278 +++++++++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 Mathlib/MeasureTheory/SetSemiring.lean diff --git a/Mathlib.lean b/Mathlib.lean index 589ce63f12c85..4619426ae0240 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2683,6 +2683,7 @@ import Mathlib.MeasureTheory.Measure.VectorMeasure import Mathlib.MeasureTheory.Measure.WithDensity import Mathlib.MeasureTheory.Measure.WithDensityVectorMeasure import Mathlib.MeasureTheory.PiSystem +import Mathlib.MeasureTheory.SetSemiring import Mathlib.MeasureTheory.Tactic import Mathlib.ModelTheory.Algebra.Field.Basic import Mathlib.ModelTheory.Algebra.Field.CharP diff --git a/Mathlib/MeasureTheory/SetSemiring.lean b/Mathlib/MeasureTheory/SetSemiring.lean new file mode 100644 index 0000000000000..e8f0ab12c8fe3 --- /dev/null +++ b/Mathlib/MeasureTheory/SetSemiring.lean @@ -0,0 +1,278 @@ +/- +Copyright (c) 2023 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne, Peter Pfaffelhuber +-/ +import Mathlib.Data.Set.Pairwise.Lattice +import Mathlib.Data.Real.ENNReal +import Mathlib.MeasureTheory.PiSystem + +/-! # Semirings of sets + +A semi-ring of sets `C` (in the sense of measure theory) is a family of sets containing `∅`, +stable by intersection and such that for all `s, t ∈ C`, `t \ s` is equal to a disjoint union of +finitely many sets in `C`. Note that a semi-ring of sets may not contain unions. + +An important example of a semi-ring of sets is intervals in `ℝ`. The intersection of two intervals +is an interval (possibly empty). The union of two intervals may not be an interval. +The set difference of two intervals may not be an interval, but it will be a disjoint union of +two intervals. + +## Main definitions + +* `MeasureTheory.IsSetSemiring C`: property of being a semi-ring of sets. +* `MeasureTheory.IsSetSemiring.diffFinset hs ht`: for `s, t` in a semi-ring `C` + (with `hC : IsSetSemiring C`) with `hs : s ∈ C`, `ht : t ∈ C`, this is a `Finset` of + pairwise disjoint sets such that `s \ t = ⋃₀ hC.diffFinset hs ht`. +* `MeasureTheory.IsSetSemiring.diffFinset₀ hs hI`: for `hs : s ∈ C` and a finset `I` of sets in `C` + (with `hI : ↑I ⊆ C`), this is a `Finset` of pairwise disjoint sets such that + `s \ ⋃₀ I = ⋃₀ hC.diffFinset₀ hs hI`. + +## Main statements + +* `MeasureTheory.IsSetSemiring.exists_disjoint_finset_diff_eq`: the existence of the `Finset` given + by the definition `IsSetSemiring.diffFinset₀` (see above). + +-/ + +open Finset Set + +open scoped ENNReal BigOperators + +namespace MeasureTheory + +variable {α : Type*} {C : Set (Set α)} {s t : Set α} + +/-- A semi-ring of sets `C` is a family of sets containing `∅`, stable by intersection and such that +for all `s, t ∈ C`, `s \ t` is equal to a disjoint union of finitely many sets in `C`. -/ +structure IsSetSemiring (C : Set (Set α)) : Prop where + empty_mem : ∅ ∈ C + inter_mem : ∀ s ∈ C, ∀ t ∈ C, s ∩ t ∈ C + diff_eq_Union' : ∀ s ∈ C, ∀ t ∈ C, + ∃ I : Finset (Set α), ↑I ⊆ C ∧ PairwiseDisjoint (I : Set (Set α)) id ∧ s \ t = ⋃₀ I + +namespace IsSetSemiring + +lemma isPiSystem (hC : IsSetSemiring C) : IsPiSystem C := fun s hs t ht _ ↦ hC.inter_mem s hs t ht + +section diffFinset + +open Classical in +/-- In a semi-ring of sets `C`, for all sets `s, t ∈ C`, `s \ t` is equal to a disjoint union of +finitely many sets in `C`. The finite set of sets in the union is not unique, but this definition +gives an arbitrary `Finset (Set α)` that satisfies the equality. + +We remove the empty set to ensure that `t ∉ hC.diffFinset hs ht` even if `t = ∅`. -/ +noncomputable def diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) : + Finset (Set α) := + (hC.diff_eq_Union' s hs t ht).choose \ {∅} + +lemma empty_not_mem_diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) : + ∅ ∉ hC.diffFinset hs ht := by + classical + simp only [diffFinset, mem_sdiff, Finset.mem_singleton, eq_self_iff_true, not_true, + and_false_iff, not_false_iff] + +lemma diffFinset_subset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) : + ↑(hC.diffFinset hs ht) ⊆ C := by + classical + simp only [diffFinset, coe_sdiff, coe_singleton, diff_singleton_subset_iff] + exact (hC.diff_eq_Union' s hs t ht).choose_spec.1.trans (Set.subset_insert _ _) + +lemma pairwiseDisjoint_diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) : + PairwiseDisjoint (hC.diffFinset hs ht : Set (Set α)) id := by + classical + simp only [diffFinset, coe_sdiff, coe_singleton] + exact Set.PairwiseDisjoint.subset (hC.diff_eq_Union' s hs t ht).choose_spec.2.1 + (Set.diff_subset _ _) + +lemma sUnion_diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) : + ⋃₀ hC.diffFinset hs ht = s \ t := by + classical + rw [(hC.diff_eq_Union' s hs t ht).choose_spec.2.2] + simp only [diffFinset, coe_sdiff, coe_singleton, diff_singleton_subset_iff] + rw [sUnion_diff_singleton_empty] + +lemma not_mem_diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) : + t ∉ hC.diffFinset hs ht := by + intro hs_mem + suffices t ⊆ s \ t by + have h := @disjoint_sdiff_self_right _ t s _ + specialize h le_rfl this + simp only [Set.bot_eq_empty, Set.le_eq_subset, subset_empty_iff] at h + refine hC.empty_not_mem_diffFinset hs ht ?_ + rwa [← h] + rw [← hC.sUnion_diffFinset hs ht] + exact subset_sUnion_of_mem hs_mem + +lemma sUnion_insert_diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) (hst : t ⊆ s) : + ⋃₀ insert t (hC.diffFinset hs ht) = s := by + conv_rhs => rw [← union_diff_cancel hst, ← hC.sUnion_diffFinset hs ht] + simp only [mem_coe, sUnion_insert] + +lemma disjoint_sUnion_diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) : + Disjoint t (⋃₀ hC.diffFinset hs ht) := by + rw [hC.sUnion_diffFinset] + exact disjoint_sdiff_right + +lemma pairwiseDisjoint_insert_diffFinset (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) : + PairwiseDisjoint (insert t (hC.diffFinset hs ht) : Set (Set α)) id := by + have h := hC.pairwiseDisjoint_diffFinset hs ht + refine PairwiseDisjoint.insert_of_not_mem h (hC.not_mem_diffFinset hs ht) fun u hu ↦ ?_ + simp_rw [id.def] + refine Disjoint.mono_right ?_ (hC.disjoint_sUnion_diffFinset hs ht) + simp only [Set.le_eq_subset] + exact subset_sUnion_of_mem hu + +end diffFinset + +section diffFinset₀ + +variable {I : Finset (Set α)} + +/-- In a semiring of sets `C`, for all set `s ∈ C` and finite set of sets `I ⊆ C`, there is a +finite set of sets in `C` whose union is `s \ ⋃₀ I`. +See `IsSetSemiring.diffFinset₀` for a definition that gives such a set. -/ +lemma exists_disjoint_finset_diff_eq (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : + ∃ (J : Finset (Set α)) (_h_ss : ↑J ⊆ C) (_h_dis : PairwiseDisjoint (J : Set (Set α)) id), + s \ ⋃₀ I = ⋃₀ J := by + classical + revert hI + refine Finset.induction ?_ ?_ I + · intro + simp only [coe_empty, sUnion_empty, diff_empty, exists_prop] + refine ⟨{s}, singleton_subset_set_iff.mpr hs, ?_⟩ + simp only [coe_singleton, pairwiseDisjoint_singleton, sUnion_singleton, eq_self_iff_true, + and_self_iff] + intro t I' _ h h_insert_subset + rw [coe_insert] at h_insert_subset + have ht : t ∈ C := h_insert_subset (Set.mem_insert _ _) + obtain ⟨J, h_ss, h_dis, h_eq⟩ := h ((Set.subset_insert _ _).trans h_insert_subset) + let Ju : ∀ u ∈ C, Finset (Set α) := fun u hu ↦ hC.diffFinset hu ht + have hJu_subset : ∀ (u) (hu : u ∈ C), ↑(Ju u hu) ⊆ C := by + intro u hu x hx + exact hC.diffFinset_subset hu ht hx + have hJu_disj : ∀ (u) (hu : u ∈ C), (Ju u hu : Set (Set α)).PairwiseDisjoint id := fun u hu ↦ + hC.pairwiseDisjoint_diffFinset hu ht + have hJu_sUnion : ∀ (u) (hu : u ∈ C), ⋃₀ (Ju u hu : Set (Set α)) = u \ t := + fun u hu ↦ hC.sUnion_diffFinset hu ht + have hJu_disj' : ∀ (u) (hu : u ∈ C) (v) (hv : v ∈ C) (_h_dis : Disjoint u v), + Disjoint (⋃₀ (Ju u hu : Set (Set α))) (⋃₀ ↑(Ju v hv)) :=by + intro u hu v hv huv_disj + rw [hJu_sUnion, hJu_sUnion] + exact disjoint_of_subset (Set.diff_subset u t) (Set.diff_subset v t) huv_disj + let J' : Finset (Set α) := Finset.biUnion (Finset.univ : Finset J) fun u ↦ Ju u (h_ss u.prop) + have hJ'_subset : ↑J' ⊆ C := by + intro u + simp only [Subtype.coe_mk, univ_eq_attach, coe_biUnion, mem_coe, mem_attach, iUnion_true, + mem_iUnion, Finset.exists_coe, bex_imp] + intro v hv huvt + exact hJu_subset v (h_ss hv) huvt + refine ⟨J', hJ'_subset, ?_, ?_⟩ + · rw [Finset.coe_biUnion] + refine PairwiseDisjoint.biUnion ?_ ?_ + · simp only [univ_eq_attach, mem_coe, id.def, iSup_eq_iUnion] + simp_rw [PairwiseDisjoint, Set.Pairwise, Function.onFun] + intro x _ y _ hxy + have hxy_disj : Disjoint (x : Set α) y := by + by_contra h_contra + refine hxy ?_ + refine Subtype.ext ?_ + exact h_dis.elim x.prop y.prop h_contra + convert hJu_disj' (x : Set α) (h_ss x.prop) y (h_ss y.prop) hxy_disj + · rw [sUnion_eq_biUnion] + congr + · rw [sUnion_eq_biUnion] + congr + · exact fun u _ ↦ hJu_disj _ _ + · rw [coe_insert, sUnion_insert, Set.union_comm, ← Set.diff_diff, h_eq] + simp_rw [sUnion_eq_biUnion, Set.iUnion_diff] + simp only [Subtype.coe_mk, mem_coe, Finset.mem_biUnion, Finset.mem_univ, exists_true_left, + Finset.exists_coe, iUnion_exists, true_and] + rw [iUnion_comm] + refine iUnion_congr fun i ↦ ?_ + by_cases hi : i ∈ J + · simp only [hi, iUnion_true, exists_prop] + rw [← hJu_sUnion i (h_ss hi), sUnion_eq_biUnion] + simp only [mem_coe] + · simp only [hi, iUnion_of_empty, iUnion_empty] + +open Classical in +/-- In a semiring of sets `C`, for all set `s ∈ C` and finite set of sets `I ⊆ C`, +`diffFinset₀` is a finite set of sets in `C` such that `s \ ⋃₀ I = ⋃₀ (hC.diffFinset₀ hs I hI)`. +`diffFinset` is a special case of `diffFinset₀` where `I` is a singleton. -/ +noncomputable def diffFinset₀ (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : Finset (Set α) := + (hC.exists_disjoint_finset_diff_eq hs hI).choose \ {∅} + +lemma empty_not_mem_diffFinset₀ (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : + ∅ ∉ hC.diffFinset₀ hs hI := by + classical + simp only [diffFinset₀, mem_sdiff, Finset.mem_singleton, eq_self_iff_true, not_true, + and_false_iff, not_false_iff] + +lemma diffFinset₀_subset (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : + ↑(hC.diffFinset₀ hs hI) ⊆ C := by + classical + simp only [diffFinset₀, coe_sdiff, coe_singleton, diff_singleton_subset_iff] + exact (hC.exists_disjoint_finset_diff_eq hs hI).choose_spec.choose.trans (Set.subset_insert _ _) + +lemma pairwiseDisjoint_diffFinset₀ (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : + PairwiseDisjoint (hC.diffFinset₀ hs hI : Set (Set α)) id := by + classical + simp only [diffFinset₀, coe_sdiff, coe_singleton] + exact Set.PairwiseDisjoint.subset + (hC.exists_disjoint_finset_diff_eq hs hI).choose_spec.choose_spec.choose (Set.diff_subset _ _) + +lemma diff_sUnion_eq_sUnion_diffFinset₀ (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : + s \ ⋃₀ I = ⋃₀ hC.diffFinset₀ hs hI := by + classical + rw [(hC.exists_disjoint_finset_diff_eq hs hI).choose_spec.choose_spec.choose_spec] + simp only [diffFinset₀, coe_sdiff, coe_singleton, diff_singleton_subset_iff] + rw [sUnion_diff_singleton_empty] + +lemma sUnion_diffFinset₀_subset (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : + ⋃₀ (hC.diffFinset₀ hs hI : Set (Set α)) ⊆ s := by + rw [← hC.diff_sUnion_eq_sUnion_diffFinset₀] + exact diff_subset _ _ + +lemma disjoint_sUnion_diffFinset₀ (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : + Disjoint (⋃₀ (I : Set (Set α))) (⋃₀ hC.diffFinset₀ hs hI) := by + rw [← hC.diff_sUnion_eq_sUnion_diffFinset₀]; exact Set.disjoint_sdiff_right + +lemma disjoint_diffFinset₀ (hC : IsSetSemiring C) (hs : s ∈ C) (hI : ↑I ⊆ C) : + Disjoint I (hC.diffFinset₀ hs hI) := by + by_contra h + rw [Finset.not_disjoint_iff] at h + obtain ⟨u, huI, hu_diffFinset₀⟩ := h + have h_disj : u ≤ ⊥ := hC.disjoint_sUnion_diffFinset₀ hs hI (subset_sUnion_of_mem huI) + (subset_sUnion_of_mem hu_diffFinset₀) + simp only [Set.bot_eq_empty, Set.le_eq_subset, subset_empty_iff] at h_disj + refine hC.empty_not_mem_diffFinset₀ hs hI ?_ + rwa [h_disj] at hu_diffFinset₀ + +lemma pairwiseDisjoint_union_diffFinset₀ (hC : IsSetSemiring C) (hs : s ∈ C) + (hI : ↑I ⊆ C) (h_dis : PairwiseDisjoint (I : Set (Set α)) id) : + PairwiseDisjoint (I ∪ hC.diffFinset₀ hs hI : Set (Set α)) id := by + rw [pairwiseDisjoint_union] + refine ⟨h_dis, hC.pairwiseDisjoint_diffFinset₀ hs hI, fun u hu v hv _ ↦ ?_⟩ + simp_rw [id.def] + exact disjoint_of_subset (subset_sUnion_of_mem hu) (subset_sUnion_of_mem hv) + (hC.disjoint_sUnion_diffFinset₀ hs hI) + +lemma sUnion_union_sUnion_diffFinset₀_of_subset (hC : IsSetSemiring C) (hs : s ∈ C) + (hI : ↑I ⊆ C) (hI_ss : ⋃₀ ↑I ⊆ s) : + ⋃₀ I ∪ ⋃₀ hC.diffFinset₀ hs hI = s := by + conv_rhs => rw [← union_diff_cancel hI_ss, hC.diff_sUnion_eq_sUnion_diffFinset₀ hs hI] + +lemma sUnion_union_diffFinset₀_of_subset (hC : IsSetSemiring C) (hs : s ∈ C) + (hI : ↑I ⊆ C) (hI_ss : ⋃₀ ↑I ⊆ s) [DecidableEq (Set α)] : + ⋃₀ ↑(I ∪ hC.diffFinset₀ hs hI) = s := by + conv_rhs => rw [← sUnion_union_sUnion_diffFinset₀_of_subset hC hs hI hI_ss] + simp_rw [coe_union] + rw [sUnion_union] + +end diffFinset₀ + +end IsSetSemiring + +end MeasureTheory From 49ee3b274b8d6dca510739494eb2ff0d0e484e8f Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 20 Dec 2023 14:02:36 +0000 Subject: [PATCH 093/353] refactor(FDeriv): use `structure` (#8907) This way we can easily change the definition so that it works for topological vector spaces without generalizing any of the theorems right away. --- .../BoxIntegral/DivergenceTheorem.lean | 4 +- Mathlib/Analysis/Calculus/Deriv/Basic.lean | 6 +-- Mathlib/Analysis/Calculus/FDeriv/Add.lean | 6 +-- Mathlib/Analysis/Calculus/FDeriv/Basic.lean | 43 ++++++++++--------- Mathlib/Analysis/Calculus/FDeriv/Comp.lean | 13 +++--- Mathlib/Analysis/Calculus/FDeriv/Equiv.lean | 6 +-- Mathlib/Analysis/Calculus/FDeriv/Extend.lean | 2 +- Mathlib/Analysis/Calculus/FDeriv/Linear.lean | 2 +- .../Analysis/Calculus/FDeriv/Measurable.lean | 15 +++---- Mathlib/Analysis/Calculus/FDeriv/Prod.lean | 4 +- .../Calculus/FDeriv/RestrictScalars.lean | 16 +++---- .../Analysis/Calculus/FDeriv/Symmetric.lean | 2 +- Mathlib/Analysis/Calculus/Gradient/Basic.lean | 6 +-- Mathlib/MeasureTheory/Function/Jacobian.lean | 4 +- .../Integral/FundThmCalculus.lean | 4 +- Mathlib/Topology/Basic.lean | 3 ++ test/Recall.lean | 4 +- 17 files changed, 71 insertions(+), 69 deletions(-) diff --git a/Mathlib/Analysis/BoxIntegral/DivergenceTheorem.lean b/Mathlib/Analysis/BoxIntegral/DivergenceTheorem.lean index db6ce46b89988..d89e402b272dd 100644 --- a/Mathlib/Analysis/BoxIntegral/DivergenceTheorem.lean +++ b/Mathlib/Analysis/BoxIntegral/DivergenceTheorem.lean @@ -245,8 +245,8 @@ theorem hasIntegral_GP_pderiv (f : (Fin (n + 1) → ℝ) → E) /- At a point `x ∉ s`, we unfold the definition of Fréchet differentiability, then use an estimate we proved earlier in this file. -/ rcases exists_pos_mul_lt ε0 (2 * c) with ⟨ε', ε'0, hlt⟩ - rcases (nhdsWithin_hasBasis nhds_basis_closedBall _).mem_iff.1 ((Hd x hx).def ε'0) with - ⟨δ, δ0, Hδ⟩ + rcases (nhdsWithin_hasBasis nhds_basis_closedBall _).mem_iff.1 ((Hd x hx).isLittleO.def ε'0) + with ⟨δ, δ0, Hδ⟩ refine' ⟨δ, δ0, fun J hle hJδ hxJ hJc => _⟩ simp only [BoxAdditiveMap.volume_apply, Box.volume_apply, dist_eq_norm] refine' (norm_volume_sub_integral_face_upper_sub_lower_smul_le _ diff --git a/Mathlib/Analysis/Calculus/Deriv/Basic.lean b/Mathlib/Analysis/Calculus/Deriv/Basic.lean index 8577837699cf2..0a3df02e596b3 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Basic.lean @@ -262,7 +262,7 @@ theorem UniqueDiffWithinAt.eq_deriv (s : Set 𝕜) (H : UniqueDiffWithinAt 𝕜 theorem hasDerivAtFilter_iff_isLittleO : HasDerivAtFilter f f' x L ↔ (fun x' : 𝕜 => f x' - f x - (x' - x) • f') =o[L] fun x' => x' - x := - Iff.rfl + hasFDerivAtFilter_iff_isLittleO .. #align has_deriv_at_filter_iff_is_o hasDerivAtFilter_iff_isLittleO theorem hasDerivAtFilter_iff_tendsto : @@ -274,7 +274,7 @@ theorem hasDerivAtFilter_iff_tendsto : theorem hasDerivWithinAt_iff_isLittleO : HasDerivWithinAt f f' s x ↔ (fun x' : 𝕜 => f x' - f x - (x' - x) • f') =o[𝓝[s] x] fun x' => x' - x := - Iff.rfl + hasFDerivAtFilter_iff_isLittleO .. #align has_deriv_within_at_iff_is_o hasDerivWithinAt_iff_isLittleO theorem hasDerivWithinAt_iff_tendsto : @@ -285,7 +285,7 @@ theorem hasDerivWithinAt_iff_tendsto : theorem hasDerivAt_iff_isLittleO : HasDerivAt f f' x ↔ (fun x' : 𝕜 => f x' - f x - (x' - x) • f') =o[𝓝 x] fun x' => x' - x := - Iff.rfl + hasFDerivAtFilter_iff_isLittleO .. #align has_deriv_at_iff_is_o hasDerivAt_iff_isLittleO theorem hasDerivAt_iff_tendsto : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Add.lean b/Mathlib/Analysis/Calculus/FDeriv/Add.lean index 5f2cf65e0b266..1ba6ce06efccf 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Add.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Add.lean @@ -123,9 +123,9 @@ nonrec theorem HasStrictFDerivAt.add (hf : HasStrictFDerivAt f f' x) abel #align has_strict_fderiv_at.add HasStrictFDerivAt.add -nonrec theorem HasFDerivAtFilter.add (hf : HasFDerivAtFilter f f' x L) +theorem HasFDerivAtFilter.add (hf : HasFDerivAtFilter f f' x L) (hg : HasFDerivAtFilter g g' x L) : HasFDerivAtFilter (fun y => f y + g y) (f' + g') x L := - (hf.add hg).congr_left fun _ => by + .of_isLittleO <| (hf.isLittleO.add hg.isLittleO).congr_left fun _ => by simp only [LinearMap.sub_apply, LinearMap.add_apply, map_sub, map_add, add_apply] abel #align has_fderiv_at_filter.add HasFDerivAtFilter.add @@ -337,7 +337,7 @@ theorem HasStrictFDerivAt.sum (h : ∀ i ∈ u, HasStrictFDerivAt (A i) (A' i) x theorem HasFDerivAtFilter.sum (h : ∀ i ∈ u, HasFDerivAtFilter (A i) (A' i) x L) : HasFDerivAtFilter (fun y => ∑ i in u, A i y) (∑ i in u, A' i) x L := by - dsimp [HasFDerivAtFilter] at * + simp only [hasFDerivAtFilter_iff_isLittleO] at * convert IsLittleO.sum h simp [ContinuousLinearMap.sum_apply] #align has_fderiv_at_filter.sum HasFDerivAtFilter.sum diff --git a/Mathlib/Analysis/Calculus/FDeriv/Basic.lean b/Mathlib/Analysis/Calculus/FDeriv/Basic.lean index 8a546f66dd6d1..00478ed34a603 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Basic.lean @@ -141,8 +141,9 @@ variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜 G'] is designed to be specialized for `L = 𝓝 x` (in `HasFDerivAt`), giving rise to the usual notion of Fréchet derivative, and for `L = 𝓝[s] x` (in `HasFDerivWithinAt`), giving rise to the notion of Fréchet derivative along the set `s`. -/ -def HasFDerivAtFilter (f : E → F) (f' : E →L[𝕜] F) (x : E) (L : Filter E) := - (fun x' => f x' - f x - f' (x' - x)) =o[L] fun x' => x' - x +@[mk_iff hasFDerivAtFilter_iff_isLittleO] +structure HasFDerivAtFilter (f : E → F) (f' : E →L[𝕜] F) (x : E) (L : Filter E) : Prop where + of_isLittleO :: isLittleO : (fun x' => f x' - f x - f' (x' - x)) =o[L] fun x' => x' - x #align has_fderiv_at_filter HasFDerivAtFilter /-- A function `f` has the continuous linear map `f'` as derivative at `x` within a set `s` if @@ -257,7 +258,7 @@ theorem HasFDerivWithinAt.lim (h : HasFDerivWithinAt f f' s x) {α : Type*} (l : constructor · apply tendsto_const_nhds.add (tangentConeAt.lim_zero l clim cdlim) · rwa [tendsto_principal] - have : (fun y => f y - f x - f' (y - x)) =o[𝓝[s] x] fun y => y - x := h + have : (fun y => f y - f x - f' (y - x)) =o[𝓝[s] x] fun y => y - x := h.isLittleO have : (fun n => f (x + d n) - f x - f' (x + d n - x)) =o[l] fun n => x + d n - x := this.comp_tendsto tendsto_arg have : (fun n => f (x + d n) - f x - f' (d n)) =o[l] d := by simpa only [add_sub_cancel'] @@ -312,8 +313,8 @@ theorem hasFDerivAtFilter_iff_tendsto : have h : ∀ x', ‖x' - x‖ = 0 → ‖f x' - f x - f' (x' - x)‖ = 0 := fun x' hx' => by rw [sub_eq_zero.1 (norm_eq_zero.1 hx')] simp - unfold HasFDerivAtFilter - rw [← isLittleO_norm_left, ← isLittleO_norm_right, isLittleO_iff_tendsto h] + rw [hasFDerivAtFilter_iff_isLittleO, ← isLittleO_norm_left, ← isLittleO_norm_right, + isLittleO_iff_tendsto h] exact tendsto_congr fun _ => div_eq_inv_mul _ _ #align has_fderiv_at_filter_iff_tendsto hasFDerivAtFilter_iff_tendsto @@ -330,7 +331,7 @@ theorem hasFDerivAt_iff_tendsto : theorem hasFDerivAt_iff_isLittleO_nhds_zero : HasFDerivAt f f' x ↔ (fun h : E => f (x + h) - f x - f' h) =o[𝓝 0] fun h => h := by - rw [HasFDerivAt, HasFDerivAtFilter, ← map_add_left_nhds_zero x, isLittleO_map] + rw [HasFDerivAt, hasFDerivAtFilter_iff_isLittleO, ← map_add_left_nhds_zero x, isLittleO_map] simp [(· ∘ ·)] #align has_fderiv_at_iff_is_o_nhds_zero hasFDerivAt_iff_isLittleO_nhds_zero @@ -368,7 +369,7 @@ theorem HasFDerivAt.le_of_lipschitz {f : E → F} {f' : E →L[𝕜] F} {x₀ : nonrec theorem HasFDerivAtFilter.mono (h : HasFDerivAtFilter f f' x L₂) (hst : L₁ ≤ L₂) : HasFDerivAtFilter f f' x L₁ := - h.mono hst + .of_isLittleO <| h.isLittleO.mono hst #align has_fderiv_at_filter.mono HasFDerivAtFilter.mono theorem HasFDerivWithinAt.mono_of_mem (h : HasFDerivWithinAt f f' t x) (hst : t ∈ 𝓝[s] x) : @@ -420,7 +421,7 @@ lemma hasFDerivWithinAt_of_isOpen (h : IsOpen s) (hx : x ∈ s) : theorem hasFDerivWithinAt_insert {y : E} : HasFDerivWithinAt f f' (insert y s) x ↔ HasFDerivWithinAt f f' s x := by rcases eq_or_ne x y with (rfl | h) - · simp_rw [HasFDerivWithinAt, HasFDerivAtFilter] + · simp_rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO] apply Asymptotics.isLittleO_insert simp only [sub_self, map_zero] refine' ⟨fun h => h.mono <| subset_insert y s, fun hf => hf.mono_of_mem _⟩ @@ -449,13 +450,13 @@ set_option linter.uppercaseLean3 false in theorem HasFDerivAtFilter.isBigO_sub (h : HasFDerivAtFilter f f' x L) : (fun x' => f x' - f x) =O[L] fun x' => x' - x := - h.isBigO.congr_of_sub.2 (f'.isBigO_sub _ _) + h.isLittleO.isBigO.congr_of_sub.2 (f'.isBigO_sub _ _) set_option linter.uppercaseLean3 false in #align has_fderiv_at_filter.is_O_sub HasFDerivAtFilter.isBigO_sub protected theorem HasStrictFDerivAt.hasFDerivAt (hf : HasStrictFDerivAt f f' x) : HasFDerivAt f f' x := by - rw [HasFDerivAt, HasFDerivAtFilter, isLittleO_iff] + rw [HasFDerivAt, hasFDerivAtFilter_iff_isLittleO, isLittleO_iff] exact fun c hc => tendsto_id.prod_mk_nhds tendsto_const_nhds (isLittleO_iff.1 hf hc) #align has_strict_fderiv_at.has_fderiv_at HasStrictFDerivAt.hasFDerivAt @@ -513,7 +514,7 @@ theorem hasFDerivWithinAt_inter (h : t ∈ 𝓝 x) : theorem HasFDerivWithinAt.union (hs : HasFDerivWithinAt f f' s x) (ht : HasFDerivWithinAt f f' t x) : HasFDerivWithinAt f f' (s ∪ t) x := by simp only [HasFDerivWithinAt, nhdsWithin_union] - exact hs.sup ht + exact .of_isLittleO <| hs.isLittleO.sup ht.isLittleO #align has_fderiv_within_at.union HasFDerivWithinAt.union theorem HasFDerivWithinAt.hasFDerivAt (h : HasFDerivWithinAt f f' s x) (hs : s ∈ 𝓝 x) : @@ -530,7 +531,7 @@ theorem DifferentiableWithinAt.differentiableAt (h : DifferentiableWithinAt 𝕜 as this statement is empty. -/ theorem HasFDerivWithinAt.of_nhdsWithin_eq_bot (h : 𝓝[s\{x}] x = ⊥) : HasFDerivWithinAt f f' s x := by - rw [← hasFDerivWithinAt_diff_singleton x, HasFDerivWithinAt, h] + rw [← hasFDerivWithinAt_diff_singleton x, HasFDerivWithinAt, h, hasFDerivAtFilter_iff_isLittleO] apply isLittleO_bot /-- If `x` is not in the closure of `s`, then `f` has any derivative at `x` within `s`, @@ -735,7 +736,7 @@ theorem fderivWithin_mem_iff {f : E → F} {t : Set E} {s : Set (E →L[𝕜] F) theorem Asymptotics.IsBigO.hasFDerivWithinAt {s : Set E} {x₀ : E} {n : ℕ} (h : f =O[𝓝[s] x₀] fun x => ‖x - x₀‖ ^ n) (hx₀ : x₀ ∈ s) (hn : 1 < n) : HasFDerivWithinAt f (0 : E →L[𝕜] F) s x₀ := by - simp_rw [HasFDerivWithinAt, HasFDerivAtFilter, + simp_rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO, h.eq_zero_of_norm_pow_within hx₀ <| zero_lt_one.trans hn, zero_apply, sub_zero, h.trans_isLittleO ((isLittleO_pow_sub_sub x₀ hn).mono nhdsWithin_le_nhds)] set_option linter.uppercaseLean3 false in @@ -831,7 +832,7 @@ theorem HasFDerivAtFilter.isBigO_sub_rev (hf : HasFDerivAtFilter f f' x L) {C} (hf' : AntilipschitzWith C f') : (fun x' => x' - x) =O[L] fun x' => f x' - f x := have : (fun x' => x' - x) =O[L] fun x' => f' (x' - x) := isBigO_iff.2 ⟨C, eventually_of_forall fun _ => ZeroHomClass.bound_of_antilipschitz f' hf' _⟩ - (this.trans (hf.trans_isBigO this).right_isBigO_add).congr (fun _ => rfl) fun _ => + (this.trans (hf.isLittleO.trans_isBigO this).right_isBigO_add).congr (fun _ => rfl) fun _ => sub_add_cancel _ _ set_option linter.uppercaseLean3 false in #align has_fderiv_at_filter.is_O_sub_rev HasFDerivAtFilter.isBigO_sub_rev @@ -915,9 +916,9 @@ theorem HasStrictFDerivAt.congr_of_eventuallyEq (h : HasStrictFDerivAt f f' x) #align has_strict_fderiv_at.congr_of_eventually_eq HasStrictFDerivAt.congr_of_eventuallyEq theorem Filter.EventuallyEq.hasFDerivAtFilter_iff (h₀ : f₀ =ᶠ[L] f₁) (hx : f₀ x = f₁ x) - (h₁ : ∀ x, f₀' x = f₁' x) : HasFDerivAtFilter f₀ f₀' x L ↔ HasFDerivAtFilter f₁ f₁' x L := - isLittleO_congr (h₀.mono fun y hy => by simp only [hy, h₁, hx]) - (eventually_of_forall fun _ => _root_.rfl) + (h₁ : ∀ x, f₀' x = f₁' x) : HasFDerivAtFilter f₀ f₀' x L ↔ HasFDerivAtFilter f₁ f₁' x L := by + simp only [hasFDerivAtFilter_iff_isLittleO] + exact isLittleO_congr (h₀.mono fun y hy => by simp only [hy, h₁, hx]) .rfl #align filter.eventually_eq.has_fderiv_at_filter_iff Filter.EventuallyEq.hasFDerivAtFilter_iff theorem HasFDerivAtFilter.congr_of_eventuallyEq (h : HasFDerivAtFilter f f' x L) (hL : f₁ =ᶠ[L] f) @@ -1073,7 +1074,7 @@ theorem hasStrictFDerivAt_id (x : E) : HasStrictFDerivAt id (id 𝕜 E) x := #align has_strict_fderiv_at_id hasStrictFDerivAt_id theorem hasFDerivAtFilter_id (x : E) (L : Filter E) : HasFDerivAtFilter id (id 𝕜 E) x L := - (isLittleO_zero _ _).congr_left <| by simp + .of_isLittleO <| (isLittleO_zero _ _).congr_left <| by simp #align has_fderiv_at_filter_id hasFDerivAtFilter_id theorem hasFDerivWithinAt_id (x : E) (s : Set E) : HasFDerivWithinAt id (id 𝕜 E) s x := @@ -1143,7 +1144,7 @@ theorem hasStrictFDerivAt_const (c : F) (x : E) : theorem hasFDerivAtFilter_const (c : F) (x : E) (L : Filter E) : HasFDerivAtFilter (fun _ => c) (0 : E →L[𝕜] F) x L := - (isLittleO_zero _ _).congr_left fun _ => by simp only [zero_apply, sub_self] + .of_isLittleO <| (isLittleO_zero _ _).congr_left fun _ => by simp only [zero_apply, sub_self] #align has_fderiv_at_filter_const hasFDerivAtFilter_const theorem hasFDerivWithinAt_const (c : F) (x : E) (s : Set E) : @@ -1192,8 +1193,8 @@ theorem differentiableOn_const (c : F) : DifferentiableOn 𝕜 (fun _ => c) s := theorem hasFDerivWithinAt_singleton (f : E → F) (x : E) : HasFDerivWithinAt f (0 : E →L[𝕜] F) {x} x := by - simp only [HasFDerivWithinAt, nhdsWithin_singleton, HasFDerivAtFilter, isLittleO_pure, - ContinuousLinearMap.zero_apply, sub_self] + simp only [HasFDerivWithinAt, nhdsWithin_singleton, hasFDerivAtFilter_iff_isLittleO, + isLittleO_pure, ContinuousLinearMap.zero_apply, sub_self] #align has_fderiv_within_at_singleton hasFDerivWithinAt_singleton theorem hasFDerivAt_of_subsingleton [h : Subsingleton E] (f : E → F) (x : E) : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Comp.lean b/Mathlib/Analysis/Calculus/FDeriv/Comp.lean index 2b32baaa9fb41..25fe25066b5dc 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Comp.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Comp.lean @@ -62,27 +62,26 @@ variable (x) theorem HasFDerivAtFilter.comp {g : F → G} {g' : F →L[𝕜] G} {L' : Filter F} (hg : HasFDerivAtFilter g g' (f x) L') (hf : HasFDerivAtFilter f f' x L) (hL : Tendsto f L L') : HasFDerivAtFilter (g ∘ f) (g'.comp f') x L := by - let eq₁ := (g'.isBigO_comp _ _).trans_isLittleO hf - let eq₂ := (hg.comp_tendsto hL).trans_isBigO hf.isBigO_sub - refine' eq₂.triangle (eq₁.congr_left fun x' => _) + let eq₁ := (g'.isBigO_comp _ _).trans_isLittleO hf.isLittleO + let eq₂ := (hg.isLittleO.comp_tendsto hL).trans_isBigO hf.isBigO_sub + refine .of_isLittleO <| eq₂.triangle <| eq₁.congr_left fun x' => ?_ simp #align has_fderiv_at_filter.comp HasFDerivAtFilter.comp /- A readable version of the previous theorem, a general form of the chain rule. -/ example {g : F → G} {g' : F →L[𝕜] G} (hg : HasFDerivAtFilter g g' (f x) (L.map f)) (hf : HasFDerivAtFilter f f' x L) : HasFDerivAtFilter (g ∘ f) (g'.comp f') x L := by - unfold HasFDerivAtFilter at hg have := calc (fun x' => g (f x') - g (f x) - g' (f x' - f x)) =o[L] fun x' => f x' - f x := - hg.comp_tendsto le_rfl + hg.isLittleO.comp_tendsto le_rfl _ =O[L] fun x' => x' - x := hf.isBigO_sub - refine' this.triangle _ + refine' .of_isLittleO <| this.triangle _ calc (fun x' : E => g' (f x' - f x) - g'.comp f' (x' - x)) _ =ᶠ[L] fun x' => g' (f x' - f x - f' (x' - x)) := eventually_of_forall fun x' => by simp _ =O[L] fun x' => f x' - f x - f' (x' - x) := (g'.isBigO_comp _ _) - _ =o[L] fun x' => x' - x := hf + _ =o[L] fun x' => x' - x := hf.isLittleO theorem HasFDerivWithinAt.comp {g : F → G} {g' : F →L[𝕜] G} {t : Set F} (hg : HasFDerivWithinAt g g' t (f x)) (hf : HasFDerivWithinAt f f' s x) (hst : MapsTo f s t) : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean index 257012e267825..5bd75dc053eed 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean @@ -393,9 +393,9 @@ theorem HasFDerivAt.of_local_left_inverse {f : E → F} {f' : E ≃L[𝕜] F} {g fun x : F => f' (g x - g a) - (x - a) := by refine' ((f'.symm : F →L[𝕜] E).isBigO_comp _ _).congr (fun x => _) fun _ => rfl simp - refine' this.trans_isLittleO _ + refine HasFDerivAtFilter.of_isLittleO <| this.trans_isLittleO ?_ clear this - refine ((hf.comp_tendsto hg).symm.congr' (hfg.mono ?_) .rfl).trans_isBigO ?_ + refine ((hf.isLittleO.comp_tendsto hg).symm.congr' (hfg.mono ?_) .rfl).trans_isBigO ?_ · intro p hp simp [hp, hfg.self_of_nhds] · refine' ((hf.isBigO_sub_rev f'.antilipschitz).comp_tendsto hg).congr' @@ -432,7 +432,7 @@ theorem HasFDerivWithinAt.eventually_ne (h : HasFDerivWithinAt f f' s x) rw [nhdsWithin, diff_eq, ← inf_principal, ← inf_assoc, eventually_inf_principal] have A : (fun z => z - x) =O[𝓝[s] x] fun z => f' (z - x) := isBigO_iff.2 <| hf'.imp fun C hC => eventually_of_forall fun z => hC _ - have : (fun z => f z - f x) ~[𝓝[s] x] fun z => f' (z - x) := h.trans_isBigO A + have : (fun z => f z - f x) ~[𝓝[s] x] fun z => f' (z - x) := h.isLittleO.trans_isBigO A simpa [not_imp_not, sub_eq_zero] using (A.trans this.isBigO_symm).eq_zero_imp #align has_fderiv_within_at.eventually_ne HasFDerivWithinAt.eventually_ne diff --git a/Mathlib/Analysis/Calculus/FDeriv/Extend.lean b/Mathlib/Analysis/Calculus/FDeriv/Extend.lean index cb148441d143b..e2859c8d2b745 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Extend.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Extend.lean @@ -45,7 +45,7 @@ theorem has_fderiv_at_boundary_of_tendsto_fderiv {f : E → F} {s : Set E} {x : by_cases hx : x ∉ closure s · rw [← closure_closure] at hx; exact hasFDerivWithinAt_of_nmem_closure hx push_neg at hx - rw [HasFDerivWithinAt, HasFDerivAtFilter, Asymptotics.isLittleO_iff] + rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO, Asymptotics.isLittleO_iff] /- One needs to show that `‖f y - f x - f' (y - x)‖ ≤ ε ‖y - x‖` for `y` close to `x` in `closure s`, where `ε` is an arbitrary positive constant. By continuity of the functions, it suffices to prove this for nearby points inside `s`. In a neighborhood of `x`, the derivative diff --git a/Mathlib/Analysis/Calculus/FDeriv/Linear.lean b/Mathlib/Analysis/Calculus/FDeriv/Linear.lean index 8295330fe567b..5c3ad26b156f4 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Linear.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Linear.lean @@ -64,7 +64,7 @@ protected theorem ContinuousLinearMap.hasStrictFDerivAt {x : E} : HasStrictFDeri #align continuous_linear_map.has_strict_fderiv_at ContinuousLinearMap.hasStrictFDerivAt protected theorem ContinuousLinearMap.hasFDerivAtFilter : HasFDerivAtFilter e e x L := - (isLittleO_zero _ _).congr_left fun x => by simp only [e.map_sub, sub_self] + .of_isLittleO <| (isLittleO_zero _ _).congr_left fun x => by simp only [e.map_sub, sub_self] #align continuous_linear_map.has_fderiv_at_filter ContinuousLinearMap.hasFDerivAtFilter protected theorem ContinuousLinearMap.hasFDerivWithinAt : HasFDerivWithinAt e e s x := diff --git a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean index 1e45579362f25..f68b4dd71db0b 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean @@ -163,22 +163,21 @@ theorem le_of_mem_A {r ε : ℝ} {L : E →L[𝕜] F} {x : E} (hx : x ∈ A f L theorem mem_A_of_differentiable {ε : ℝ} (hε : 0 < ε) {x : E} (hx : DifferentiableAt 𝕜 f x) : ∃ R > 0, ∀ r ∈ Ioo (0 : ℝ) R, x ∈ A f (fderiv 𝕜 f x) r ε := by - have := hx.hasFDerivAt - simp only [HasFDerivAt, HasFDerivAtFilter, isLittleO_iff] at this let δ := (ε / 2) / 2 - have hδ : 0 < δ := by positivity - rcases eventually_nhds_iff_ball.1 (this hδ) with ⟨R, R_pos, hR⟩ + obtain ⟨R, R_pos, hR⟩ : + ∃ R > 0, ∀ y ∈ ball x R, ‖f y - f x - fderiv 𝕜 f x (y - x)‖ ≤ δ * ‖y - x‖ := + eventually_nhds_iff_ball.1 <| hx.hasFDerivAt.isLittleO.bound <| by positivity refine' ⟨R, R_pos, fun r hr => _⟩ - have : r ∈ Ioc (r / 2) r := ⟨half_lt_self hr.1, le_rfl⟩ + have : r ∈ Ioc (r / 2) r := right_mem_Ioc.2 <| half_lt_self hr.1 refine' ⟨r, this, fun y hy z hz => _⟩ calc ‖f z - f y - (fderiv 𝕜 f x) (z - y)‖ = ‖f z - f x - (fderiv 𝕜 f x) (z - x) - (f y - f x - (fderiv 𝕜 f x) (y - x))‖ := - by congr 1; simp only [ContinuousLinearMap.map_sub]; abel + by simp only [map_sub]; abel_nf _ ≤ ‖f z - f x - (fderiv 𝕜 f x) (z - x)‖ + ‖f y - f x - (fderiv 𝕜 f x) (y - x)‖ := - (norm_sub_le _ _) + norm_sub_le _ _ _ ≤ δ * ‖z - x‖ + δ * ‖y - x‖ := - (add_le_add (hR _ (lt_trans (mem_ball.1 hz) hr.2)) (hR _ (lt_trans (mem_ball.1 hy) hr.2))) + add_le_add (hR _ (ball_subset_ball hr.2.le hz)) (hR _ (ball_subset_ball hr.2.le hy)) _ ≤ δ * r + δ * r := by rw [mem_ball_iff_norm] at hz hy; gcongr _ = (ε / 2) * r := by ring _ < ε * r := by gcongr; exacts [hr.1, half_lt_self hε] diff --git a/Mathlib/Analysis/Calculus/FDeriv/Prod.lean b/Mathlib/Analysis/Calculus/FDeriv/Prod.lean index 8241c33847598..1dc744fb39f0e 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Prod.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Prod.lean @@ -67,7 +67,7 @@ protected theorem HasStrictFDerivAt.prod (hf₁ : HasStrictFDerivAt f₁ f₁' x theorem HasFDerivAtFilter.prod (hf₁ : HasFDerivAtFilter f₁ f₁' x L) (hf₂ : HasFDerivAtFilter f₂ f₂' x L) : HasFDerivAtFilter (fun x => (f₁ x, f₂ x)) (f₁'.prod f₂') x L := - hf₁.prod_left hf₂ + .of_isLittleO <| hf₁.isLittleO.prod_left hf₂.isLittleO #align has_fderiv_at_filter.prod HasFDerivAtFilter.prod nonrec theorem HasFDerivWithinAt.prod (hf₁ : HasFDerivWithinAt f₁ f₁' s x) @@ -391,7 +391,7 @@ theorem hasStrictFDerivAt_pi : theorem hasFDerivAtFilter_pi' : HasFDerivAtFilter Φ Φ' x L ↔ ∀ i, HasFDerivAtFilter (fun x => Φ x i) ((proj i).comp Φ') x L := by - simp only [HasFDerivAtFilter, ContinuousLinearMap.coe_pi] + simp only [hasFDerivAtFilter_iff_isLittleO, ContinuousLinearMap.coe_pi] exact isLittleO_pi #align has_fderiv_at_filter_pi' hasFDerivAtFilter_pi' diff --git a/Mathlib/Analysis/Calculus/FDeriv/RestrictScalars.lean b/Mathlib/Analysis/Calculus/FDeriv/RestrictScalars.lean index c40472a04f6e5..9131e5db3ac8b 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/RestrictScalars.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/RestrictScalars.lean @@ -56,17 +56,17 @@ theorem HasStrictFDerivAt.restrictScalars (h : HasStrictFDerivAt f f' x) : theorem HasFDerivAtFilter.restrictScalars {L} (h : HasFDerivAtFilter f f' x L) : HasFDerivAtFilter f (f'.restrictScalars 𝕜) x L := - h + .of_isLittleO h.1 #align has_fderiv_at_filter.restrict_scalars HasFDerivAtFilter.restrictScalars theorem HasFDerivAt.restrictScalars (h : HasFDerivAt f f' x) : HasFDerivAt f (f'.restrictScalars 𝕜) x := - h + .of_isLittleO h.1 #align has_fderiv_at.restrict_scalars HasFDerivAt.restrictScalars theorem HasFDerivWithinAt.restrictScalars (h : HasFDerivWithinAt f f' s x) : HasFDerivWithinAt f (f'.restrictScalars 𝕜) s x := - h + .of_isLittleO h.1 #align has_fderiv_within_at.restrict_scalars HasFDerivWithinAt.restrictScalars theorem DifferentiableAt.restrictScalars (h : DifferentiableAt 𝕜' f x) : DifferentiableAt 𝕜 f x := @@ -86,16 +86,16 @@ theorem Differentiable.restrictScalars (h : Differentiable 𝕜' f) : Differenti (h x).restrictScalars 𝕜 #align differentiable.restrict_scalars Differentiable.restrictScalars -theorem hasFDerivWithinAt_of_restrictScalars {g' : E →L[𝕜] F} (h : HasFDerivWithinAt f g' s x) +theorem HasFDerivWithinAt.of_restrictScalars {g' : E →L[𝕜] F} (h : HasFDerivWithinAt f g' s x) (H : f'.restrictScalars 𝕜 = g') : HasFDerivWithinAt f f' s x := by rw [← H] at h - exact h -#align has_fderiv_within_at_of_restrict_scalars hasFDerivWithinAt_of_restrictScalars + exact .of_isLittleO h.1 +#align has_fderiv_within_at_of_restrict_scalars HasFDerivWithinAt.of_restrictScalars theorem hasFDerivAt_of_restrictScalars {g' : E →L[𝕜] F} (h : HasFDerivAt f g' x) (H : f'.restrictScalars 𝕜 = g') : HasFDerivAt f f' x := by rw [← H] at h - exact h + exact .of_isLittleO h.1 #align has_fderiv_at_of_restrict_scalars hasFDerivAt_of_restrictScalars theorem DifferentiableAt.fderiv_restrictScalars (h : DifferentiableAt 𝕜' f x) : @@ -110,7 +110,7 @@ theorem differentiableWithinAt_iff_restrictScalars (hf : DifferentiableWithinAt · rintro ⟨g', hg'⟩ exact ⟨g', hs.eq (hg'.restrictScalars 𝕜) hf.hasFDerivWithinAt⟩ · rintro ⟨f', hf'⟩ - exact ⟨f', hasFDerivWithinAt_of_restrictScalars 𝕜 hf.hasFDerivWithinAt hf'⟩ + exact ⟨f', hf.hasFDerivWithinAt.of_restrictScalars 𝕜 hf'⟩ #align differentiable_within_at_iff_restrict_scalars differentiableWithinAt_iff_restrictScalars theorem differentiableAt_iff_restrictScalars (hf : DifferentiableAt 𝕜 f x) : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean index 9a9643591c762..6e17b9d117492 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean @@ -76,7 +76,7 @@ theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s) (isLittleO_iff.2 fun ε εpos => _) (isBigO_const_mul_self ((‖v‖ + ‖w‖) * ‖w‖) _ _) -- consider a ball of radius `δ` around `x` in which the Taylor approximation for `f''` is -- good up to `δ`. - rw [HasFDerivWithinAt, HasFDerivAtFilter, isLittleO_iff] at hx + rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO, isLittleO_iff] at hx rcases Metric.mem_nhdsWithin_iff.1 (hx εpos) with ⟨δ, δpos, sδ⟩ have E1 : ∀ᶠ h in 𝓝[>] (0 : ℝ), h * (‖v‖ + ‖w‖) < δ := by have : Filter.Tendsto (fun h => h * (‖v‖ + ‖w‖)) (𝓝[>] (0 : ℝ)) (𝓝 (0 * (‖v‖ + ‖w‖))) := diff --git a/Mathlib/Analysis/Calculus/Gradient/Basic.lean b/Mathlib/Analysis/Calculus/Gradient/Basic.lean index d7d14e5c2e825..61c7eda849864 100644 --- a/Mathlib/Analysis/Calculus/Gradient/Basic.lean +++ b/Mathlib/Analysis/Calculus/Gradient/Basic.lean @@ -211,12 +211,12 @@ section GradientProperties theorem hasGradientAtFilter_iff_isLittleO : HasGradientAtFilter f f' x L ↔ (fun x' : F => f x' - f x - ⟪f', x' - x⟫) =o[L] fun x' => x' - x := - Iff.rfl + hasFDerivAtFilter_iff_isLittleO .. theorem hasGradientWithinAt_iff_isLittleO : HasGradientWithinAt f f' s x ↔ (fun x' : F => f x' - f x - ⟪f', x' - x⟫) =o[𝓝[s] x] fun x' => x' - x := - Iff.rfl + hasGradientAtFilter_iff_isLittleO theorem hasGradientWithinAt_iff_tendsto : HasGradientWithinAt f f' s x ↔ @@ -225,7 +225,7 @@ theorem hasGradientWithinAt_iff_tendsto : theorem hasGradientAt_iff_isLittleO : HasGradientAt f f' x ↔ (fun x' : F => f x' - f x - ⟪f', x' - x⟫) =o[𝓝 x] fun x' => x' - x := - Iff.rfl + hasGradientAtFilter_iff_isLittleO theorem hasGradientAt_iff_tendsto : HasGradientAt f f' x ↔ diff --git a/Mathlib/MeasureTheory/Function/Jacobian.lean b/Mathlib/MeasureTheory/Function/Jacobian.lean index 0afc446ce88dc..8cd27dd4d467d 100644 --- a/Mathlib/MeasureTheory/Function/Jacobian.lean +++ b/Mathlib/MeasureTheory/Function/Jacobian.lean @@ -154,7 +154,7 @@ theorem exists_closed_cover_approximatesLinearOn_of_hasFDerivWithinAt [SecondCou simpa only [sub_pos] using mem_ball_iff_norm.mp hz obtain ⟨δ, δpos, hδ⟩ : ∃ (δ : ℝ), 0 < δ ∧ ball x δ ∩ s ⊆ {y | ‖f y - f x - (f' x) (y - x)‖ ≤ ε * ‖y - x‖} := - Metric.mem_nhdsWithin_iff.1 (IsLittleO.def (hf' x xs) εpos) + Metric.mem_nhdsWithin_iff.1 ((hf' x xs).isLittleO.def εpos) obtain ⟨n, hn⟩ : ∃ n, u n < δ := ((tendsto_order.1 u_lim).2 _ δpos).exists refine' ⟨n, ⟨z, zT⟩, ⟨xs, _⟩⟩ intro y hy @@ -494,7 +494,7 @@ theorem _root_.ApproximatesLinearOn.norm_fderiv_sub_le {A : E →L[ℝ] E} {δ : (measure_closedBall_pos μ z εpos).ne' obtain ⟨ρ, ρpos, hρ⟩ : ∃ ρ > 0, ball x ρ ∩ s ⊆ {y : E | ‖f y - f x - (f' x) (y - x)‖ ≤ ε * ‖y - x‖} := - mem_nhdsWithin_iff.1 (IsLittleO.def (hf' x xs) εpos) + mem_nhdsWithin_iff.1 ((hf' x xs).isLittleO.def εpos) -- for small enough `r`, the rescaled ball `r • closedBall z ε` is included in the set where -- `f y - f x` is well approximated by `f' x (y - x)`. have B₂ : ∀ᶠ r in 𝓝[>] (0 : ℝ), {x} + r • closedBall z ε ⊆ ball x ρ := by diff --git a/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean index 4d1ddc8ff4110..a97920a4cdf6e 100644 --- a/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean +++ b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean @@ -834,7 +834,7 @@ theorem integral_hasFDerivWithinAt_of_tendsto_ae (hf : IntervalIntegrable f volu integral_sub_integral_sub_linear_isLittleO_of_tendsto_ae hf hmeas_a hmeas_b ha hb (tendsto_const_pure.mono_right FTCFilter.pure_le : Tendsto _ _ (𝓝[s] a)) tendsto_fst (tendsto_const_pure.mono_right FTCFilter.pure_le : Tendsto _ _ (𝓝[t] b)) tendsto_snd - refine' (this.congr_left _).trans_isBigO _ + refine .of_isLittleO <| (this.congr_left ?_).trans_isBigO ?_ · intro x; simp [sub_smul]; abel · exact isBigO_fst_prod.norm_left.add isBigO_snd_prod.norm_left #align interval_integral.integral_has_fderiv_within_at_of_tendsto_ae intervalIntegral.integral_hasFDerivWithinAt_of_tendsto_ae @@ -899,7 +899,7 @@ theorem integral_hasDerivWithinAt_of_tendsto_ae_right (hf : IntervalIntegrable f {s t : Set ℝ} [FTCFilter b (𝓝[s] b) (𝓝[t] b)] (hmeas : StronglyMeasurableAtFilter f (𝓝[t] b)) (hb : Tendsto f (𝓝[t] b ⊓ volume.ae) (𝓝 c)) : HasDerivWithinAt (fun u => ∫ x in a..u, f x) c s b := - integral_sub_integral_sub_linear_isLittleO_of_tendsto_ae_right hf hmeas hb + .of_isLittleO <| integral_sub_integral_sub_linear_isLittleO_of_tendsto_ae_right hf hmeas hb (tendsto_const_pure.mono_right FTCFilter.pure_le) tendsto_id #align interval_integral.integral_has_deriv_within_at_of_tendsto_ae_right intervalIntegral.integral_hasDerivWithinAt_of_tendsto_ae_right diff --git a/Mathlib/Topology/Basic.lean b/Mathlib/Topology/Basic.lean index 5c2b5736e149c..71109c438ce32 100644 --- a/Mathlib/Topology/Basic.lean +++ b/Mathlib/Topology/Basic.lean @@ -1326,6 +1326,9 @@ theorem mem_closure_iff_nhdsWithin_neBot {s : Set α} {x : α} : x ∈ closure s mem_closure_iff_clusterPt #align mem_closure_iff_nhds_within_ne_bot mem_closure_iff_nhdsWithin_neBot +lemma not_mem_closure_iff_nhdsWithin_eq_bot {s : Set α} {x : α} : x ∉ closure s ↔ 𝓝[s] x = ⊥ := by + rw [mem_closure_iff_nhdsWithin_neBot, not_neBot] + /-- If `x` is not an isolated point of a topological space, then `{x}ᶜ` is dense in the whole space. -/ theorem dense_compl_singleton (x : α) [NeBot (𝓝[≠] x)] : Dense ({x}ᶜ : Set α) := by diff --git a/test/Recall.lean b/test/Recall.lean index 8809da844a2b6..3222dd5eb3f86 100644 --- a/test/Recall.lean +++ b/test/Recall.lean @@ -17,8 +17,8 @@ section variable {𝕜 : Type _} [NontriviallyNormedField 𝕜] variable {E : Type _} [NormedAddCommGroup E] [NormedSpace 𝕜 E] variable {F : Type _} [NormedAddCommGroup F] [NormedSpace 𝕜 F] -recall HasFDerivAtFilter (f : E → F) (f' : E →L[𝕜] F) (x : E) (L : Filter E) := - (fun x' => f x' - f x - f' (x' - x)) =o[L] fun x' => x' - x +recall HasFDerivAt (f : E → F) (f' : E →L[𝕜] F) (x : E) := + HasFDerivAtFilter f f' x (nhds x) end /-- From a4a7700f822368a3979ea19aaad20f5d3c2beefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 20 Dec 2023 15:10:33 +0000 Subject: [PATCH 094/353] refactor: Closure predicate for `ClosureOperator` (#9153) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is the result of two years and a half of pondering. The only way we ever define closure operators is by having a pre-existing "closedness" predicate and defining the closure of an element `x` as the infimum of all closed `y ≥ x` (assuming we're in a complete lattice). In particular, the emphasis is not on the **preorder of closed elements**, but on the **closedness predicate**. Morally, this is because a closure operator is the same as a Galois connection to the preorder of closed elements, but without mentioning the preorder of closed elements. That means that if we cared about the preorder of closed elements, we would not have wanted a closure operator in the first place, but a Galois connection. All this said, here's what this PR does * Add an `IsClosed` predicate to `ClosureOperator`. This redundant field is here to fix definitional equalities. * Remove the set `closeds`. This is mostly replaced by the predicate, except in the map `toCloseds`, so we... * ... Introduce an `abbrev Closeds` for the order of closed elements * Rename `toClosed` to `toCloseds` to match. * Rename the constructor `mk₃` to the more sexy `ofPred`. This is virtually the only useful constructor. Maybe it should even be taken as the definition, but I haven't gone that far. * Rename the old `ofPred` to `ofCompletePred`. `ofCompletePred` is a specialisation of `ofPred` to the case where we are in a complete lattice. * Remove a bunch of lemmas that are junk now that the definitional equality for `IsClosed` can be controlled. * Golf existing uses of `ClosureOperator`. The diff here, I think, truly demonstrates that this PR is a step forward. I am not extending the refactor to `LowerAdjoint` because: * I am still not sure we want `LowerAdjoint` to even exist * The rationale of preferring the closedness predicate over the preorder of closed elements is less strong here. * I am lazy. It is however easy to do the same refactor if wanted. --- Mathlib/Analysis/Convex/Hull.lean | 25 ++-- Mathlib/CategoryTheory/Sites/Closed.lean | 40 ++---- Mathlib/Order/Closure.lean | 175 ++++++++++------------- Mathlib/Order/SupClosed.lean | 43 +++--- 4 files changed, 110 insertions(+), 173 deletions(-) diff --git a/Mathlib/Analysis/Convex/Hull.lean b/Mathlib/Analysis/Convex/Hull.lean index 7815423e211aa..4e3454c157cb4 100644 --- a/Mathlib/Analysis/Convex/Hull.lean +++ b/Mathlib/Analysis/Convex/Hull.lean @@ -40,12 +40,8 @@ variable (𝕜) variable [AddCommMonoid E] [AddCommMonoid F] [Module 𝕜 E] [Module 𝕜 F] /-- The convex hull of a set `s` is the minimal convex set that includes `s`. -/ -def convexHull : ClosureOperator (Set E) := - ClosureOperator.mk₃ (fun s => ⋂ (t : Set E) (_ : s ⊆ t) (_ : Convex 𝕜 t), t) (Convex 𝕜) - (fun _ => - Set.subset_iInter fun _ => Set.subset_iInter fun hst => Set.subset_iInter fun _ => hst) - (fun _ => convex_iInter fun _ => convex_iInter fun _ => convex_iInter id) fun _ t hst ht => - Set.iInter_subset_of_subset t <| Set.iInter_subset_of_subset hst <| Set.iInter_subset _ ht +@[simps! isClosed] +def convexHull : ClosureOperator (Set E) := .ofCompletePred (Convex 𝕜) fun _ ↦ convex_sInter #align convex_hull convexHull variable (s : Set E) @@ -54,13 +50,11 @@ theorem subset_convexHull : s ⊆ convexHull 𝕜 s := (convexHull 𝕜).le_closure s #align subset_convex_hull subset_convexHull -theorem convex_convexHull : Convex 𝕜 (convexHull 𝕜 s) := - ClosureOperator.closure_mem_mk₃ s +theorem convex_convexHull : Convex 𝕜 (convexHull 𝕜 s) := (convexHull 𝕜).isClosed_closure s #align convex_convex_hull convex_convexHull -theorem convexHull_eq_iInter : convexHull 𝕜 s = - ⋂ (t : Set E) (_ : s ⊆ t) (_ : Convex 𝕜 t), t := - rfl +theorem convexHull_eq_iInter : convexHull 𝕜 s = ⋂ (t : Set E) (_ : s ⊆ t) (_ : Convex 𝕜 t), t := by + simp [convexHull, iInter_subtype, iInter_and] #align convex_hull_eq_Inter convexHull_eq_iInter variable {𝕜 s} {t : Set E} {x y : E} @@ -69,12 +63,11 @@ theorem mem_convexHull_iff : x ∈ convexHull 𝕜 s ↔ ∀ t, s ⊆ t → Conv simp_rw [convexHull_eq_iInter, mem_iInter] #align mem_convex_hull_iff mem_convexHull_iff -theorem convexHull_min (hst : s ⊆ t) (ht : Convex 𝕜 t) : convexHull 𝕜 s ⊆ t := - ClosureOperator.closure_le_mk₃_iff (show s ≤ t from hst) ht +theorem convexHull_min : s ⊆ t → Convex 𝕜 t → convexHull 𝕜 s ⊆ t := (convexHull 𝕜).closure_min #align convex_hull_min convexHull_min theorem Convex.convexHull_subset_iff (ht : Convex 𝕜 t) : convexHull 𝕜 s ⊆ t ↔ s ⊆ t := - ⟨(subset_convexHull _ _).trans, fun h => convexHull_min h ht⟩ + (show (convexHull 𝕜).IsClosed t from ht).closure_le_iff #align convex.convex_hull_subset_iff Convex.convexHull_subset_iff @[mono] @@ -82,7 +75,9 @@ theorem convexHull_mono (hst : s ⊆ t) : convexHull 𝕜 s ⊆ convexHull 𝕜 (convexHull 𝕜).monotone hst #align convex_hull_mono convexHull_mono -theorem Convex.convexHull_eq : Convex 𝕜 s → convexHull 𝕜 s = s := ClosureOperator.mem_mk₃_closed.2 +lemma convexHull_eq_self : convexHull 𝕜 s = s ↔ Convex 𝕜 s := (convexHull 𝕜).isClosed_iff.symm + +alias ⟨_, Convex.convexHull_eq⟩ := convexHull_eq_self #align convex.convex_hull_eq Convex.convexHull_eq @[simp] diff --git a/Mathlib/CategoryTheory/Sites/Closed.lean b/Mathlib/CategoryTheory/Sites/Closed.lean index 7cd46668661a1..82452a339ea72 100644 --- a/Mathlib/CategoryTheory/Sites/Closed.lean +++ b/Mathlib/CategoryTheory/Sites/Closed.lean @@ -104,18 +104,17 @@ theorem close_isClosed {X : C} (S : Sieve X) : J₁.IsClosed (J₁.close S) := fun _ g hg => J₁.arrow_trans g _ S hg fun _ hS => hS #align category_theory.grothendieck_topology.close_is_closed CategoryTheory.GrothendieckTopology.close_isClosed +/-- A Grothendieck topology induces a natural family of closure operators on sieves. -/ +@[simps! isClosed] +def closureOperator (X : C) : ClosureOperator (Sieve X) := + .ofPred J₁.close J₁.IsClosed J₁.le_close J₁.close_isClosed fun _ _ ↦ J₁.le_close_of_isClosed +#align category_theory.grothendieck_topology.closure_operator CategoryTheory.GrothendieckTopology.closureOperator + +#align category_theory.grothendieck_topology.closed_iff_closed CategoryTheory.GrothendieckTopology.closureOperator_isClosed + /-- The sieve `S` is closed iff its closure is equal to itself. -/ -theorem isClosed_iff_close_eq_self {X : C} (S : Sieve X) : J₁.IsClosed S ↔ J₁.close S = S := by - constructor - · intro h - apply le_antisymm - · intro Y f hf - rw [← J₁.covers_iff_mem_of_isClosed h] - apply hf - · apply J₁.le_close - · intro e - rw [← e] - apply J₁.close_isClosed +theorem isClosed_iff_close_eq_self {X : C} (S : Sieve X) : J₁.IsClosed S ↔ J₁.close S = S := + (J₁.closureOperator _).isClosed_iff #align category_theory.grothendieck_topology.is_closed_iff_close_eq_self CategoryTheory.GrothendieckTopology.isClosed_iff_close_eq_self theorem close_eq_self_of_isClosed {X : C} {S : Sieve X} (hS : J₁.IsClosed S) : J₁.close S = S := @@ -136,13 +135,12 @@ theorem pullback_close {X Y : C} (f : Y ⟶ X) (S : Sieve X) : @[mono] theorem monotone_close {X : C} : Monotone (J₁.close : Sieve X → Sieve X) := - fun _ S₂ h => J₁.le_close_of_isClosed (h.trans (J₁.le_close _)) (J₁.close_isClosed S₂) + (J₁.closureOperator _).monotone #align category_theory.grothendieck_topology.monotone_close CategoryTheory.GrothendieckTopology.monotone_close @[simp] theorem close_close {X : C} (S : Sieve X) : J₁.close (J₁.close S) = J₁.close S := - le_antisymm (J₁.le_close_of_isClosed le_rfl (J₁.close_isClosed S)) - (J₁.monotone_close (J₁.le_close _)) + (J₁.closureOperator _).idempotent _ #align category_theory.grothendieck_topology.close_close CategoryTheory.GrothendieckTopology.close_close /-- @@ -162,20 +160,6 @@ theorem close_eq_top_iff_mem {X : C} (S : Sieve X) : J₁.close S = ⊤ ↔ S apply J₁.pullback_stable _ hS #align category_theory.grothendieck_topology.close_eq_top_iff_mem CategoryTheory.GrothendieckTopology.close_eq_top_iff_mem -/-- A Grothendieck topology induces a natural family of closure operators on sieves. -/ -@[simps!] -def closureOperator (X : C) : ClosureOperator (Sieve X) := - ClosureOperator.mk' J₁.close - (fun _ S₂ h => J₁.le_close_of_isClosed (h.trans (J₁.le_close _)) (J₁.close_isClosed S₂)) - J₁.le_close fun S => J₁.le_close_of_isClosed le_rfl (J₁.close_isClosed S) -#align category_theory.grothendieck_topology.closure_operator CategoryTheory.GrothendieckTopology.closureOperator - -@[simp] -theorem closed_iff_closed {X : C} (S : Sieve X) : - S ∈ (J₁.closureOperator X).closed ↔ J₁.IsClosed S := - (J₁.isClosed_iff_close_eq_self S).symm -#align category_theory.grothendieck_topology.closed_iff_closed CategoryTheory.GrothendieckTopology.closed_iff_closed - end GrothendieckTopology /-- diff --git a/Mathlib/Order/Closure.lean b/Mathlib/Order/Closure.lean index 2b9f73336ed62..af6f24417d78e 100644 --- a/Mathlib/Order/Closure.lean +++ b/Mathlib/Order/Closure.lean @@ -61,16 +61,22 @@ structure ClosureOperator [Preorder α] extends α →o α where le_closure' : ∀ x, x ≤ toFun x /-- Closures are idempotent -/ idempotent' : ∀ x, toFun (toFun x) = toFun x + /-- Predicate for an element to be closed. + + By default, this is defined as `c.IsClosed x := (c x = x)` (see `isClosed_iff`). + We allow an override to fix definitional equalities. -/ + IsClosed (x : α) : Prop := toFun x = x + isClosed_iff {x : α} : IsClosed x ↔ toFun x = x := by aesop #align closure_operator ClosureOperator namespace ClosureOperator instance [Preorder α] : OrderHomClass (ClosureOperator α) α α where coe c := c.1 - coe_injective' := by rintro ⟨⟩ ⟨⟩ h; congr; exact FunLike.ext' h + coe_injective' := by rintro ⟨⟩ ⟨⟩ h; obtain rfl := FunLike.ext' h; congr with x; simp [*] map_rel f _ _ h := f.mono h -initialize_simps_projections ClosureOperator (toFun → apply) +initialize_simps_projections ClosureOperator (toFun → apply, IsClosed → isClosed) section PartialOrder @@ -82,8 +88,11 @@ def id : ClosureOperator α where toOrderHom := OrderHom.id le_closure' _ := le_rfl idempotent' _ := rfl + IsClosed _ := True #align closure_operator.id ClosureOperator.id #align closure_operator.id_apply ClosureOperator.id_apply +#align closure_operator.closed ClosureOperator.IsClosed +#align closure_operator.mem_closed_iff ClosureOperator.isClosed_iff instance : Inhabited (ClosureOperator α) := ⟨id α⟩ @@ -91,9 +100,8 @@ instance : Inhabited (ClosureOperator α) := variable {α} [PartialOrder α] (c : ClosureOperator α) @[ext] -theorem ext : ∀ c₁ c₂ : ClosureOperator α, (c₁ : α → α) = (c₂ : α → α) → c₁ = c₂ - | ⟨⟨c₁, _⟩, _, _⟩, ⟨⟨c₂, _⟩, _, _⟩, h => by - congr +theorem ext : ∀ c₁ c₂ : ClosureOperator α, (c₁ : α → α) = (c₂ : α → α) → c₁ = c₂ := + FunLike.coe_injective #align closure_operator.ext ClosureOperator.ext /-- Constructor for a closure operator using the weaker idempotency axiom: `f (f x) ≤ f x`. -/ @@ -119,30 +127,20 @@ def mk₂ (f : α → α) (hf : ∀ x, x ≤ f x) (hmin : ∀ ⦃x y⦄, x ≤ f #align closure_operator.mk₂ ClosureOperator.mk₂ #align closure_operator.mk₂_apply ClosureOperator.mk₂_apply -/-- Expanded out version of `mk₂`. `p` implies being closed. This constructor should be used when -you already know a sufficient condition for being closed and using `mem_mk₃_closed` will avoid you -the (slight) hassle of having to prove it both inside and outside the constructor. -/ +/-- Construct a closure operator from an inflationary function `f` and a "closedness" predicate `p` +witnessing minimality of `f x` among closed elements greater than `x`. -/ @[simps!] -def mk₃ (f : α → α) (p : α → Prop) (hf : ∀ x, x ≤ f x) (hfp : ∀ x, p (f x)) - (hmin : ∀ ⦃x y⦄, x ≤ y → p y → f x ≤ y) : ClosureOperator α := - mk₂ f hf fun _ y hxy => hmin hxy (hfp y) -#align closure_operator.mk₃ ClosureOperator.mk₃ -#align closure_operator.mk₃_apply ClosureOperator.mk₃_apply - -/-- This lemma shows that the image of `x` of a closure operator built from the `mk₃` constructor -respects `p`, the property that was fed into it. -/ -theorem closure_mem_mk₃ {f : α → α} {p : α → Prop} {hf : ∀ x, x ≤ f x} {hfp : ∀ x, p (f x)} - {hmin : ∀ ⦃x y⦄, x ≤ y → p y → f x ≤ y} (x : α) : p (mk₃ f p hf hfp hmin x) := - hfp x -#align closure_operator.closure_mem_mk₃ ClosureOperator.closure_mem_mk₃ - -/-- Analogue of `closure_le_closed_iff_le` but with the `p` that was fed into the `mk₃` constructor. --/ -theorem closure_le_mk₃_iff {f : α → α} {p : α → Prop} {hf : ∀ x, x ≤ f x} {hfp : ∀ x, p (f x)} - {hmin : ∀ ⦃x y⦄, x ≤ y → p y → f x ≤ y} {x y : α} (hxy : x ≤ y) (hy : p y) : - mk₃ f p hf hfp hmin x ≤ y := - hmin hxy hy -#align closure_operator.closure_le_mk₃_iff ClosureOperator.closure_le_mk₃_iff +def ofPred (f : α → α) (p : α → Prop) (hf : ∀ x, x ≤ f x) (hfp : ∀ x, p (f x)) + (hmin : ∀ ⦃x y⦄, x ≤ y → p y → f x ≤ y) : ClosureOperator α where + __ := mk₂ f hf fun _ y hxy => hmin hxy (hfp y) + IsClosed := p + isClosed_iff := ⟨λ hx ↦ (hmin le_rfl hx).antisymm $ hf _, λ hx ↦ hx ▸ hfp _⟩ +#align closure_operator.mk₃ ClosureOperator.ofPred +#align closure_operator.mk₃_apply ClosureOperator.ofPred_apply +#align closure_operator.mem_mk₃_closed ClosureOperator.ofPred_isClosed + +#noalign closure_operator.closure_mem_ofPred +#noalign closure_operator.closure_le_ofPred_iff @[mono] theorem monotone : Monotone c := @@ -160,66 +158,48 @@ theorem idempotent (x : α) : c (c x) = c x := c.idempotent' x #align closure_operator.idempotent ClosureOperator.idempotent -theorem le_closure_iff (x y : α) : x ≤ c y ↔ c x ≤ c y := - ⟨fun h => c.idempotent y ▸ c.monotone h, fun h => (c.le_closure x).trans h⟩ -#align closure_operator.le_closure_iff ClosureOperator.le_closure_iff +@[simp] lemma isClosed_closure (x : α) : c.IsClosed (c x) := c.isClosed_iff.2 $ c.idempotent x +#align closure_operator.closure_is_closed ClosureOperator.isClosed_closure -/-- An element `x` is closed for the closure operator `c` if it is a fixed point for it. -/ -def closed : Set α := {x | c x = x} -#align closure_operator.closed ClosureOperator.closed +/-- The type of elements closed under a closure operator. -/ +abbrev Closeds := {x // c.IsClosed x} -theorem mem_closed_iff (x : α) : x ∈ c.closed ↔ c x = x := - Iff.rfl -#align closure_operator.mem_closed_iff ClosureOperator.mem_closed_iff +/-- Send an element to a closed element (by taking the closure). -/ +def toCloseds (x : α) : c.Closeds := ⟨c x, c.isClosed_closure x⟩ +#align closure_operator.to_closed ClosureOperator.toCloseds -theorem mem_closed_iff_closure_le (x : α) : x ∈ c.closed ↔ c x ≤ x := - ⟨le_of_eq, fun h => h.antisymm (c.le_closure x)⟩ -#align closure_operator.mem_closed_iff_closure_le ClosureOperator.mem_closed_iff_closure_le +variable {c} {x y : α} -theorem closure_eq_self_of_mem_closed {x : α} (h : x ∈ c.closed) : c x = x := - h -#align closure_operator.closure_eq_self_of_mem_closed ClosureOperator.closure_eq_self_of_mem_closed +theorem IsClosed.closure_eq : c.IsClosed x → c x = x := c.isClosed_iff.1 +#align closure_operator.closure_eq_self_of_mem_closed ClosureOperator.IsClosed.closure_eq -@[simp] -theorem closure_is_closed (x : α) : c x ∈ c.closed := - c.idempotent x -#align closure_operator.closure_is_closed ClosureOperator.closure_is_closed +theorem isClosed_iff_closure_le : c.IsClosed x ↔ c x ≤ x := + ⟨fun h ↦ h.closure_eq.le, fun h ↦ c.isClosed_iff.2 $ h.antisymm $ c.le_closure x⟩ +#align closure_operator.mem_closed_iff_closure_le ClosureOperator.isClosed_iff_closure_le /-- The set of closed elements for `c` is exactly its range. -/ -theorem closed_eq_range_close : c.closed = Set.range c := - Set.ext fun x => - ⟨fun h => ⟨x, h⟩, by - rintro ⟨y, rfl⟩ - apply c.idempotent⟩ -#align closure_operator.closed_eq_range_close ClosureOperator.closed_eq_range_close +theorem setOf_isClosed_eq_range_closure : {x | c.IsClosed x} = Set.range c := by + ext x; exact ⟨fun hx ↦ ⟨x, hx.closure_eq⟩, by rintro ⟨y, rfl⟩; exact c.isClosed_closure _⟩ +#align closure_operator.closed_eq_range_close ClosureOperator.setOf_isClosed_eq_range_closure -/-- Send an `x` to an element of the set of closed elements (by taking the closure). -/ -def toClosed (x : α) : c.closed := - ⟨c x, c.closure_is_closed x⟩ -#align closure_operator.to_closed ClosureOperator.toClosed +theorem le_closure_iff : x ≤ c y ↔ c x ≤ c y := + ⟨fun h ↦ c.idempotent y ▸ c.monotone h, (c.le_closure x).trans⟩ +#align closure_operator.le_closure_iff ClosureOperator.le_closure_iff @[simp] -theorem closure_le_closed_iff_le (x : α) {y : α} (hy : c.closed y) : c x ≤ y ↔ x ≤ y := by - rw [← c.closure_eq_self_of_mem_closed hy, ← le_closure_iff] -#align closure_operator.closure_le_closed_iff_le ClosureOperator.closure_le_closed_iff_le +theorem IsClosed.closure_le_iff (hy : c.IsClosed y) : c x ≤ y ↔ x ≤ y := by + rw [← hy.closure_eq, ← le_closure_iff] +#align closure_operator.closure_le_closed_iff_le ClosureOperator.IsClosed.closure_le_iff + +lemma closure_min (hxy : x ≤ y) (hy : c.IsClosed y) : c x ≤ y := hy.closure_le_iff.2 hxy /-- A closure operator is equal to the closure operator obtained by feeding `c.closed` into the -`mk₃` constructor. -/ -theorem eq_mk₃_closed (c : ClosureOperator α) : - c = - mk₃ c c.closed c.le_closure c.closure_is_closed fun x y hxy hy => - (c.closure_le_closed_iff_le x hy).2 hxy := by +`ofPred` constructor. -/ +theorem eq_ofPred_closed (c : ClosureOperator α) : + c = ofPred c c.IsClosed c.le_closure c.isClosed_closure fun x y ↦ closure_min := by ext rfl -#align closure_operator.eq_mk₃_closed ClosureOperator.eq_mk₃_closed - -/-- The property `p` fed into the `mk₃` constructor exactly corresponds to being closed. -/ -@[simp] theorem mem_mk₃_closed {f : α → α} {p : α → Prop} {hf hfp hmin} {x : α} : - x ∈ (mk₃ f p hf hfp hmin).closed ↔ p x := by - refine' ⟨λ hx ↦ _, λ hx ↦ (hmin le_rfl hx).antisymm (hf _)⟩ - rw [← closure_eq_self_of_mem_closed _ hx] - exact hfp _ -#align closure_operator.mem_mk₃_closed ClosureOperator.mem_mk₃_closedₓ +#align closure_operator.eq_mk₃_closed ClosureOperator.eq_ofPred_closed end PartialOrder @@ -234,9 +214,8 @@ theorem closure_top : c ⊤ = ⊤ := le_top.antisymm (c.le_closure _) #align closure_operator.closure_top ClosureOperator.closure_top -theorem top_mem_closed : ⊤ ∈ c.closed := - c.closure_top -#align closure_operator.top_mem_closed ClosureOperator.top_mem_closed +@[simp] lemma isClosed_top : c.IsClosed ⊤ := c.isClosed_iff.2 c.closure_top +#align closure_operator.top_mem_closed ClosureOperator.isClosed_top end OrderTop @@ -254,7 +233,7 @@ theorem closure_sup_closure_le (x y : α) : c x ⊔ c y ≤ c (x ⊔ y) := #align closure_operator.closure_sup_closure_le ClosureOperator.closure_sup_closure_le theorem closure_sup_closure_left (x y : α) : c (c x ⊔ y) = c (x ⊔ y) := - ((c.le_closure_iff _ _).1 + (le_closure_iff.1 (sup_le (c.monotone le_sup_left) (le_sup_right.trans (c.le_closure _)))).antisymm (c.monotone (sup_le_sup_right (c.le_closure _) _)) #align closure_operator.closure_sup_closure_left ClosureOperator.closure_sup_closure_left @@ -274,33 +253,23 @@ section CompleteLattice variable [CompleteLattice α] (c : ClosureOperator α) {p : α → Prop} /-- Define a closure operator from a predicate that's preserved under infima. -/ -def ofPred (p : α → Prop) (hsinf : ∀ s, (∀ a ∈ s, p a) → p (sInf s)) : ClosureOperator α := - ClosureOperator.mk₃ (fun a ↦ ⨅ b : {b // p b ∧ a ≤ b}, b) p +@[simps!] +def ofCompletePred (p : α → Prop) (hsinf : ∀ s, (∀ a ∈ s, p a) → p (sInf s)) : ClosureOperator α := + ofPred (fun a ↦ ⨅ b : {b // a ≤ b ∧ p b}, b) p (fun a ↦ by simp [forall_swap]) - (fun a ↦ hsinf _ $ forall_range_iff.2 $ fun b ↦ b.2.1) - (fun a b hab hb ↦ iInf_le_of_le ⟨b, hb, hab⟩ le_rfl) - -/-- This lemma shows that the image of `x` of a closure operator built from the `ofPred` constructor -respects `p`, the property that was fed into it. -/ -lemma ofPred_spec {sinf} (x : α) : p (ofPred p sinf x) := closure_mem_mk₃ _ - -/-- The property `p` fed into the `ofPred` constructor exactly corresponds to being closed. -/ -@[simp] lemma closed_ofPred {hsinf} : (ofPred p hsinf).closed = {x | p x} := by - ext; exact mem_mk₃_closed - -/-- The property `p` fed into the `ofPred` constructor exactly corresponds to being closed. -/ -lemma mem_closed_ofPred {hsinf} {x : α} : x ∈ (ofPred p hsinf).closed ↔ p x := mem_mk₃_closed + (fun a ↦ hsinf _ $ forall_range_iff.2 $ fun b ↦ b.2.2) + (fun a b hab hb ↦ iInf_le_of_le ⟨b, hab, hb⟩ le_rfl) @[simp] theorem closure_iSup_closure (f : ι → α) : c (⨆ i, c (f i)) = c (⨆ i, f i) := - le_antisymm ((c.le_closure_iff _ _).1 <| iSup_le fun i => c.monotone <| le_iSup f i) <| + le_antisymm (le_closure_iff.1 <| iSup_le fun i => c.monotone <| le_iSup f i) <| c.monotone <| iSup_mono fun _ => c.le_closure _ #align closure_operator.closure_supr_closure ClosureOperator.closure_iSup_closure @[simp] theorem closure_iSup₂_closure (f : ∀ i, κ i → α) : c (⨆ (i) (j), c (f i j)) = c (⨆ (i) (j), f i j) := - le_antisymm ((c.le_closure_iff _ _).1 <| iSup₂_le fun i j => c.monotone <| le_iSup₂ i j) <| + le_antisymm (le_closure_iff.1 <| iSup₂_le fun i j => c.monotone <| le_iSup₂ i j) <| c.monotone <| iSup₂_mono fun _ _ => c.le_closure _ #align closure_operator.closure_supr₂_closure ClosureOperator.closure_iSup₂_closure @@ -389,7 +358,7 @@ theorem idempotent (x : α) : u (l (u (l x))) = u (l x) := #align lower_adjoint.idempotent LowerAdjoint.idempotent theorem le_closure_iff (x y : α) : x ≤ u (l y) ↔ u (l x) ≤ u (l y) := - l.closureOperator.le_closure_iff _ _ + l.closureOperator.le_closure_iff #align lower_adjoint.le_closure_iff LowerAdjoint.le_closure_iff end PartialOrder @@ -417,7 +386,7 @@ section PartialOrder variable [PartialOrder α] [PartialOrder β] {u : β → α} (l : LowerAdjoint u) theorem mem_closed_iff_closure_le (x : α) : x ∈ l.closed ↔ u (l x) ≤ x := - l.closureOperator.mem_closed_iff_closure_le _ + l.closureOperator.isClosed_iff_closure_le #align lower_adjoint.mem_closed_iff_closure_le LowerAdjoint.mem_closed_iff_closure_le @[simp, nolint simpNF] -- Porting note: lemma does prove itself, seems to be a linter error @@ -427,7 +396,7 @@ theorem closure_is_closed (x : α) : u (l x) ∈ l.closed := /-- The set of closed elements for `l` is the range of `u ∘ l`. -/ theorem closed_eq_range_close : l.closed = Set.range (u ∘ l) := - l.closureOperator.closed_eq_range_close + l.closureOperator.setOf_isClosed_eq_range_closure #align lower_adjoint.closed_eq_range_close LowerAdjoint.closed_eq_range_close /-- Send an `x` to an element of the set of closed elements (by taking the closure). -/ @@ -437,7 +406,7 @@ def toClosed (x : α) : l.closed := @[simp] theorem closure_le_closed_iff_le (x : α) {y : α} (hy : l.closed y) : u (l x) ≤ y ↔ x ≤ y := - l.closureOperator.closure_le_closed_iff_le x hy + (show l.closureOperator.IsClosed y from hy).closure_le_iff #align lower_adjoint.closure_le_closed_iff_le LowerAdjoint.closure_le_closed_iff_le end PartialOrder @@ -572,10 +541,10 @@ def GaloisConnection.closureOperator [PartialOrder α] [Preorder β] {l : α → #align galois_connection.closure_operator_apply GaloisConnection.closureOperator_apply /-- The set of closed elements has a Galois insertion to the underlying type. -/ -def _root_.ClosureOperator.gi [PartialOrder α] (c : ClosureOperator α) : - GaloisInsertion c.toClosed (↑) where - choice x hx := ⟨x, hx.antisymm (c.le_closure x)⟩ - gc _ y := c.closure_le_closed_iff_le _ y.2 +def ClosureOperator.gi [PartialOrder α] (c : ClosureOperator α) : + GaloisInsertion c.toCloseds (↑) where + choice x hx := ⟨x, isClosed_iff_closure_le.2 hx⟩ + gc _ y := y.2.closure_le_iff le_l_u _ := c.le_closure _ choice_eq x hx := le_antisymm (c.le_closure x) hx #align closure_operator.gi ClosureOperator.gi diff --git a/Mathlib/Order/SupClosed.lean b/Mathlib/Order/SupClosed.lean index c485fbbdd6b49..18169ee234f31 100644 --- a/Mathlib/Order/SupClosed.lean +++ b/Mathlib/Order/SupClosed.lean @@ -252,7 +252,8 @@ section SemilatticeSup variable [SemilatticeSup α] [SemilatticeSup β] {s t : Set α} {a b : α} /-- Every set in a join-semilattice generates a set closed under join. -/ -def supClosure : ClosureOperator (Set α) := ClosureOperator.mk₃ +@[simps! isClosed] +def supClosure : ClosureOperator (Set α) := .ofPred (λ s ↦ {a | ∃ (t : Finset α) (ht : t.Nonempty), ↑t ⊆ s ∧ t.sup' ht id = a}) SupClosed (λ s a ha ↦ ⟨{a}, singleton_nonempty _, by simpa⟩) @@ -266,12 +267,11 @@ def supClosure : ClosureOperator (Set α) := ClosureOperator.mk₃ @[simp] lemma subset_supClosure {s : Set α} : s ⊆ supClosure s := supClosure.le_closure _ -@[simp] lemma supClosed_supClosure {s : Set α} : SupClosed (supClosure s) := -ClosureOperator.closure_mem_mk₃ _ +@[simp] lemma supClosed_supClosure : SupClosed (supClosure s) := supClosure.isClosed_closure _ lemma supClosure_mono : Monotone (supClosure : Set α → Set α) := supClosure.monotone -@[simp] lemma supClosure_eq_self : supClosure s = s ↔ SupClosed s := ClosureOperator.mem_mk₃_closed +@[simp] lemma supClosure_eq_self : supClosure s = s ↔ SupClosed s := supClosure.isClosed_iff.symm alias ⟨_, SupClosed.supClosure_eq⟩ := supClosure_eq_self @@ -296,11 +296,7 @@ lemma finsetSup'_mem_supClosure {ι : Type*} {t : Finset ι} (ht : t.Nonempty) { (hf : ∀ i ∈ t, f i ∈ s) : t.sup' ht f ∈ supClosure s := supClosed_supClosure.finsetSup'_mem _ $ fun _i hi ↦ subset_supClosure $ hf _ hi -@[simp] lemma supClosure_closed : supClosure.closed = {s : Set α | SupClosed s} := by - ext; exact ClosureOperator.mem_mk₃_closed - -lemma supClosure_min (hst : s ⊆ t) (ht : SupClosed t) : supClosure s ⊆ t := - ClosureOperator.closure_le_mk₃_iff hst ht +lemma supClosure_min : s ⊆ t → SupClosed t → supClosure s ⊆ t := supClosure.closure_min /-- The semilatice generated by a finite set is finite. -/ protected lemma Set.Finite.supClosure (hs : s.Finite) : (supClosure s).Finite := by @@ -319,7 +315,8 @@ section SemilatticeInf variable [SemilatticeInf α] [SemilatticeInf β] {s t : Set α} {a b : α} /-- Every set in a join-semilattice generates a set closed under join. -/ -def infClosure : ClosureOperator (Set α) := ClosureOperator.mk₃ +@[simps! isClosed] +def infClosure : ClosureOperator (Set α) := ClosureOperator.ofPred (λ s ↦ {a | ∃ (t : Finset α) (ht : t.Nonempty), ↑t ⊆ s ∧ t.inf' ht id = a}) InfClosed (λ s a ha ↦ ⟨{a}, singleton_nonempty _, by simpa⟩) @@ -333,12 +330,11 @@ def infClosure : ClosureOperator (Set α) := ClosureOperator.mk₃ @[simp] lemma subset_infClosure {s : Set α} : s ⊆ infClosure s := infClosure.le_closure _ -@[simp] lemma infClosed_infClosure {s : Set α} : InfClosed (infClosure s) := -ClosureOperator.closure_mem_mk₃ _ +@[simp] lemma infClosed_infClosure : InfClosed (infClosure s) := infClosure.isClosed_closure _ lemma infClosure_mono : Monotone (infClosure : Set α → Set α) := infClosure.monotone -@[simp] lemma infClosure_eq_self : infClosure s = s ↔ InfClosed s := ClosureOperator.mem_mk₃_closed +@[simp] lemma infClosure_eq_self : infClosure s = s ↔ InfClosed s := infClosure.isClosed_iff.symm alias ⟨_, InfClosed.infClosure_eq⟩ := infClosure_eq_self @@ -364,11 +360,7 @@ lemma finsetInf'_mem_infClosure {ι : Type*} {t : Finset ι} (ht : t.Nonempty) { (hf : ∀ i ∈ t, f i ∈ s) : t.inf' ht f ∈ infClosure s := infClosed_infClosure.finsetInf'_mem _ $ fun _i hi ↦ subset_infClosure $ hf _ hi -@[simp] lemma infClosure_closed : infClosure.closed = {s : Set α | InfClosed s} := by - ext; exact ClosureOperator.mem_mk₃_closed - -lemma infClosure_min (hst : s ⊆ t) (ht : InfClosed t) : infClosure s ⊆ t := - ClosureOperator.closure_le_mk₃_iff hst ht +lemma infClosure_min : s ⊆ t → InfClosed t → infClosure s ⊆ t := infClosure.closure_min /-- The semilatice generated by a finite set is finite. -/ protected lemma Set.Finite.infClosure (hs : s.Finite) : (infClosure s).Finite := by @@ -387,25 +379,22 @@ section Lattice variable [Lattice α] {s t : Set α} /-- Every set in a join-semilattice generates a set closed under join. -/ +@[simps! isClosed] def latticeClosure : ClosureOperator (Set α) := - ClosureOperator.ofPred IsSublattice $ fun _ ↦ isSublattice_sInter + .ofCompletePred IsSublattice $ fun _ ↦ isSublattice_sInter @[simp] lemma subset_latticeClosure : s ⊆ latticeClosure s := latticeClosure.le_closure _ @[simp] lemma isSublattice_latticeClosure : IsSublattice (latticeClosure s) := - ClosureOperator.ofPred_spec _ + latticeClosure.isClosed_closure _ -lemma latticeClosure_min (hst : s ⊆ t) (ht : IsSublattice t) : latticeClosure s ⊆ t := by - rw [latticeClosure, ClosureOperator.ofPred] - exact ClosureOperator.closure_le_mk₃_iff hst ht +lemma latticeClosure_min : s ⊆ t → IsSublattice t → latticeClosure s ⊆ t := + latticeClosure.closure_min lemma latticeClosure_mono : Monotone (latticeClosure : Set α → Set α) := latticeClosure.monotone @[simp] lemma latticeClosure_eq_self : latticeClosure s = s ↔ IsSublattice s := - ClosureOperator.mem_closed_ofPred - -@[simp] lemma latticeClosure_closed : latticeClosure.closed = {s : Set α | IsSublattice s} := - ClosureOperator.closed_ofPred + latticeClosure.isClosed_iff.symm alias ⟨_, IsSublattice.latticeClosure_eq⟩ := latticeClosure_eq_self From 56c6c0952afa7911701c775dea510efbe9626ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 20 Dec 2023 15:54:21 +0000 Subject: [PATCH 095/353] feat: `f i * f j`, `f k * f l` are independent if `f` is (#8971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also prove that a subsingleton family is always independent and that an independent family implies the measure is a probability measure. This latter result means we can drop `IsProbabilityMeasure μ` assumptions from many theorems. From PFR Co-authored-by: sgouezel --- Mathlib/Probability/Independence/Basic.lean | 116 ++++++++++++++---- .../Probability/Independence/Conditional.lean | 84 +++++++++++-- Mathlib/Probability/Independence/Kernel.lean | 107 +++++++++++++--- 3 files changed, 260 insertions(+), 47 deletions(-) diff --git a/Mathlib/Probability/Independence/Basic.lean b/Mathlib/Probability/Independence/Basic.lean index 502124125e079..18a7e4b341b6c 100644 --- a/Mathlib/Probability/Independence/Basic.lean +++ b/Mathlib/Probability/Independence/Basic.lean @@ -668,42 +668,113 @@ theorem IndepFun.comp {_mβ : MeasurableSpace β} {_mβ' : MeasurableSpace β'} kernel.IndepFun.comp hfg hφ hψ #align probability_theory.indep_fun.comp ProbabilityTheory.IndepFun.comp +section iIndepFun +variable {β : ι → Type*} {m : ∀ i, MeasurableSpace (β i)} {f : ∀ i, Ω → β i} + +@[nontriviality] +lemma iIndepFun.of_subsingleton [IsProbabilityMeasure μ] [Subsingleton ι] : iIndepFun m f μ := + kernel.iIndepFun.of_subsingleton + +lemma iIndepFun.isProbabilityMeasure (h : iIndepFun m f μ) : IsProbabilityMeasure μ := + ⟨by simpa using h.meas_biInter (S := ∅) (s := fun _ ↦ univ)⟩ + /-- If `f` is a family of mutually independent random variables (`iIndepFun m f μ`) and `S, T` are two disjoint finite index sets, then the tuple formed by `f i` for `i ∈ S` is independent of the tuple `(f i)_i` for `i ∈ T`. -/ -theorem iIndepFun.indepFun_finset [IsProbabilityMeasure μ] {ι : Type*} {β : ι → Type*} - {m : ∀ i, MeasurableSpace (β i)} {f : ∀ i, Ω → β i} (S T : Finset ι) (hST : Disjoint S T) - (hf_Indep : iIndepFun m f μ) (hf_meas : ∀ i, Measurable (f i)) : - IndepFun (fun a (i : S) => f i a) (fun a (i : T) => f i a) μ := +lemma iIndepFun.indepFun_finset (S T : Finset ι) (hST : Disjoint S T) (hf_Indep : iIndepFun m f μ) + (hf_meas : ∀ i, Measurable (f i)) : + IndepFun (fun a (i : S) ↦ f i a) (fun a (i : T) ↦ f i a) μ := + have := hf_Indep.isProbabilityMeasure kernel.iIndepFun.indepFun_finset S T hST hf_Indep hf_meas set_option linter.uppercaseLean3 false in #align probability_theory.Indep_fun.indep_fun_finset ProbabilityTheory.iIndepFun.indepFun_finset -theorem iIndepFun.indepFun_prod [IsProbabilityMeasure μ] {ι : Type*} {β : ι → Type*} - {m : ∀ i, MeasurableSpace (β i)} {f : ∀ i, Ω → β i} (hf_Indep : iIndepFun m f μ) - (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : +lemma iIndepFun.indepFun_prod_mk (hf_Indep : iIndepFun m f μ) (hf_meas : ∀ i, Measurable (f i)) + (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : IndepFun (fun a => (f i a, f j a)) (f k) μ := - kernel.iIndepFun.indepFun_prod hf_Indep hf_meas i j k hik hjk + have := hf_Indep.isProbabilityMeasure + kernel.iIndepFun.indepFun_prod_mk hf_Indep hf_meas i j k hik hjk set_option linter.uppercaseLean3 false in -#align probability_theory.Indep_fun.indep_fun_prod ProbabilityTheory.iIndepFun.indepFun_prod +#align probability_theory.Indep_fun.indep_fun_prod ProbabilityTheory.iIndepFun.indepFun_prod_mk + +open Finset in +lemma iIndepFun.indepFun_prod_mk_prod_mk (h_indep : iIndepFun m f μ) (hf : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + IndepFun (fun a ↦ (f i a, f j a)) (fun a ↦ (f k a, f l a)) μ := by + classical + let g (i j : ι) (v : Π x : ({i, j} : Finset ι), β x) : β i × β j := + ⟨v ⟨i, mem_insert_self _ _⟩, v ⟨j, mem_insert_of_mem $ mem_singleton_self _⟩⟩ + have hg (i j : ι) : Measurable (g i j) := by measurability + exact (h_indep.indepFun_finset {i, j} {k, l} (by aesop) hf).comp (hg i j) (hg k l) + +end iIndepFun + +section Mul +variable {β : Type*} {m : MeasurableSpace β} [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} @[to_additive] -theorem iIndepFun.mul [IsProbabilityMeasure μ] {ι : Type*} {β : Type*} {m : MeasurableSpace β} - [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} (hf_Indep : iIndepFun (fun _ => m) f μ) +lemma iIndepFun.indepFun_mul_left (hf_indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : IndepFun (f i * f j) (f k) μ := - kernel.iIndepFun.mul hf_Indep hf_meas i j k hik hjk + have := hf_indep.isProbabilityMeasure + kernel.iIndepFun.indepFun_mul_left hf_indep hf_meas i j k hik hjk set_option linter.uppercaseLean3 false in -#align probability_theory.Indep_fun.mul ProbabilityTheory.iIndepFun.mul +#align probability_theory.Indep_fun.mul ProbabilityTheory.iIndepFun.indepFun_mul_left set_option linter.uppercaseLean3 false in -#align probability_theory.Indep_fun.add ProbabilityTheory.iIndepFun.add +#align probability_theory.Indep_fun.add ProbabilityTheory.iIndepFun.indepFun_add_left + +@[to_additive] +lemma iIndepFun.indepFun_mul_right (hf_indep : iIndepFun (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hij : i ≠ j) (hik : i ≠ k) : + IndepFun (f i) (f j * f k) μ := + have := hf_indep.isProbabilityMeasure + kernel.iIndepFun.indepFun_mul_right hf_indep hf_meas i j k hij hik @[to_additive] -theorem iIndepFun.indepFun_finset_prod_of_not_mem [IsProbabilityMeasure μ] {ι : Type*} {β : Type*} - {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} - (hf_Indep : iIndepFun (fun _ => m) f μ) (hf_meas : ∀ i, Measurable (f i)) {s : Finset ι} {i : ι} - (hi : i ∉ s) : +lemma iIndepFun.indepFun_mul_mul (hf_indep : iIndepFun (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + IndepFun (f i * f j) (f k * f l) μ := + have := hf_indep.isProbabilityMeasure + kernel.iIndepFun.indepFun_mul_mul hf_indep hf_meas i j k l hik hil hjk hjl + +end Mul + +section Div +variable {β : Type*} {m : MeasurableSpace β} [Div β] [MeasurableDiv₂ β] {f : ι → Ω → β} + +@[to_additive] +lemma iIndepFun.indepFun_div_left (hf_indep : iIndepFun (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : + IndepFun (f i / f j) (f k) μ := + have := hf_indep.isProbabilityMeasure + kernel.iIndepFun.indepFun_div_left hf_indep hf_meas i j k hik hjk + +@[to_additive] +lemma iIndepFun.indepFun_div_right (hf_indep : iIndepFun (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hij : i ≠ j) (hik : i ≠ k) : + IndepFun (f i) (f j / f k) μ := + have := hf_indep.isProbabilityMeasure + kernel.iIndepFun.indepFun_div_right hf_indep hf_meas i j k hij hik + +@[to_additive] +lemma iIndepFun.indepFun_div_div (hf_indep : iIndepFun (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + IndepFun (f i / f j) (f k / f l) μ := + have := hf_indep.isProbabilityMeasure + kernel.iIndepFun.indepFun_div_div hf_indep hf_meas i j k l hik hil hjk hjl + +end Div + +section CommMonoid +variable {β : Type*} {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} + +@[to_additive] +lemma iIndepFun.indepFun_finset_prod_of_not_mem (hf_Indep : iIndepFun (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) {s : Finset ι} {i : ι} (hi : i ∉ s) : IndepFun (∏ j in s, f j) (f i) μ := + have := hf_Indep.isProbabilityMeasure kernel.iIndepFun.indepFun_finset_prod_of_not_mem hf_Indep hf_meas hi set_option linter.uppercaseLean3 false in #align probability_theory.Indep_fun.indep_fun_finset_prod_of_not_mem ProbabilityTheory.iIndepFun.indepFun_finset_prod_of_not_mem @@ -711,16 +782,17 @@ set_option linter.uppercaseLean3 false in #align probability_theory.Indep_fun.indep_fun_finset_sum_of_not_mem ProbabilityTheory.iIndepFun.indepFun_finset_sum_of_not_mem @[to_additive] -theorem iIndepFun.indepFun_prod_range_succ [IsProbabilityMeasure μ] {β : Type*} - {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ℕ → Ω → β} - (hf_Indep : iIndepFun (fun _ => m) f μ) (hf_meas : ∀ i, Measurable (f i)) (n : ℕ) : - IndepFun (∏ j in Finset.range n, f j) (f n) μ := +lemma iIndepFun.indepFun_prod_range_succ {f : ℕ → Ω → β} (hf_Indep : iIndepFun (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) (n : ℕ) : IndepFun (∏ j in Finset.range n, f j) (f n) μ := + have := hf_Indep.isProbabilityMeasure kernel.iIndepFun.indepFun_prod_range_succ hf_Indep hf_meas n set_option linter.uppercaseLean3 false in #align probability_theory.Indep_fun.indep_fun_prod_range_succ ProbabilityTheory.iIndepFun.indepFun_prod_range_succ set_option linter.uppercaseLean3 false in #align probability_theory.Indep_fun.indep_fun_sum_range_succ ProbabilityTheory.iIndepFun.indepFun_sum_range_succ +end CommMonoid + theorem iIndepSet.iIndepFun_indicator [Zero β] [One β] {m : MeasurableSpace β} {s : ι → Set Ω} (hs : iIndepSet s μ) : iIndepFun (fun _n => m) (fun n => (s n).indicator fun _ω => 1) μ := diff --git a/Mathlib/Probability/Independence/Conditional.lean b/Mathlib/Probability/Independence/Conditional.lean index 537198d6ff5d3..c0c12d16890ba 100644 --- a/Mathlib/Probability/Independence/Conditional.lean +++ b/Mathlib/Probability/Independence/Conditional.lean @@ -425,7 +425,7 @@ end CondIndepSet section CondIndep @[symm] -theorem CondIndep.symm {m' m₁ m₂: MeasurableSpace Ω} [mΩ : MeasurableSpace Ω] +theorem CondIndep.symm {m' m₁ m₂ : MeasurableSpace Ω} [mΩ : MeasurableSpace Ω] [StandardBorelSpace Ω] [Nonempty Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] (h : CondIndep m' m₁ m₂ hm' μ) : CondIndep m' m₂ m₁ hm' μ := @@ -450,7 +450,7 @@ theorem condIndep_of_condIndep_of_le_left {m' m₁ m₂ m₃ : MeasurableSpace CondIndep m' m₃ m₂ hm' μ := kernel.indep_of_indep_of_le_left h_indep h31 -theorem condIndep_of_condIndep_of_le_right {m' m₁ m₂ m₃: MeasurableSpace Ω} +theorem condIndep_of_condIndep_of_le_right {m' m₁ m₂ m₃ : MeasurableSpace Ω} [mΩ : MeasurableSpace Ω] [StandardBorelSpace Ω] [Nonempty Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] (h_indep : CondIndep m' m₁ m₂ hm' μ) (h32 : m₃ ≤ m₂) : @@ -694,6 +694,13 @@ theorem CondIndepFun.comp {γ γ' : Type*} {_mβ : MeasurableSpace β} {_mβ' : CondIndepFun m' hm' (φ ∘ f) (ψ ∘ g) μ := kernel.IndepFun.comp hfg hφ hψ +section iCondIndepFun +variable {β : ι → Type*} {m : ∀ i, MeasurableSpace (β i)} {f : ∀ i, Ω → β i} + +@[nontriviality] +lemma iCondIndepFun.of_subsingleton [Subsingleton ι] : iCondIndepFun m' hm' m f μ := + kernel.iIndepFun.of_subsingleton + /-- If `f` is a family of mutually conditionally independent random variables (`iCondIndepFun m' hm' m f μ`) and `S, T` are two disjoint finite index sets, then the tuple formed by `f i` for `i ∈ S` is conditionally independent of the tuple `(f i)_i` for `i ∈ T`. -/ @@ -703,34 +710,91 @@ theorem iCondIndepFun.condIndepFun_finset {β : ι → Type*} CondIndepFun m' hm' (fun a (i : S) => f i a) (fun a (i : T) => f i a) μ := kernel.iIndepFun.indepFun_finset S T hST hf_Indep hf_meas -theorem iCondIndepFun.condIndepFun_prod {β : ι → Type*} +theorem iCondIndepFun.condIndepFun_prod_mk {β : ι → Type*} {m : ∀ i, MeasurableSpace (β i)} {f : ∀ i, Ω → β i} (hf_Indep : iCondIndepFun m' hm' m f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : CondIndepFun m' hm' (fun a => (f i a, f j a)) (f k) μ := - kernel.iIndepFun.indepFun_prod hf_Indep hf_meas i j k hik hjk + kernel.iIndepFun.indepFun_prod_mk hf_Indep hf_meas i j k hik hjk + +open Finset in +lemma iCondIndepFun.condIndepFun_prod_mk_prod_mk (h_indep : iCondIndepFun m' hm' m f μ) + (hf : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + CondIndepFun m' hm' (fun a ↦ (f i a, f j a)) (fun a ↦ (f k a, f l a)) μ := by + classical + let g (i j : ι) (v : Π x : ({i, j} : Finset ι), β x) : β i × β j := + ⟨v ⟨i, mem_insert_self _ _⟩, v ⟨j, mem_insert_of_mem $ mem_singleton_self _⟩⟩ + have hg (i j : ι) : Measurable (g i j) := by measurability + exact (h_indep.indepFun_finset {i, j} {k, l} (by aesop) hf).comp (hg i j) (hg k l) + +end iCondIndepFun + +section Mul +variable {β : Type*} {m : MeasurableSpace β} [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} @[to_additive] -theorem iCondIndepFun.mul {m : MeasurableSpace β} - [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} (hf_Indep : iCondIndepFun m' hm' (fun _ => m) f μ) +lemma iCondIndepFun.indepFun_mul_left (hf_indep : iCondIndepFun m' hm' (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : CondIndepFun m' hm' (f i * f j) (f k) μ := - kernel.iIndepFun.mul hf_Indep hf_meas i j k hik hjk + kernel.iIndepFun.indepFun_mul_left hf_indep hf_meas i j k hik hjk + +@[to_additive] +lemma iCondIndepFun.indepFun_mul_right (hf_indep : iCondIndepFun m' hm' (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hij : i ≠ j) (hik : i ≠ k) : + CondIndepFun m' hm' (f i) (f j * f k) μ := + kernel.iIndepFun.indepFun_mul_right hf_indep hf_meas i j k hij hik + +@[to_additive] +lemma iCondIndepFun.indepFun_mul_mul (hf_indep : iCondIndepFun m' hm' (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + CondIndepFun m' hm' (f i * f j) (f k * f l) μ := + kernel.iIndepFun.indepFun_mul_mul hf_indep hf_meas i j k l hik hil hjk hjl + +end Mul + +section Div +variable {β : Type*} {m : MeasurableSpace β} [Div β] [MeasurableDiv₂ β] {f : ι → Ω → β} + +@[to_additive] +lemma iCondIndepFun.indepFun_div_left (hf_indep : iCondIndepFun m' hm' (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : + CondIndepFun m' hm' (f i / f j) (f k) μ := + kernel.iIndepFun.indepFun_div_left hf_indep hf_meas i j k hik hjk + +@[to_additive] +lemma iCondIndepFun.indepFun_div_right (hf_indep : iCondIndepFun m' hm' (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hij : i ≠ j) (hik : i ≠ k) : + CondIndepFun m' hm' (f i) (f j / f k) μ := + kernel.iIndepFun.indepFun_div_right hf_indep hf_meas i j k hij hik + +@[to_additive] +lemma iCondIndepFun.indepFun_div_div (hf_indep : iCondIndepFun m' hm' (fun _ ↦ m) f μ) + (hf_meas : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + CondIndepFun m' hm' (f i / f j) (f k / f l) μ := + kernel.iIndepFun.indepFun_div_div hf_indep hf_meas i j k l hik hil hjk hjl + +end Div + +section CommMonoid +variable {β : Type*} {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} @[to_additive] theorem iCondIndepFun.condIndepFun_finset_prod_of_not_mem - {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} (hf_Indep : iCondIndepFun m' hm' (fun _ => m) f μ) (hf_meas : ∀ i, Measurable (f i)) {s : Finset ι} {i : ι} (hi : i ∉ s) : CondIndepFun m' hm' (∏ j in s, f j) (f i) μ := kernel.iIndepFun.indepFun_finset_prod_of_not_mem hf_Indep hf_meas hi @[to_additive] -theorem iCondIndepFun.condIndepFun_prod_range_succ - {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ℕ → Ω → β} +theorem iCondIndepFun.condIndepFun_prod_range_succ {f : ℕ → Ω → β} (hf_Indep : iCondIndepFun m' hm' (fun _ => m) f μ) (hf_meas : ∀ i, Measurable (f i)) (n : ℕ) : CondIndepFun m' hm' (∏ j in Finset.range n, f j) (f n) μ := kernel.iIndepFun.indepFun_prod_range_succ hf_Indep hf_meas n +end CommMonoid + theorem iCondIndepSet.iCondIndepFun_indicator [Zero β] [One β] {m : MeasurableSpace β} {s : ι → Set Ω} (hs : iCondIndepSet m' hm' s μ) : iCondIndepFun m' hm' (fun _n => m) (fun n => (s n).indicator fun _ω => 1) μ := diff --git a/Mathlib/Probability/Independence/Kernel.lean b/Mathlib/Probability/Independence/Kernel.lean index a91c7306ecc90..89457332a0f2f 100644 --- a/Mathlib/Probability/Independence/Kernel.lean +++ b/Mathlib/Probability/Independence/Kernel.lean @@ -809,14 +809,28 @@ theorem IndepFun.comp {mβ : MeasurableSpace β} {mβ' : MeasurableSpace β'} · exact ⟨φ ⁻¹' A, hφ hA, Set.preimage_comp.symm⟩ · exact ⟨ψ ⁻¹' B, hψ hB, Set.preimage_comp.symm⟩ +section iIndepFun +variable {β : ι → Type*} {m : ∀ i, MeasurableSpace (β i)} {f : ∀ i, Ω → β i} + +@[nontriviality] +lemma iIndepFun.of_subsingleton [IsMarkovKernel κ] [Subsingleton ι] : iIndepFun m f κ μ := by + refine (iIndepFun_iff_measure_inter_preimage_eq_mul ..).2 fun s f' hf' ↦ ?_ + obtain rfl | ⟨x, hx⟩ := s.eq_empty_or_nonempty + · simp + · have : s = {x} := by ext y; simp [Subsingleton.elim y x, hx] + simp [this] + +lemma iIndepFun.ae_isProbabilityMeasure (h : iIndepFun m f κ μ) : + ∀ᵐ a ∂μ, IsProbabilityMeasure (κ a) := by + simpa [isProbabilityMeasure_iff] using h.meas_biInter (S := ∅) (s := fun _ ↦ Set.univ) + /-- If `f` is a family of mutually independent random variables (`iIndepFun m f μ`) and `S, T` are two disjoint finite index sets, then the tuple formed by `f i` for `i ∈ S` is independent of the tuple `(f i)_i` for `i ∈ T`. -/ -theorem iIndepFun.indepFun_finset [IsMarkovKernel κ] {ι : Type*} {β : ι → Type*} - {m : ∀ i, MeasurableSpace (β i)} {f : ∀ i, Ω → β i} (S T : Finset ι) (hST : Disjoint S T) +theorem iIndepFun.indepFun_finset [IsMarkovKernel κ] (S T : Finset ι) (hST : Disjoint S T) (hf_Indep : iIndepFun m f κ μ) (hf_meas : ∀ i, Measurable (f i)) : IndepFun (fun a (i : S) => f i a) (fun a (i : T) => f i a) κ μ := by - -- We introduce π-systems, build from the π-system of boxes which generates `MeasurableSpace.pi`. + -- We introduce π-systems, built from the π-system of boxes which generates `MeasurableSpace.pi`. let πSβ := Set.pi (Set.univ : Set S) '' Set.pi (Set.univ : Set S) fun i => { s : Set (β i) | MeasurableSet[m i] s } let πS := { s : Set Ω | ∃ t ∈ πSβ, (fun a (i : S) => f i a) ⁻¹' t = s } @@ -905,8 +919,7 @@ theorem iIndepFun.indepFun_finset [IsMarkovKernel κ] {ι : Type*} {β : ι → show κ a (f i ⁻¹' (sets_s' i ∩ sets_t' i)) = κ a (f i ⁻¹' (sets_t' i)) rw [h_sets_s'_univ hi, Set.univ_inter] -theorem iIndepFun.indepFun_prod [IsMarkovKernel κ] {ι : Type*} {β : ι → Type*} - {m : ∀ i, MeasurableSpace (β i)} {f : ∀ i, Ω → β i} (hf_Indep : iIndepFun m f κ μ) +theorem iIndepFun.indepFun_prod_mk [IsMarkovKernel κ] (hf_Indep : iIndepFun m f κ μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : IndepFun (fun a => (f i a, f j a)) (f k) κ μ := by classical @@ -932,21 +945,84 @@ theorem iIndepFun.indepFun_prod [IsMarkovKernel κ] {ι : Type*} {β : ι → Ty simp only [Finset.mem_insert, Finset.mem_singleton, not_or] exact ⟨hik.symm, hjk.symm⟩ +open Finset in +lemma iIndepFun.indepFun_prod_mk_prod_mk [IsMarkovKernel κ] (hf_indep : iIndepFun m f κ μ) + (hf_meas : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + IndepFun (fun a ↦ (f i a, f j a)) (fun a ↦ (f k a, f l a)) κ μ := by + classical + let g (i j : ι) (v : Π x : ({i, j} : Finset ι), β x) : β i × β j := + ⟨v ⟨i, mem_insert_self _ _⟩, v ⟨j, mem_insert_of_mem $ mem_singleton_self _⟩⟩ + have hg (i j : ι) : Measurable (g i j) := by measurability + exact (hf_indep.indepFun_finset {i, j} {k, l} (by aesop) hf_meas).comp (hg i j) (hg k l) + +end iIndepFun + +section Mul +variable {β : Type*} {m : MeasurableSpace β} [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} + [IsMarkovKernel κ] + @[to_additive] -theorem iIndepFun.mul [IsMarkovKernel κ] {ι : Type*} {β : Type*} {m : MeasurableSpace β} - [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} (hf_Indep : iIndepFun (fun _ => m) f κ μ) +lemma iIndepFun.indepFun_mul_left (hf_indep : iIndepFun (fun _ ↦ m) f κ μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : IndepFun (f i * f j) (f k) κ μ := by have : IndepFun (fun ω => (f i ω, f j ω)) (f k) κ μ := - hf_Indep.indepFun_prod hf_meas i j k hik hjk + hf_indep.indepFun_prod_mk hf_meas i j k hik hjk change IndepFun ((fun p : β × β => p.fst * p.snd) ∘ fun ω => (f i ω, f j ω)) (id ∘ f k) κ μ - exact IndepFun.comp this (measurable_fst.mul measurable_snd) measurable_id + exact this.comp (measurable_fst.mul measurable_snd) measurable_id + +@[to_additive] +lemma iIndepFun.indepFun_mul_right (hf_indep : iIndepFun (fun _ ↦ m) f κ μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hij : i ≠ j) (hik : i ≠ k) : + IndepFun (f i) (f j * f k) κ μ := + (hf_indep.indepFun_mul_left hf_meas _ _ _ hij.symm hik.symm).symm + +@[to_additive] +lemma iIndepFun.indepFun_mul_mul (hf_indep : iIndepFun (fun _ ↦ m) f κ μ) + (hf_meas : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + IndepFun (f i * f j) (f k * f l) κ μ := + (hf_indep.indepFun_prod_mk_prod_mk hf_meas i j k l hik hil hjk hjl).comp + measurable_mul measurable_mul + +end Mul + +section Div +variable {β : Type*} {m : MeasurableSpace β} [Div β] [MeasurableDiv₂ β] {f : ι → Ω → β} + [IsMarkovKernel κ] + +@[to_additive] +lemma iIndepFun.indepFun_div_left (hf_indep : iIndepFun (fun _ ↦ m) f κ μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : + IndepFun (f i / f j) (f k) κ μ := by + have : IndepFun (fun ω => (f i ω, f j ω)) (f k) κ μ := + hf_indep.indepFun_prod_mk hf_meas i j k hik hjk + change IndepFun ((fun p : β × β => p.fst / p.snd) ∘ fun ω => (f i ω, f j ω)) (id ∘ f k) κ μ + exact this.comp (measurable_fst.div measurable_snd) measurable_id + +@[to_additive] +lemma iIndepFun.indepFun_div_right (hf_indep : iIndepFun (fun _ ↦ m) f κ μ) + (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hij : i ≠ j) (hik : i ≠ k) : + IndepFun (f i) (f j / f k) κ μ := + (hf_indep.indepFun_div_left hf_meas _ _ _ hij.symm hik.symm).symm + +@[to_additive] +lemma iIndepFun.indepFun_div_div (hf_indep : iIndepFun (fun _ ↦ m) f κ μ) + (hf_meas : ∀ i, Measurable (f i)) + (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : + IndepFun (f i / f j) (f k / f l) κ μ := + (hf_indep.indepFun_prod_mk_prod_mk hf_meas i j k l hik hil hjk hjl).comp + measurable_div measurable_div + +end Div + +section CommMonoid +variable {β : Type*} {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} + [IsMarkovKernel κ] @[to_additive] -theorem iIndepFun.indepFun_finset_prod_of_not_mem [IsMarkovKernel κ] {ι : Type*} {β : Type*} - {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} - (hf_Indep : iIndepFun (fun _ => m) f κ μ) (hf_meas : ∀ i, Measurable (f i)) - {s : Finset ι} {i : ι} (hi : i ∉ s) : +theorem iIndepFun.indepFun_finset_prod_of_not_mem (hf_Indep : iIndepFun (fun _ ↦ m) f κ μ) + (hf_meas : ∀ i, Measurable (f i)) {s : Finset ι} {i : ι} (hi : i ∉ s) : IndepFun (∏ j in s, f j) (f i) κ μ := by classical have h_right : f i = @@ -967,12 +1043,13 @@ theorem iIndepFun.indepFun_finset_prod_of_not_mem [IsMarkovKernel κ] {ι : Type h_meas_left h_meas_right @[to_additive] -theorem iIndepFun.indepFun_prod_range_succ [IsMarkovKernel κ] {β : Type*} - {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ℕ → Ω → β} +theorem iIndepFun.indepFun_prod_range_succ {f : ℕ → Ω → β} (hf_Indep : iIndepFun (fun _ => m) f κ μ) (hf_meas : ∀ i, Measurable (f i)) (n : ℕ) : IndepFun (∏ j in Finset.range n, f j) (f n) κ μ := hf_Indep.indepFun_finset_prod_of_not_mem hf_meas Finset.not_mem_range_self +end CommMonoid + theorem iIndepSet.iIndepFun_indicator [Zero β] [One β] {m : MeasurableSpace β} {s : ι → Set Ω} (hs : iIndepSet s κ μ) : iIndepFun (fun _n => m) (fun n => (s n).indicator fun _ω => 1) κ μ := by From fb0bfc6b695eb2daf3e97642d235ce657dd9efde Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 20 Dec 2023 15:54:22 +0000 Subject: [PATCH 096/353] feat(Order/Filter): add lemmas about `Eventually*` and `iInter`/`iUnion` (#9090) As requested by Terence Tao on [Zulip](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Where.20is.20EventuallyEq.2Efinite_iInter.3F) --- Mathlib/Order/Filter/Basic.lean | 72 +++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index c96460ab769d1..3b635d1d87aa4 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -14,13 +14,14 @@ import Mathlib.Data.Set.Finite ## Main definitions * `Filter` : filters on a set; -* `Filter.Principal` : specific filters; -* `map`, `comap` : operations on filters; +* `Filter.principal` : filter of all sets containing a given set; +* `Filter.map`, `Filter.comap` : operations on filters; * `Filter.Tendsto` : limit with respect to filters; * `Filter.Eventually` : `f.eventually p` means `{x | p x} ∈ f`; * `Filter.Frequently` : `f.frequently p` means `{x | ¬p x} ∉ f`; -* `filter_upwards [h₁, ..., hₙ]` : takes a list of proofs `hᵢ : sᵢ ∈ f`, and replaces a goal `s ∈ f` - with `∀ x, x ∈ s₁ → ... → x ∈ sₙ → x ∈ s`; +* `filter_upwards [h₁, ..., hₙ]` : + a tactic that takes a list of proofs `hᵢ : sᵢ ∈ f`, + and replaces a goal `s ∈ f` with `∀ x, x ∈ s₁ → ... → x ∈ sₙ → x ∈ s`; * `Filter.NeBot f` : a utility class stating that `f` is a non-trivial filter. Filters on a type `X` are sets of sets of `X` satisfying three conditions. They are mostly used to @@ -1760,6 +1761,69 @@ theorem EventuallyLE.union {s t s' t' : Set α} {l : Filter α} (h : s ≤ᶠ[l] h'.mp <| h.mono fun _ => Or.imp #align filter.eventually_le.union Filter.EventuallyLE.union +protected lemma EventuallyLE.iUnion [Finite ι] {s t : ι → Set α} + (h : ∀ i, s i ≤ᶠ[l] t i) : (⋃ i, s i) ≤ᶠ[l] ⋃ i, t i := + (eventually_all.2 h).mono fun _x hx hx' ↦ + let ⟨i, hi⟩ := mem_iUnion.1 hx'; mem_iUnion.2 ⟨i, hx i hi⟩ + +protected lemma EventuallyEq.iUnion [Finite ι] {s t : ι → Set α} + (h : ∀ i, s i =ᶠ[l] t i) : (⋃ i, s i) =ᶠ[l] ⋃ i, t i := + (EventuallyLE.iUnion fun i ↦ (h i).le).antisymm <| .iUnion fun i ↦ (h i).symm.le + +protected lemma EventuallyLE.iInter [Finite ι] {s t : ι → Set α} + (h : ∀ i, s i ≤ᶠ[l] t i) : (⋂ i, s i) ≤ᶠ[l] ⋂ i, t i := + (eventually_all.2 h).mono fun _x hx hx' ↦ mem_iInter.2 fun i ↦ hx i (mem_iInter.1 hx' i) + +protected lemma EventuallyEq.iInter [Finite ι] {s t : ι → Set α} + (h : ∀ i, s i =ᶠ[l] t i) : (⋂ i, s i) =ᶠ[l] ⋂ i, t i := + (EventuallyLE.iInter fun i ↦ (h i).le).antisymm <| .iInter fun i ↦ (h i).symm.le + +lemma _root_.Set.Finite.eventuallyLE_iUnion {ι : Type*} {s : Set ι} (hs : s.Finite) + {f g : ι → Set α} (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋃ i ∈ s, f i) ≤ᶠ[l] (⋃ i ∈ s, g i) := by + have := hs.to_subtype + rw [biUnion_eq_iUnion, biUnion_eq_iUnion] + exact .iUnion fun i ↦ hle i.1 i.2 + +alias EventuallyLE.biUnion := Set.Finite.eventuallyLE_iUnion + +lemma _root_.Set.Finite.eventuallyEq_iUnion {ι : Type*} {s : Set ι} (hs : s.Finite) + {f g : ι → Set α} (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋃ i ∈ s, f i) =ᶠ[l] (⋃ i ∈ s, g i) := + (EventuallyLE.biUnion hs fun i hi ↦ (heq i hi).le).antisymm <| + .biUnion hs fun i hi ↦ (heq i hi).symm.le + +alias EventuallyEq.biUnion := Set.Finite.eventuallyEq_iUnion + +lemma _root_.Set.Finite.eventuallyLE_iInter {ι : Type*} {s : Set ι} (hs : s.Finite) + {f g : ι → Set α} (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋂ i ∈ s, f i) ≤ᶠ[l] (⋂ i ∈ s, g i) := by + have := hs.to_subtype + rw [biInter_eq_iInter, biInter_eq_iInter] + exact .iInter fun i ↦ hle i.1 i.2 + +alias EventuallyLE.biInter := Set.Finite.eventuallyLE_iInter + +lemma _root_.Set.Finite.eventuallyEq_iInter {ι : Type*} {s : Set ι} (hs : s.Finite) + {f g : ι → Set α} (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋂ i ∈ s, f i) =ᶠ[l] (⋂ i ∈ s, g i) := + (EventuallyLE.biInter hs fun i hi ↦ (heq i hi).le).antisymm <| + .biInter hs fun i hi ↦ (heq i hi).symm.le + +alias EventuallyEq.biInter := Set.Finite.eventuallyEq_iInter + +lemma _root_.Finset.eventuallyLE_iUnion {ι : Type*} (s : Finset ι) {f g : ι → Set α} + (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋃ i ∈ s, f i) ≤ᶠ[l] (⋃ i ∈ s, g i) := + .biUnion s.finite_toSet hle + +lemma _root_.Finset.eventuallyEq_iUnion {ι : Type*} (s : Finset ι) {f g : ι → Set α} + (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋃ i ∈ s, f i) =ᶠ[l] (⋃ i ∈ s, g i) := + .biUnion s.finite_toSet heq + +lemma _root_.Finset.eventuallyLE_iInter {ι : Type*} (s : Finset ι) {f g : ι → Set α} + (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋂ i ∈ s, f i) ≤ᶠ[l] (⋂ i ∈ s, g i) := + .biInter s.finite_toSet hle + +lemma _root_.Finset.eventuallyEq_iInter {ι : Type*} (s : Finset ι) {f g : ι → Set α} + (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋂ i ∈ s, f i) =ᶠ[l] (⋂ i ∈ s, g i) := + .biInter s.finite_toSet heq + @[mono] theorem EventuallyLE.compl {s t : Set α} {l : Filter α} (h : s ≤ᶠ[l] t) : (tᶜ : Set α) ≤ᶠ[l] (sᶜ : Set α) := From 65a96a1872ba7cd79cefa12971c2172695541e2e Mon Sep 17 00:00:00 2001 From: Scott Carnahan <128885296+ScottCarnahan@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:00:34 +0000 Subject: [PATCH 097/353] feat: define nonunital power-associativity (#8618) introduce `Prop`-valued mixin `PNatPowAssoc` and show that power-associativity holds for semigroups. --- Mathlib.lean | 1 + Mathlib/Algebra/Group/PNatPowAssoc.lean | 93 +++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 Mathlib/Algebra/Group/PNatPowAssoc.lean diff --git a/Mathlib.lean b/Mathlib.lean index 4619426ae0240..b907ebbf3fcd7 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -188,6 +188,7 @@ import Mathlib.Algebra.Group.InjSurj import Mathlib.Algebra.Group.MinimalAxioms import Mathlib.Algebra.Group.Opposite import Mathlib.Algebra.Group.OrderSynonym +import Mathlib.Algebra.Group.PNatPowAssoc import Mathlib.Algebra.Group.Pi import Mathlib.Algebra.Group.Prod import Mathlib.Algebra.Group.Semiconj.Basic diff --git a/Mathlib/Algebra/Group/PNatPowAssoc.lean b/Mathlib/Algebra/Group/PNatPowAssoc.lean new file mode 100644 index 0000000000000..56f7b7342fcbb --- /dev/null +++ b/Mathlib/Algebra/Group/PNatPowAssoc.lean @@ -0,0 +1,93 @@ +/- +Copyright (c) 2023 Scott Carnahan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Carnahan +-/ + +import Mathlib.Algebra.Group.Defs +import Mathlib.Algebra.GroupPower.Basic +import Mathlib.Algebra.Group.Prod +import Mathlib.Data.PNat.Basic +import Mathlib.GroupTheory.GroupAction.Prod + +/-! +# Typeclasses for power-associative structures + +In this file we define power-associativity for algebraic structures with a multiplication operation. +The class is a Prop-valued mixin named `PNatPowAssoc`, where `PNat` means only strictly positive +powers are considered. + +## Results + +- `ppow_add` a defining property: `x ^ (k + n) = x ^ k * x ^ n` +- `ppow_one` a defining property: `x ^ 1 = x` +- `ppow_assoc` strictly positive powers of an element have associative multiplication. +- `ppow_comm` `x ^ m * x ^ n = x ^ n * x ^ m` for strictly positive `m` and `n`. +- `ppow_mul` `x ^ (m * n) = (x ^ m) ^ n` for strictly positive `m` and `n`. +- `ppow_eq_pow` monoid exponentiation coincides with semigroup exponentiation. + +## Instances + +- PNatPowAssoc for products and Pi types + +## Todo + +* `NatPowAssoc` for `MulOneClass` - more or less the same flow +* It seems unlikely that anyone will want `NatSMulAssoc` and `PNatSmulAssoc` as additive versions of + power-associativity, but we have found that it is not hard to write. + +-/ + +variable {M : Type*} + +/-- A `Prop`-valued mixin for power-associative multiplication in the non-unital setting. -/ +class PNatPowAssoc (M : Type*) [Mul M] [Pow M ℕ+] : Prop where + /-- Multiplication is power-associative. -/ + protected ppow_add : ∀ (k n : ℕ+) (x : M), x ^ (k + n) = x ^ k * x ^ n + /-- Exponent one is identity. -/ + protected ppow_one : ∀ (x : M), x ^ (1 : ℕ+) = x + +section Mul + +variable [Mul M] [Pow M ℕ+] [PNatPowAssoc M] + +theorem ppow_add (k n : ℕ+) (x : M) : x ^ (k + n) = x ^ k * x ^ n := + PNatPowAssoc.ppow_add k n x + +@[simp] +theorem ppow_one (x : M) : x ^ (1 : ℕ+) = x := + PNatPowAssoc.ppow_one x + +theorem ppow_mul_assoc (k m n : ℕ+) (x : M) : + (x ^ k * x ^ m) * x ^ n = x ^ k * (x ^ m * x ^ n) := by + simp only [← ppow_add, add_assoc] + +theorem ppow_mul_comm (m n : ℕ+) (x : M) : + x ^ m * x ^ n = x ^ n * x ^ m := by simp only [← ppow_add, add_comm] + +theorem ppow_mul (x : M) (m n : ℕ+) : x ^ (m * n) = (x ^ m) ^ n := by + refine PNat.recOn n ?_ fun k hk ↦ ?_ + rw [ppow_one, mul_one] + rw [ppow_add, ppow_one, mul_add, ppow_add, mul_one, hk] + +theorem ppow_mul' (x : M) (m n : ℕ+) : x ^ (m * n) = (x ^ n) ^ m := by + rw [mul_comm] + exact ppow_mul x n m + +end Mul + +instance Pi.instPNatPowAssoc {ι : Type*} {α : ι → Type*} [∀ i, Mul <| α i] [∀ i, Pow (α i) ℕ+] + [∀ i, PNatPowAssoc <| α i] : PNatPowAssoc (∀ i, α i) where + ppow_add _ _ _ := by ext; simp [ppow_add] + ppow_one _ := by ext; simp + +instance Prod.instPNatPowAssoc {N : Type*} [Mul M] [Pow M ℕ+] [PNatPowAssoc M] [Mul N] [Pow N ℕ+] + [PNatPowAssoc N] : PNatPowAssoc (M × N) where + ppow_add _ _ _ := by ext <;> simp [ppow_add] + ppow_one _ := by ext <;> simp + +theorem ppow_eq_pow [Monoid M] [Pow M ℕ+] [PNatPowAssoc M] (x : M) (n : ℕ+) : + x ^ n = x ^ (n : ℕ) := by + refine PNat.recOn n ?_ fun k hk ↦ ?_ + rw [ppow_one, PNat.one_coe, pow_one] + rw [ppow_add, ppow_one, PNat.add_coe, pow_add, PNat.one_coe, pow_one, ← hk] From 051aa73462329fa6f7421c7112a573d135b828c1 Mon Sep 17 00:00:00 2001 From: sgouezel Date: Wed, 20 Dec 2023 19:25:42 +0000 Subject: [PATCH 098/353] feat: non-integrability results of derivatives on `[a, +oo)` (#8712) We have in the library the lemma `not_intervalIntegrable_of_tendsto_norm_atTop_of_deriv_isBigO_filter`, saying that if a function tends to infinity at a point in an interval `[a, b]`, then its derivative is not interval-integrable on `[a, b]`. We generalize this result to allow for any set instead of `[a, b]`, and apply it to half-infinite intervals. In particular, we characterize integrability of `x^s` on `[a, +oo)`, and deduce that `x^s` is never integrable on `[0, +oo)`. This makes it possible to remove one assumption in Lemma `mellin_comp_rpow` on the Mellin transform. --- Mathlib/Analysis/Asymptotics/Asymptotics.lean | 3 + Mathlib/Analysis/MellinTransform.lean | 18 +-- .../SpecialFunctions/Gamma/Basic.lean | 11 +- .../Analysis/SpecialFunctions/Gamma/Beta.lean | 2 +- .../Analysis/SpecialFunctions/Gaussian.lean | 2 +- .../SpecialFunctions/ImproperIntegrals.lean | 57 ++++++++++ .../Analysis/SpecialFunctions/Integrals.lean | 36 +++++- .../SpecialFunctions/JapaneseBracket.lean | 2 +- .../SpecialFunctions/NonIntegrable.lean | 105 +++++++++++++----- .../Integral/DivergenceTheorem.lean | 2 +- Mathlib/MeasureTheory/Integral/ExpDecay.lean | 2 +- .../Integral/FundThmCalculus.lean | 30 +++-- .../Integral/IntegralEqImproper.lean | 8 +- .../Integral/IntervalIntegral.lean | 21 +++- .../Measure/Haar/NormedSpace.lean | 4 +- Mathlib/NumberTheory/ZetaFunction.lean | 14 ++- Mathlib/Order/Filter/Interval.lean | 35 +++++- .../Topology/Algebra/InfiniteSum/Basic.lean | 24 ++++ 18 files changed, 300 insertions(+), 76 deletions(-) diff --git a/Mathlib/Analysis/Asymptotics/Asymptotics.lean b/Mathlib/Analysis/Asymptotics/Asymptotics.lean index 4f8636d9e4510..25e7ceeafef91 100644 --- a/Mathlib/Analysis/Asymptotics/Asymptotics.lean +++ b/Mathlib/Analysis/Asymptotics/Asymptotics.lean @@ -603,6 +603,9 @@ theorem isBigO_refl (f : α → E) (l : Filter α) : f =O[l] f := (isBigOWith_refl f l).isBigO #align asymptotics.is_O_refl Asymptotics.isBigO_refl +theorem _root_.Filter.EventuallyEq.isBigO {f₁ f₂ : α → E} (hf : f₁ =ᶠ[l] f₂) : f₁ =O[l] f₂ := + hf.trans_isBigO (isBigO_refl _ _) + theorem IsBigOWith.trans_le (hfg : IsBigOWith c l f g) (hgk : ∀ x, ‖g x‖ ≤ ‖k x‖) (hc : 0 ≤ c) : IsBigOWith c l f k := (hfg.trans (isBigOWith_of_le l hgk) hc).congr_const <| mul_one c diff --git a/Mathlib/Analysis/MellinTransform.lean b/Mathlib/Analysis/MellinTransform.lean index 5cdb0a9d8a64a..c9d67860f041b 100644 --- a/Mathlib/Analysis/MellinTransform.lean +++ b/Mathlib/Analysis/MellinTransform.lean @@ -99,8 +99,6 @@ theorem MellinConvergent.comp_rpow {f : ℝ → E} {s : ℂ} {a : ℝ} (ha : a add_sub_assoc, sub_add_cancel] #align mellin_convergent.comp_rpow MellinConvergent.comp_rpow -variable [CompleteSpace E] - /-- The Mellin transform of a function `f` (for a complex exponent `s`), defined as the integral of `t ^ (s - 1) • f` over `Ioi 0`. -/ def mellin (f : ℝ → E) (s : ℂ) : E := @@ -123,10 +121,14 @@ theorem mellin_div_const (f : ℝ → ℂ) (s a : ℂ) : mellin (fun t => f t / simp_rw [mellin, smul_eq_mul, ← mul_div_assoc, integral_div] #align mellin_div_const mellin_div_const -theorem mellin_comp_rpow (f : ℝ → E) (s : ℂ) {a : ℝ} (ha : a ≠ 0) : +theorem mellin_comp_rpow (f : ℝ → E) (s : ℂ) (a : ℝ) : mellin (fun t => f (t ^ a)) s = |a|⁻¹ • mellin f (s / a) := by - -- note: this is also true for a = 0 (both sides are zero), but this is mathematically - -- uninteresting and rather time-consuming to check + /- This is true for `a = 0` as all sides are undefined but turn out to vanish thanks to our + convention. The interesting case is `a ≠ 0` -/ + rcases eq_or_ne a 0 with rfl|ha + · by_cases hE : CompleteSpace E + · simp [integral_smul_const, mellin, setIntegral_Ioi_zero_cpow] + · simp [integral, mellin, hE] simp_rw [mellin] conv_rhs => rw [← integral_comp_rpow_Ioi _ ha, ← integral_smul] refine' set_integral_congr measurableSet_Ioi fun t ht => _ @@ -162,7 +164,7 @@ theorem mellin_comp_mul_right (f : ℝ → E) (s : ℂ) {a : ℝ} (ha : 0 < a) : #align mellin_comp_mul_right mellin_comp_mul_right theorem mellin_comp_inv (f : ℝ → E) (s : ℂ) : mellin (fun t => f t⁻¹) s = mellin f (-s) := by - simp_rw [← rpow_neg_one, mellin_comp_rpow _ _ (neg_ne_zero.mpr one_ne_zero), abs_neg, abs_one, + simp_rw [← rpow_neg_one, mellin_comp_rpow _ _ _, abs_neg, abs_one, inv_one, one_smul, ofReal_neg, ofReal_one, div_neg, div_one] #align mellin_comp_inv mellin_comp_inv @@ -250,7 +252,7 @@ theorem mellin_convergent_zero_of_isBigO {b : ℝ} {f : ℝ → ℝ} · show HasFiniteIntegral (fun t => d * t ^ (s - b - 1)) _ refine' (Integrable.hasFiniteIntegral _).const_mul _ rw [← IntegrableOn, ← integrableOn_Ioc_iff_integrableOn_Ioo, ← - intervalIntegrable_iff_integrable_Ioc_of_le hε.le] + intervalIntegrable_iff_integrableOn_Ioc_of_le hε.le] exact intervalIntegral.intervalIntegrable_rpow' (by linarith) · refine' (ae_restrict_iff' measurableSet_Ioo).mpr (eventually_of_forall fun t ht => _) rw [mul_comm, norm_mul] @@ -471,7 +473,7 @@ theorem hasMellin_one_Ioc {s : ℂ} (hs : 0 < re s) : simp_rw [HasMellin, mellin, MellinConvergent, ← indicator_smul, IntegrableOn, integrable_indicator_iff aux3, smul_eq_mul, integral_indicator aux3, mul_one, IntegrableOn, Measure.restrict_restrict_of_subset Ioc_subset_Ioi_self] - rw [← IntegrableOn, ← intervalIntegrable_iff_integrable_Ioc_of_le zero_le_one] + rw [← IntegrableOn, ← intervalIntegrable_iff_integrableOn_Ioc_of_le zero_le_one] refine' ⟨intervalIntegral.intervalIntegrable_cpow' aux1, _⟩ rw [← intervalIntegral.integral_of_le zero_le_one, integral_cpow (Or.inl aux1), sub_add_cancel, ofReal_zero, ofReal_one, one_cpow, zero_cpow aux2, sub_zero] diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean index 27c8b2afc3abf..462ed8d781a71 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean @@ -75,7 +75,7 @@ theorem GammaIntegral_convergent {s : ℝ} (h : 0 < s) : constructor · rw [← integrableOn_Icc_iff_integrableOn_Ioc] refine' IntegrableOn.continuousOn_mul continuousOn_id.neg.exp _ isCompact_Icc - refine' (intervalIntegrable_iff_integrable_Icc_of_le zero_le_one).mp _ + refine' (intervalIntegrable_iff_integrableOn_Icc_of_le zero_le_one).mp _ exact intervalIntegrable_rpow' (by linarith) · refine' integrable_of_isBigO_exp_neg one_half_pos _ (Gamma_integrand_isLittleO _).isBigO refine' continuousOn_id.neg.exp.mul (continuousOn_id.rpow_const _) @@ -169,7 +169,7 @@ theorem tendsto_partialGamma {s : ℂ} (hs : 0 < s.re) : private theorem Gamma_integrand_interval_integrable (s : ℂ) {X : ℝ} (hs : 0 < s.re) (hX : 0 ≤ X) : IntervalIntegrable (fun x => (-x).exp * x ^ (s - 1) : ℝ → ℂ) volume 0 X := by - rw [intervalIntegrable_iff_integrable_Ioc_of_le hX] + rw [intervalIntegrable_iff_integrableOn_Ioc_of_le hX] exact IntegrableOn.mono_set (GammaIntegral_convergent hs) Ioc_subset_Ioi_self private theorem Gamma_integrand_deriv_integrable_A {s : ℂ} (hs : 0 < s.re) {X : ℝ} (hX : 0 ≤ X) : @@ -182,7 +182,7 @@ private theorem Gamma_integrand_deriv_integrable_B {s : ℂ} (hs : 0 < s.re) {Y IntervalIntegrable (fun x : ℝ => (-x).exp * (s * x ^ (s - 1)) : ℝ → ℂ) volume 0 Y := by have : (fun x => (-x).exp * (s * x ^ (s - 1)) : ℝ → ℂ) = (fun x => s * ((-x).exp * x ^ (s - 1)) : ℝ → ℂ) := by ext1; ring - rw [this, intervalIntegrable_iff_integrable_Ioc_of_le hY] + rw [this, intervalIntegrable_iff_integrableOn_Ioc_of_le hY] constructor · refine' (continuousOn_const.mul _).aestronglyMeasurable measurableSet_Ioc apply (continuous_ofReal.comp continuous_neg.exp).continuousOn.mul @@ -306,7 +306,7 @@ theorem GammaAux_recurrence2 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) : /-- The `Γ` function (of a complex variable `s`). -/ -- @[pp_nodot] -- Porting note: removed -def Gamma (s : ℂ) : ℂ := +irreducible_def Gamma (s : ℂ) : ℂ := GammaAux ⌊1 - s.re⌋₊ s #align complex.Gamma Complex.Gamma @@ -377,7 +377,8 @@ theorem Gamma_neg_nat_eq_zero (n : ℕ) : Gamma (-n) = 0 := by #align complex.Gamma_neg_nat_eq_zero Complex.Gamma_neg_nat_eq_zero theorem Gamma_conj (s : ℂ) : Gamma (conj s) = conj (Gamma s) := by - suffices : ∀ (n : ℕ) (s : ℂ), GammaAux n (conj s) = conj (GammaAux n s); exact this _ _ + suffices ∀ (n : ℕ) (s : ℂ), GammaAux n (conj s) = conj (GammaAux n s) by + simp [Gamma, this] intro n induction' n with n IH · rw [GammaAux]; exact GammaIntegral_conj diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean index 2bd846666489f..f5af478858237 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean @@ -300,7 +300,7 @@ theorem approx_Gamma_integral_tendsto_Gamma_integral {s : ℂ} (hs : 0 < re s) : intro n rw [integrable_indicator_iff (measurableSet_Ioc : MeasurableSet (Ioc (_ : ℝ) _)), IntegrableOn, Measure.restrict_restrict_of_subset Ioc_subset_Ioi_self, ← IntegrableOn, ← - intervalIntegrable_iff_integrable_Ioc_of_le (by positivity : (0 : ℝ) ≤ n)] + intervalIntegrable_iff_integrableOn_Ioc_of_le (by positivity : (0 : ℝ) ≤ n)] apply IntervalIntegrable.continuousOn_mul · refine' intervalIntegral.intervalIntegrable_cpow' _ rwa [sub_re, one_re, ← zero_sub, sub_lt_sub_iff_right] diff --git a/Mathlib/Analysis/SpecialFunctions/Gaussian.lean b/Mathlib/Analysis/SpecialFunctions/Gaussian.lean index a592bdbab64d3..02eb3077c9828 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gaussian.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gaussian.lean @@ -85,7 +85,7 @@ theorem integrableOn_rpow_mul_exp_neg_rpow {p s : ℝ} (hs : -1 < s) (hp : 1 ≤ constructor · rw [← integrableOn_Icc_iff_integrableOn_Ioc] refine IntegrableOn.mul_continuousOn ?_ ?_ isCompact_Icc - · refine (intervalIntegrable_iff_integrable_Icc_of_le zero_le_one).mp ?_ + · refine (intervalIntegrable_iff_integrableOn_Icc_of_le zero_le_one).mp ?_ exact intervalIntegral.intervalIntegrable_rpow' hs · intro x _ change ContinuousWithinAt ((fun x => exp (- x)) ∘ (fun x => x ^ p)) (Icc 0 1) x diff --git a/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean b/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean index 1356ffd72599c..3eebe992bab84 100644 --- a/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean @@ -73,6 +73,36 @@ theorem integrableOn_Ioi_rpow_of_lt {a : ℝ} (ha : a < -1) {c : ℝ} (hc : 0 < integrableOn_Ioi_deriv_of_nonneg' hd (fun t ht => rpow_nonneg_of_nonneg (hc.trans ht).le a) ht #align integrable_on_Ioi_rpow_of_lt integrableOn_Ioi_rpow_of_lt +theorem integrableOn_Ioi_rpow_iff {s t : ℝ} (ht : 0 < t) : + IntegrableOn (fun x ↦ x ^ s) (Ioi t) ↔ s < -1 := by + refine ⟨fun h ↦ ?_, fun h ↦ integrableOn_Ioi_rpow_of_lt h ht⟩ + contrapose! h + intro H + have H' : IntegrableOn (fun x ↦ x ^ s) (Ioi (max 1 t)) := + H.mono (Set.Ioi_subset_Ioi (le_max_right _ _)) le_rfl + have : IntegrableOn (fun x ↦ x⁻¹) (Ioi (max 1 t)) := by + apply H'.mono' measurable_inv.aestronglyMeasurable + filter_upwards [ae_restrict_mem measurableSet_Ioi] with x hx + have x_one : 1 ≤ x := ((le_max_left _ _).trans_lt (mem_Ioi.1 hx)).le + simp only [norm_inv, Real.norm_eq_abs, abs_of_nonneg (zero_le_one.trans x_one)] + rw [← Real.rpow_neg_one x] + exact Real.rpow_le_rpow_of_exponent_le x_one h + exact not_IntegrableOn_Ioi_inv this + +/-- The real power function with any exponent is not integrable on `(0, +∞)`. -/ +theorem not_integrableOn_Ioi_rpow (s : ℝ) : ¬ IntegrableOn (fun x ↦ x ^ s) (Ioi (0 : ℝ)) := by + intro h + rcases le_or_lt s (-1) with hs|hs + · have : IntegrableOn (fun x ↦ x ^ s) (Ioo (0 : ℝ) 1) := h.mono Ioo_subset_Ioi_self le_rfl + rw [integrableOn_Ioo_rpow_iff zero_lt_one] at this + exact hs.not_lt this + · have : IntegrableOn (fun x ↦ x ^ s) (Ioi 1) := h.mono (Ioi_subset_Ioi zero_le_one) le_rfl + rw [integrableOn_Ioi_rpow_iff zero_lt_one] at this + exact hs.not_lt this + +theorem setIntegral_Ioi_zero_rpow (s : ℝ) : ∫ x in Ioi (0 : ℝ), x ^ s = 0 := + MeasureTheory.integral_undef (not_integrableOn_Ioi_rpow s) + theorem integral_Ioi_rpow_of_lt {a : ℝ} (ha : a < -1) {c : ℝ} (hc : 0 < c) : ∫ t : ℝ in Ioi c, t ^ a = -c ^ (a + 1) / (a + 1) := by have hd : ∀ (x : ℝ) (_ : x ∈ Ici c), HasDerivAt (fun t => t ^ (a + 1) / (a + 1)) (x ^ a) x := by @@ -97,6 +127,33 @@ theorem integrableOn_Ioi_cpow_of_lt {a : ℂ} (ha : a.re < -1) {c : ℝ} (hc : 0 (Complex.continuousAt_ofReal_cpow_const _ _ (Or.inr (hc.trans ht).ne')).continuousWithinAt #align integrable_on_Ioi_cpow_of_lt integrableOn_Ioi_cpow_of_lt +theorem integrableOn_Ioi_cpow_iff {s : ℂ} {t : ℝ} (ht : 0 < t) : + IntegrableOn (fun x : ℝ ↦ (x : ℂ) ^ s) (Ioi t) ↔ s.re < -1 := by + refine ⟨fun h ↦ ?_, fun h ↦ integrableOn_Ioi_cpow_of_lt h ht⟩ + have B : IntegrableOn (fun a ↦ a ^ s.re) (Ioi t) := by + apply (integrableOn_congr_fun _ measurableSet_Ioi).1 h.norm + intro a ha + have : 0 < a := ht.trans ha + simp [Complex.abs_cpow_eq_rpow_re_of_pos this] + rwa [integrableOn_Ioi_rpow_iff ht] at B + +/-- The complex power function with any exponent is not integrable on `(0, +∞)`. -/ +theorem not_integrableOn_Ioi_cpow (s : ℂ) : + ¬ IntegrableOn (fun x : ℝ ↦ (x : ℂ) ^ s) (Ioi (0 : ℝ)) := by + intro h + rcases le_or_lt s.re (-1) with hs|hs + · have : IntegrableOn (fun x : ℝ ↦ (x : ℂ) ^ s) (Ioo (0 : ℝ) 1) := + h.mono Ioo_subset_Ioi_self le_rfl + rw [integrableOn_Ioo_cpow_iff zero_lt_one] at this + exact hs.not_lt this + · have : IntegrableOn (fun x : ℝ ↦ (x : ℂ) ^ s) (Ioi 1) := + h.mono (Ioi_subset_Ioi zero_le_one) le_rfl + rw [integrableOn_Ioi_cpow_iff zero_lt_one] at this + exact hs.not_lt this + +theorem setIntegral_Ioi_zero_cpow (s : ℂ) : ∫ x in Ioi (0 : ℝ), (x : ℂ) ^ s = 0 := + MeasureTheory.integral_undef (not_integrableOn_Ioi_cpow s) + theorem integral_Ioi_cpow_of_lt {a : ℂ} (ha : a.re < -1) {c : ℝ} (hc : 0 < c) : (∫ t : ℝ in Ioi c, (t : ℂ) ^ a) = -(c : ℂ) ^ (a + 1) / (a + 1) := by refine' diff --git a/Mathlib/Analysis/SpecialFunctions/Integrals.lean b/Mathlib/Analysis/SpecialFunctions/Integrals.lean index 1866918bd3f9e..ce8ad9de3f0fa 100644 --- a/Mathlib/Analysis/SpecialFunctions/Integrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/Integrals.lean @@ -5,6 +5,7 @@ Authors: Benjamin Davidson -/ import Mathlib.MeasureTheory.Integral.FundThmCalculus import Mathlib.Analysis.SpecialFunctions.Trigonometric.ArctanDeriv +import Mathlib.Analysis.SpecialFunctions.NonIntegrable #align_import analysis.special_functions.integrals from "leanprover-community/mathlib"@"011cafb4a5bc695875d186e245d6b3df03bf6c40" @@ -93,6 +94,26 @@ theorem intervalIntegrable_rpow' {r : ℝ} (h : -1 < r) : rpow_def_of_pos hx.1, rpow_def_of_neg (by linarith [hx.1] : -x < 0)] #align interval_integral.interval_integrable_rpow' intervalIntegral.intervalIntegrable_rpow' +/-- The power function `x ↦ x^s` is integrable on `(0, t)` iff `-1 < s`. -/ +lemma integrableOn_Ioo_rpow_iff {s t : ℝ} (ht : 0 < t) : + IntegrableOn (fun x ↦ x ^ s) (Ioo (0 : ℝ) t) ↔ -1 < s := by + refine ⟨fun h ↦ ?_, fun h ↦ by simpa [intervalIntegrable_iff_integrableOn_Ioo_of_le ht.le] + using intervalIntegrable_rpow' h (a := 0) (b := t)⟩ + contrapose! h + intro H + have I : 0 < min 1 t := lt_min zero_lt_one ht + have H' : IntegrableOn (fun x ↦ x ^ s) (Ioo 0 (min 1 t)) := + H.mono (Set.Ioo_subset_Ioo le_rfl (min_le_right _ _)) le_rfl + have : IntegrableOn (fun x ↦ x⁻¹) (Ioo 0 (min 1 t)) := by + apply H'.mono' measurable_inv.aestronglyMeasurable + filter_upwards [ae_restrict_mem measurableSet_Ioo] with x hx + simp only [norm_inv, Real.norm_eq_abs, abs_of_nonneg (le_of_lt hx.1)] + rwa [← Real.rpow_neg_one x, Real.rpow_le_rpow_left_iff_of_base_lt_one hx.1] + exact lt_of_lt_of_le hx.2 (min_le_left _ _) + have : IntervalIntegrable (fun x ↦ x⁻¹) volume 0 (min 1 t) := by + rwa [intervalIntegrable_iff_integrableOn_Ioo_of_le I.le] + simp [intervalIntegrable_inv_iff, I.ne] at this + /-- See `intervalIntegrable_cpow'` for a version with a weaker hypothesis on `r`, but assuming the measure is volume. -/ theorem intervalIntegrable_cpow {r : ℂ} (h : 0 ≤ r.re ∨ (0 : ℝ) ∉ [[a, b]]) : @@ -117,13 +138,13 @@ theorem intervalIntegrable_cpow {r : ℂ} (h : 0 ≤ r.re ∨ (0 : ℝ) ∉ [[a, rcases le_or_lt 0 c with (hc | hc) · -- case `0 ≤ c`: integrand is identically 1 have : IntervalIntegrable (fun _ => 1 : ℝ → ℝ) μ 0 c := intervalIntegrable_const - rw [intervalIntegrable_iff_integrable_Ioc_of_le hc] at this ⊢ + rw [intervalIntegrable_iff_integrableOn_Ioc_of_le hc] at this ⊢ refine' IntegrableOn.congr_fun this (fun x hx => _) measurableSet_Ioc dsimp only rw [Complex.norm_eq_abs, Complex.abs_cpow_eq_rpow_re_of_pos hx.1, ← h', rpow_zero] · -- case `c < 0`: integrand is identically constant, *except* at `x = 0` if `r ≠ 0`. apply IntervalIntegrable.symm - rw [intervalIntegrable_iff_integrable_Ioc_of_le hc.le] + rw [intervalIntegrable_iff_integrableOn_Ioc_of_le hc.le] have : Ioc c 0 = Ioo c 0 ∪ {(0 : ℝ)} := by rw [← Ioo_union_Icc_eq_Ioc hc (le_refl 0), ← Icc_def] simp_rw [← le_antisymm_iff, setOf_eq_eq_singleton'] @@ -177,6 +198,17 @@ theorem intervalIntegrable_cpow' {r : ℂ} (h : -1 < r.re) : simp #align interval_integral.interval_integrable_cpow' intervalIntegral.intervalIntegrable_cpow' +/-- The complex power function `x ↦ x^s` is integrable on `(0, t)` iff `-1 < s.re`. -/ +theorem integrableOn_Ioo_cpow_iff {s : ℂ} {t : ℝ} (ht : 0 < t) : + IntegrableOn (fun x : ℝ ↦ (x : ℂ) ^ s) (Ioo (0 : ℝ) t) ↔ -1 < s.re := by + refine ⟨fun h ↦ ?_, fun h ↦ by simpa [intervalIntegrable_iff_integrableOn_Ioo_of_le ht.le] + using intervalIntegrable_cpow' h (a := 0) (b := t)⟩ + have B : IntegrableOn (fun a ↦ a ^ s.re) (Ioo 0 t) := by + apply (integrableOn_congr_fun _ measurableSet_Ioo).1 h.norm + intro a ha + simp [Complex.abs_cpow_eq_rpow_re_of_pos ha.1] + rwa [integrableOn_Ioo_rpow_iff ht] at B + @[simp] theorem intervalIntegrable_id : IntervalIntegrable (fun x => x) μ a b := continuous_id.intervalIntegrable a b diff --git a/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean b/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean index ac0728f081189..282ce63bab599 100644 --- a/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean +++ b/Mathlib/Analysis/SpecialFunctions/JapaneseBracket.lean @@ -90,7 +90,7 @@ theorem finite_integral_rpow_sub_one_pow_aux {r : ℝ} (n : ℕ) (hnr : (n : ℝ exact hr.le refine' lt_of_le_of_lt (set_lintegral_mono' measurableSet_Ioc h_int) _ refine' IntegrableOn.set_lintegral_lt_top _ - rw [← intervalIntegrable_iff_integrable_Ioc_of_le zero_le_one] + rw [← intervalIntegrable_iff_integrableOn_Ioc_of_le zero_le_one] apply intervalIntegral.intervalIntegrable_rpow' rwa [neg_lt_neg_iff, inv_mul_lt_iff' hr, one_mul] #align finite_integral_rpow_sub_one_pow_aux finite_integral_rpow_sub_one_pow_aux diff --git a/Mathlib/Analysis/SpecialFunctions/NonIntegrable.lean b/Mathlib/Analysis/SpecialFunctions/NonIntegrable.lean index 1ab1e87d8af20..0a86d7cbd9ae2 100644 --- a/Mathlib/Analysis/SpecialFunctions/NonIntegrable.lean +++ b/Mathlib/Analysis/SpecialFunctions/NonIntegrable.lean @@ -43,56 +43,93 @@ open scoped MeasureTheory Topology Interval NNReal ENNReal open MeasureTheory TopologicalSpace Set Filter Asymptotics intervalIntegral -variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [SecondCountableTopology E] - [CompleteSpace E] [NormedAddCommGroup F] +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [NormedAddCommGroup F] /-- If `f` is eventually differentiable along a nontrivial filter `l : Filter ℝ` that is generated by convex sets, the norm of `f` tends to infinity along `l`, and `f' = O(g)` along `l`, where `f'` -is the derivative of `f`, then `g` is not integrable on any interval `a..b` such that -`[a, b] ∈ l`. -/ -theorem not_intervalIntegrable_of_tendsto_norm_atTop_of_deriv_isBigO_filter {f : ℝ → E} {g : ℝ → F} - {a b : ℝ} (l : Filter ℝ) [NeBot l] [TendstoIxxClass Icc l l] (hl : [[a, b]] ∈ l) - (hd : ∀ᶠ x in l, DifferentiableAt ℝ f x) (hf : Tendsto (fun x => ‖f x‖) l atTop) - (hfg : deriv f =O[l] g) : ¬IntervalIntegrable g volume a b := by +is the derivative of `f`, then `g` is not integrable on any set `k` belonging to `l`. +Auxiliary version assuming that `E` is complete. -/ +theorem not_integrableOn_of_tendsto_norm_atTop_of_deriv_isBigO_filter_aux + [CompleteSpace E] {f : ℝ → E} {g : ℝ → F} + {k : Set ℝ} (l : Filter ℝ) [NeBot l] [TendstoIxxClass Icc l l] + (hl : k ∈ l) (hd : ∀ᶠ x in l, DifferentiableAt ℝ f x) (hf : Tendsto (fun x => ‖f x‖) l atTop) + (hfg : deriv f =O[l] g) : ¬IntegrableOn g k := by intro hgi obtain ⟨C, hC₀, s, hsl, hsub, hfd, hg⟩ : - ∃ (C : ℝ) (_ : 0 ≤ C), ∃ s ∈ l, (∀ x ∈ s, ∀ y ∈ s, [[x, y]] ⊆ [[a, b]]) ∧ + ∃ (C : ℝ) (_ : 0 ≤ C), ∃ s ∈ l, (∀ x ∈ s, ∀ y ∈ s, [[x, y]] ⊆ k) ∧ (∀ x ∈ s, ∀ y ∈ s, ∀ z ∈ [[x, y]], DifferentiableAt ℝ f z) ∧ ∀ x ∈ s, ∀ y ∈ s, ∀ z ∈ [[x, y]], ‖deriv f z‖ ≤ C * ‖g z‖ := by rcases hfg.exists_nonneg with ⟨C, C₀, hC⟩ have h : ∀ᶠ x : ℝ × ℝ in l.prod l, - ∀ y ∈ [[x.1, x.2]], (DifferentiableAt ℝ f y ∧ ‖deriv f y‖ ≤ C * ‖g y‖) ∧ y ∈ [[a, b]] := + ∀ y ∈ [[x.1, x.2]], (DifferentiableAt ℝ f y ∧ ‖deriv f y‖ ≤ C * ‖g y‖) ∧ y ∈ k := (tendsto_fst.uIcc tendsto_snd).eventually ((hd.and hC.bound).and hl).smallSets rcases mem_prod_self_iff.1 h with ⟨s, hsl, hs⟩ simp only [prod_subset_iff, mem_setOf_eq] at hs exact ⟨C, C₀, s, hsl, fun x hx y hy z hz => (hs x hx y hy z hz).2, fun x hx y hy z hz => (hs x hx y hy z hz).1.1, fun x hx y hy z hz => (hs x hx y hy z hz).1.2⟩ - replace hgi : IntervalIntegrable (fun x => C * ‖g x‖) volume a b - · convert hgi.norm.smul C using 1 - obtain ⟨c, hc, d, hd, hlt⟩ : ∃ c ∈ s, ∃ d ∈ s, (‖f c‖ + ∫ y in Ι a b, C * ‖g y‖) < ‖f d‖ := by + replace hgi : IntegrableOn (fun x ↦ C * ‖g x‖) k := by exact hgi.norm.smul C + obtain ⟨c, hc, d, hd, hlt⟩ : ∃ c ∈ s, ∃ d ∈ s, (‖f c‖ + ∫ y in k, C * ‖g y‖) < ‖f d‖ := by rcases Filter.nonempty_of_mem hsl with ⟨c, hc⟩ - have : ∀ᶠ x in l, (‖f c‖ + ∫ y in Ι a b, C * ‖g y‖) < ‖f x‖ := + have : ∀ᶠ x in l, (‖f c‖ + ∫ y in k, C * ‖g y‖) < ‖f x‖ := hf.eventually (eventually_gt_atTop _) exact ⟨c, hc, (this.and hsl).exists.imp fun d hd => ⟨hd.2, hd.1⟩⟩ specialize hsub c hc d hd; specialize hfd c hc d hd - replace hg : ∀ x ∈ Ι c d, ‖deriv f x‖ ≤ C * ‖g x‖; - exact fun z hz => hg c hc d hd z ⟨hz.1.le, hz.2⟩ + replace hg : ∀ x ∈ Ι c d, ‖deriv f x‖ ≤ C * ‖g x‖ := + fun z hz => hg c hc d hd z ⟨hz.1.le, hz.2⟩ have hg_ae : ∀ᵐ x ∂volume.restrict (Ι c d), ‖deriv f x‖ ≤ C * ‖g x‖ := (ae_restrict_mem measurableSet_uIoc).mono hg - have hsub' : Ι c d ⊆ Ι a b := uIoc_subset_uIoc_of_uIcc_subset_uIcc hsub - have hfi : IntervalIntegrable (deriv f) volume c d := - (hgi.mono_set hsub).mono_fun' (aestronglyMeasurable_deriv _ _) hg_ae + have hsub' : Ι c d ⊆ k := Subset.trans Ioc_subset_Icc_self hsub + have hfi : IntervalIntegrable (deriv f) volume c d := by + rw [intervalIntegrable_iff] + have : IntegrableOn (fun x ↦ C * ‖g x‖) (Ι c d) := IntegrableOn.mono hgi hsub' le_rfl + exact Integrable.mono' this (aestronglyMeasurable_deriv _ _) hg_ae refine' hlt.not_le (sub_le_iff_le_add'.1 _) calc ‖f d‖ - ‖f c‖ ≤ ‖f d - f c‖ := norm_sub_norm_le _ _ - _ = ‖∫ x in c..d, deriv f x‖ := (congr_arg _ (integral_deriv_eq_sub hfd hfi).symm) - _ = ‖∫ x in Ι c d, deriv f x‖ := (norm_integral_eq_norm_integral_Ioc _) - _ ≤ ∫ x in Ι c d, ‖deriv f x‖ := (norm_integral_le_integral_norm _) + _ = ‖∫ x in c..d, deriv f x‖ := congr_arg _ (integral_deriv_eq_sub hfd hfi).symm + _ = ‖∫ x in Ι c d, deriv f x‖ := norm_integral_eq_norm_integral_Ioc _ + _ ≤ ∫ x in Ι c d, ‖deriv f x‖ := norm_integral_le_integral_norm _ _ ≤ ∫ x in Ι c d, C * ‖g x‖ := - (set_integral_mono_on hfi.norm.def (hgi.def.mono_set hsub') measurableSet_uIoc hg) - _ ≤ ∫ x in Ι a b, C * ‖g x‖ := - set_integral_mono_set hgi.def (ae_of_all _ fun x => mul_nonneg hC₀ (norm_nonneg _)) - hsub'.eventuallyLE + set_integral_mono_on hfi.norm.def (hgi.mono_set hsub') measurableSet_uIoc hg + _ ≤ ∫ x in k, C * ‖g x‖ := by + apply set_integral_mono_set hgi + (ae_of_all _ fun x => mul_nonneg hC₀ (norm_nonneg _)) hsub'.eventuallyLE + +theorem not_integrableOn_of_tendsto_norm_atTop_of_deriv_isBigO_filter + {f : ℝ → E} {g : ℝ → F} + {k : Set ℝ} (l : Filter ℝ) [NeBot l] [TendstoIxxClass Icc l l] + (hl : k ∈ l) (hd : ∀ᶠ x in l, DifferentiableAt ℝ f x) (hf : Tendsto (fun x => ‖f x‖) l atTop) + (hfg : deriv f =O[l] g) : ¬IntegrableOn g k := by + let a : E →ₗᵢ[ℝ] UniformSpace.Completion E := UniformSpace.Completion.toComplₗᵢ + let f' := a ∘ f + have h'd : ∀ᶠ x in l, DifferentiableAt ℝ f' x := by + filter_upwards [hd] with x hx using a.toContinuousLinearMap.differentiableAt.comp x hx + have h'f : Tendsto (fun x => ‖f' x‖) l atTop := hf.congr (fun x ↦ by simp) + have h'fg : deriv f' =O[l] g := by + apply IsBigO.trans _ hfg + rw [← isBigO_norm_norm] + suffices (fun x ↦ ‖deriv f' x‖) =ᶠ[l] (fun x ↦ ‖deriv f x‖) by exact this.isBigO + filter_upwards [hd] with x hx + have : deriv f' x = a (deriv f x) := by + rw [fderiv.comp_deriv x _ hx] + · have : fderiv ℝ a (f x) = a.toContinuousLinearMap := a.toContinuousLinearMap.fderiv + simp only [this] + rfl + · exact a.toContinuousLinearMap.differentiableAt + simp only [this] + simp + exact not_integrableOn_of_tendsto_norm_atTop_of_deriv_isBigO_filter_aux l hl h'd h'f h'fg + +/-- If `f` is eventually differentiable along a nontrivial filter `l : Filter ℝ` that is generated +by convex sets, the norm of `f` tends to infinity along `l`, and `f' = O(g)` along `l`, where `f'` +is the derivative of `f`, then `g` is not integrable on any interval `a..b` such that +`[a, b] ∈ l`. -/ +theorem not_intervalIntegrable_of_tendsto_norm_atTop_of_deriv_isBigO_filter {f : ℝ → E} {g : ℝ → F} + {a b : ℝ} (l : Filter ℝ) [NeBot l] [TendstoIxxClass Icc l l] (hl : [[a, b]] ∈ l) + (hd : ∀ᶠ x in l, DifferentiableAt ℝ f x) (hf : Tendsto (fun x => ‖f x‖) l atTop) + (hfg : deriv f =O[l] g) : ¬IntervalIntegrable g volume a b := by + rw [intervalIntegrable_iff'] + exact not_integrableOn_of_tendsto_norm_atTop_of_deriv_isBigO_filter _ hl hd hf hfg set_option linter.uppercaseLean3 false in #align not_interval_integrable_of_tendsto_norm_at_top_of_deriv_is_O_filter not_intervalIntegrable_of_tendsto_norm_atTop_of_deriv_isBigO_filter @@ -174,3 +211,19 @@ theorem intervalIntegrable_inv_iff {a b : ℝ} : IntervalIntegrable (fun x => x⁻¹) volume a b ↔ a = b ∨ (0 : ℝ) ∉ [[a, b]] := by simp only [← intervalIntegrable_sub_inv_iff, sub_zero] #align interval_integrable_inv_iff intervalIntegrable_inv_iff + +/-- The function `fun x ↦ x⁻¹` is not integrable on any interval `[a, +∞)`. -/ +theorem not_IntegrableOn_Ici_inv {a : ℝ} : + ¬ IntegrableOn (fun x => x⁻¹) (Ici a) := by + have A : ∀ᶠ x in atTop, HasDerivAt (fun x => Real.log x) x⁻¹ x := by + filter_upwards [Ioi_mem_atTop 0] with x hx using Real.hasDerivAt_log (ne_of_gt hx) + have B : Tendsto (fun x => ‖Real.log x‖) atTop atTop := + tendsto_norm_atTop_atTop.comp Real.tendsto_log_atTop + exact not_integrableOn_of_tendsto_norm_atTop_of_deriv_isBigO_filter atTop (Ici_mem_atTop a) + (A.mono (fun x hx ↦ hx.differentiableAt)) B + (Filter.EventuallyEq.isBigO (A.mono (fun x hx ↦ hx.deriv))) + +/-- The function `fun x ↦ x⁻¹` is not integrable on any interval `(a, +∞)`. -/ +theorem not_IntegrableOn_Ioi_inv {a : ℝ} : + ¬ IntegrableOn (·⁻¹) (Ioi a) := by + simpa only [IntegrableOn, restrict_Ioi_eq_restrict_Ici] using not_IntegrableOn_Ici_inv diff --git a/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean b/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean index b1eaedb0a1fdf..b4d52eb14ae5f 100644 --- a/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean +++ b/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean @@ -401,7 +401,7 @@ theorem integral_eq_of_hasDerivWithinAt_off_countable_of_le (f f' : ℝ → E) { · exact fun x y => (OrderIso.funUnique (Fin 1) ℝ).symm.le_iff_le · exact (volume_preserving_funUnique (Fin 1) ℝ).symm _ · intro x; rw [Fin.sum_univ_one, hF', e_symm, Pi.single_eq_same, one_smul] - · rw [intervalIntegrable_iff_integrable_Ioc_of_le hle] at Hi + · rw [intervalIntegrable_iff_integrableOn_Ioc_of_le hle] at Hi exact Hi.congr_set_ae Ioc_ae_eq_Icc.symm _ = f b - f a := by simp only [Fin.sum_univ_one, e_symm] diff --git a/Mathlib/MeasureTheory/Integral/ExpDecay.lean b/Mathlib/MeasureTheory/Integral/ExpDecay.lean index fe702d2970c9e..53891a6243f24 100644 --- a/Mathlib/MeasureTheory/Integral/ExpDecay.lean +++ b/Mathlib/MeasureTheory/Integral/ExpDecay.lean @@ -46,7 +46,7 @@ theorem integrable_of_isBigO_exp_neg {f : ℝ → ℝ} {a b : ℝ} (h0 : 0 < b) let v := max a r -- show integrable on `(a, v]` from continuity have int_left : IntegrableOn f (Ioc a v) := by - rw [← intervalIntegrable_iff_integrable_Ioc_of_le (le_max_left a r)] + rw [← intervalIntegrable_iff_integrableOn_Ioc_of_le (le_max_left a r)] have u : Icc a v ⊆ Ici a := Icc_subset_Ici_self exact (h1.mono u).intervalIntegrable_of_Icc (le_max_left a r) suffices IntegrableOn f (Ioi v) by diff --git a/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean index a97920a4cdf6e..edff5f8d486e1 100644 --- a/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean +++ b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean @@ -149,7 +149,7 @@ open MeasureTheory Set Classical Filter Function open scoped Classical Topology Filter ENNReal BigOperators Interval NNReal -variable {ι 𝕜 E F A : Type*} [NormedAddCommGroup E] [CompleteSpace E] [NormedSpace ℝ E] +variable {ι 𝕜 E F A : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] namespace intervalIntegral @@ -275,6 +275,8 @@ theorem measure_integral_sub_linear_isLittleO_of_tendsto_ae' [IsMeasurablyGenera (hv : Tendsto v lt l) : (fun t => (∫ x in u t..v t, f x ∂μ) - ∫ _ in u t..v t, c ∂μ) =o[lt] fun t => ∫ _ in u t..v t, (1 : ℝ) ∂μ := by + by_cases hE : CompleteSpace E; swap + · simp [intervalIntegral, integral, hE] have A := hf.integral_sub_linear_isLittleO_ae hfm hl (hu.Ioc hv) have B := hf.integral_sub_linear_isLittleO_ae hfm hl (hv.Ioc hu) simp_rw [integral_const', sub_smul] @@ -285,6 +287,8 @@ theorem measure_integral_sub_linear_isLittleO_of_tendsto_ae' [IsMeasurablyGenera abel #align interval_integral.measure_integral_sub_linear_is_o_of_tendsto_ae' intervalIntegral.measure_integral_sub_linear_isLittleO_of_tendsto_ae' +variable [CompleteSpace E] + /-- **Fundamental theorem of calculus-1**, local version for any measure. Let filters `l` and `l'` be related by `TendstoIxxClass Ioc`. If `f` has a finite limit `c` at `l ⊓ μ.ae`, where `μ` is a measure @@ -484,7 +488,8 @@ at `(a, b)` provided that `f` is integrable on `a..b` and is continuous at `a` a -/ -variable {f : ℝ → E} {c ca cb : E} {l l' la la' lb lb' : Filter ℝ} {lt : Filter ι} {a b z : ℝ} +variable [CompleteSpace E] + {f : ℝ → E} {c ca cb : E} {l l' la la' lb lb' : Filter ℝ} {lt : Filter ι} {a b z : ℝ} {u v ua ub va vb : ι → ℝ} [FTCFilter a la la'] [FTCFilter b lb lb'] /-! @@ -1093,10 +1098,10 @@ theorem sub_le_integral_of_hasDeriv_right_of_le_Ico (hab : a ≤ b) _ ≤ (∫ w in a..t, (G' w).toReal) + ∫ w in t..x, (G' w).toReal := (add_le_add ht.1 hx) _ = ∫ w in a..x, (G' w).toReal := by apply integral_add_adjacent_intervals - · rw [intervalIntegrable_iff_integrable_Ioc_of_le ht.2.1] + · rw [intervalIntegrable_iff_integrableOn_Ioc_of_le ht.2.1] exact IntegrableOn.mono_set G'int (Ioc_subset_Icc_self.trans (Icc_subset_Icc le_rfl ht.2.2.le)) - · rw [intervalIntegrable_iff_integrable_Ioc_of_le h'x.1.le] + · rw [intervalIntegrable_iff_integrableOn_Ioc_of_le h'x.1.le] apply IntegrableOn.mono_set G'int exact Ioc_subset_Icc_self.trans (Icc_subset_Icc ht.2.1 (h'x.2.trans (min_le_right _ _))) -- now that we know that `s` contains `[a, b]`, we get the desired result by applying this to `b`. @@ -1161,7 +1166,7 @@ theorem integral_eq_sub_of_hasDeriv_right_of_le_real (hab : a ≤ b) (sub_le_integral_of_hasDeriv_right_of_le hab hcont hderiv g'int fun _ _ => le_rfl) #align interval_integral.integral_eq_sub_of_has_deriv_right_of_le_real intervalIntegral.integral_eq_sub_of_hasDeriv_right_of_le_real -variable {f f' : ℝ → E} +variable [CompleteSpace E] {f f' : ℝ → E} /-- **Fundamental theorem of calculus-2**: If `f : ℝ → E` is continuous on `[a, b]` (where `a ≤ b`) and has a right derivative at `f' x` for all `x` in `(a, b)`, and `f'` is integrable on `[a, b]`, @@ -1173,7 +1178,7 @@ theorem integral_eq_sub_of_hasDeriv_right_of_le (hab : a ≤ b) (hcont : Continu rw [← g.intervalIntegral_comp_comm f'int, g.map_sub] exact integral_eq_sub_of_hasDeriv_right_of_le_real hab (g.continuous.comp_continuousOn hcont) (fun x hx => g.hasFDerivAt.comp_hasDerivWithinAt x (hderiv x hx)) - (g.integrable_comp ((intervalIntegrable_iff_integrable_Icc_of_le hab).1 f'int)) + (g.integrable_comp ((intervalIntegrable_iff_integrableOn_Icc_of_le hab).1 f'int)) #align interval_integral.integral_eq_sub_of_has_deriv_right_of_le intervalIntegral.integral_eq_sub_of_hasDeriv_right_of_le /-- Fundamental theorem of calculus-2: If `f : ℝ → E` is continuous on `[a, b]` and @@ -1362,19 +1367,22 @@ end Parts ### Integration by substitution / Change of variables -/ - section SMul +variable {G : Type*} [NormedAddCommGroup G] [NormedSpace ℝ G] + /-- Change of variables, general form. If `f` is continuous on `[a, b]` and has right-derivative `f'` in `(a, b)`, `g` is continuous on `f '' (a, b)` and integrable on `f '' [a, b]`, and `f' x • (g ∘ f) x` is integrable on `[a, b]`, then we can substitute `u = f x` to get `∫ x in a..b, f' x • (g ∘ f) x = ∫ u in f a..f b, g u`. -/ -theorem integral_comp_smul_deriv''' {f f' : ℝ → ℝ} {g : ℝ → E} (hf : ContinuousOn f [[a, b]]) +theorem integral_comp_smul_deriv''' {f f' : ℝ → ℝ} {g : ℝ → G} (hf : ContinuousOn f [[a, b]]) (hff' : ∀ x ∈ Ioo (min a b) (max a b), HasDerivWithinAt f (f' x) (Ioi x) x) (hg_cont : ContinuousOn g (f '' Ioo (min a b) (max a b))) (hg1 : IntegrableOn g (f '' [[a, b]])) (hg2 : IntegrableOn (fun x => f' x • (g ∘ f) x) [[a, b]]) : (∫ x in a..b, f' x • (g ∘ f) x) = ∫ u in f a..f b, g u := by + by_cases hG : CompleteSpace G; swap + · simp [intervalIntegral, integral, hG] rw [hf.image_uIcc, ← intervalIntegrable_iff'] at hg1 have h_cont : ContinuousOn (fun u => ∫ t in f a..f u, g t) [[a, b]] := by refine' (continuousOn_primitive_interval' hg1 _).comp hf _ @@ -1415,7 +1423,7 @@ theorem integral_comp_smul_deriv''' {f f' : ℝ → ℝ} {g : ℝ → E} (hf : C continuous right-derivative `f'` in `(a, b)`, and `g` is continuous on `f '' [a, b]` then we can substitute `u = f x` to get `∫ x in a..b, f' x • (g ∘ f) x = ∫ u in f a..f b, g u`. -/ -theorem integral_comp_smul_deriv'' {f f' : ℝ → ℝ} {g : ℝ → E} (hf : ContinuousOn f [[a, b]]) +theorem integral_comp_smul_deriv'' {f f' : ℝ → ℝ} {g : ℝ → G} (hf : ContinuousOn f [[a, b]]) (hff' : ∀ x ∈ Ioo (min a b) (max a b), HasDerivWithinAt f (f' x) (Ioi x) x) (hf' : ContinuousOn f' [[a, b]]) (hg : ContinuousOn g (f '' [[a, b]])) : (∫ x in a..b, f' x • (g ∘ f) x) = ∫ u in f a..f b, g u := by @@ -1432,7 +1440,7 @@ and `g` is continuous on `f '' [a, b]`, then we can substitute `u = f x` to get Compared to `intervalIntegral.integral_comp_smul_deriv` we only require that `g` is continuous on `f '' [a, b]`. -/ -theorem integral_comp_smul_deriv' {f f' : ℝ → ℝ} {g : ℝ → E} +theorem integral_comp_smul_deriv' {f f' : ℝ → ℝ} {g : ℝ → G} (h : ∀ x ∈ uIcc a b, HasDerivAt f (f' x) x) (h' : ContinuousOn f' (uIcc a b)) (hg : ContinuousOn g (f '' [[a, b]])) : (∫ x in a..b, f' x • (g ∘ f) x) = ∫ x in f a..f b, g x := @@ -1444,7 +1452,7 @@ theorem integral_comp_smul_deriv' {f f' : ℝ → ℝ} {g : ℝ → E} and `g` is continuous, then we can substitute `u = f x` to get `∫ x in a..b, f' x • (g ∘ f) x = ∫ u in f a..f b, g u`. -/ -theorem integral_comp_smul_deriv {f f' : ℝ → ℝ} {g : ℝ → E} +theorem integral_comp_smul_deriv {f f' : ℝ → ℝ} {g : ℝ → G} (h : ∀ x ∈ uIcc a b, HasDerivAt f (f' x) x) (h' : ContinuousOn f' (uIcc a b)) (hg : Continuous g) : (∫ x in a..b, f' x • (g ∘ f) x) = ∫ x in f a..f b, g x := integral_comp_smul_deriv' h h' hg.continuousOn diff --git a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean index 5caffbd50b781..9d483849f878b 100644 --- a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean +++ b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean @@ -683,7 +683,7 @@ theorem integral_Ioi_of_hasDerivAt_of_tendsto (hcont : ContinuousWithinAt f (Ici apply intervalIntegral.integral_eq_sub_of_hasDerivAt_of_le h'x (hcont.mono Icc_subset_Ici_self) fun y hy => hderiv y hy.1 - rw [intervalIntegrable_iff_integrable_Ioc_of_le h'x] + rw [intervalIntegrable_iff_integrableOn_Ioc_of_le h'x] exact f'int.mono (fun y hy => hy.1) le_rfl #align measure_theory.integral_Ioi_of_has_deriv_at_of_tendsto MeasureTheory.integral_Ioi_of_hasDerivAt_of_tendsto @@ -731,7 +731,7 @@ theorem integrableOn_Ioi_deriv_of_nonneg (hcont : ContinuousWithinAt g (Ici a) a symm apply intervalIntegral.integral_eq_sub_of_hasDerivAt_of_le h'x (hcont.mono Icc_subset_Ici_self) fun y hy => hderiv y hy.1 - rw [intervalIntegrable_iff_integrable_Ioc_of_le h'x] + rw [intervalIntegrable_iff_integrableOn_Ioc_of_le h'x] exact intervalIntegral.integrableOn_deriv_of_nonneg (hcont.mono Icc_subset_Ici_self) (fun y hy => hderiv y hy.1) fun y hy => g'pos y hy.1 _ = ∫ y in a..id x, ‖g' y‖ := by @@ -835,7 +835,7 @@ theorem integral_Iic_of_hasDerivAt_of_tendsto (hcont : ContinuousWithinAt f (Iic symm apply intervalIntegral.integral_eq_sub_of_hasDerivAt_of_le hx (hcont.mono Icc_subset_Iic_self) fun y hy => hderiv y hy.2 - rw [intervalIntegrable_iff_integrable_Ioc_of_le hx] + rw [intervalIntegrable_iff_integrableOn_Ioc_of_le hx] exact f'int.mono (fun y hy => hy.2) le_rfl /-- **Fundamental theorem of calculus-2**, on semi-infinite intervals `(-∞, a)`. @@ -867,7 +867,7 @@ open Real open scoped Interval -variable {E : Type*} {f : ℝ → E} [NormedAddCommGroup E] [NormedSpace ℝ E] [CompleteSpace E] +variable {E : Type*} {f : ℝ → E} [NormedAddCommGroup E] [NormedSpace ℝ E] /-- Change-of-variables formula for `Ioi` integrals of vector-valued functions, proved by taking limits from the result for finite intervals. -/ diff --git a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean index 3e6ad1de93990..cbfc79abcb452 100644 --- a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean @@ -86,20 +86,28 @@ theorem IntervalIntegrable.def (h : IntervalIntegrable f μ a b) : IntegrableOn intervalIntegrable_iff.mp h #align interval_integrable.def IntervalIntegrable.def -theorem intervalIntegrable_iff_integrable_Ioc_of_le (hab : a ≤ b) : +theorem intervalIntegrable_iff_integrableOn_Ioc_of_le (hab : a ≤ b) : IntervalIntegrable f μ a b ↔ IntegrableOn f (Ioc a b) μ := by rw [intervalIntegrable_iff, uIoc_of_le hab] -#align interval_integrable_iff_integrable_Ioc_of_le intervalIntegrable_iff_integrable_Ioc_of_le +#align interval_integrable_iff_integrable_Ioc_of_le intervalIntegrable_iff_integrableOn_Ioc_of_le theorem intervalIntegrable_iff' [NoAtoms μ] : IntervalIntegrable f μ a b ↔ IntegrableOn f (uIcc a b) μ := by rw [intervalIntegrable_iff, ← Icc_min_max, uIoc, integrableOn_Icc_iff_integrableOn_Ioc] #align interval_integrable_iff' intervalIntegrable_iff' -theorem intervalIntegrable_iff_integrable_Icc_of_le {f : ℝ → E} {a b : ℝ} (hab : a ≤ b) +theorem intervalIntegrable_iff_integrableOn_Icc_of_le {f : ℝ → E} {a b : ℝ} (hab : a ≤ b) {μ : Measure ℝ} [NoAtoms μ] : IntervalIntegrable f μ a b ↔ IntegrableOn f (Icc a b) μ := by - rw [intervalIntegrable_iff_integrable_Ioc_of_le hab, integrableOn_Icc_iff_integrableOn_Ioc] -#align interval_integrable_iff_integrable_Icc_of_le intervalIntegrable_iff_integrable_Icc_of_le + rw [intervalIntegrable_iff_integrableOn_Ioc_of_le hab, integrableOn_Icc_iff_integrableOn_Ioc] +#align interval_integrable_iff_integrable_Icc_of_le intervalIntegrable_iff_integrableOn_Icc_of_le + +theorem intervalIntegrable_iff_integrableOn_Ico_of_le [NoAtoms μ] (hab : a ≤ b) : + IntervalIntegrable f μ a b ↔ IntegrableOn f (Ico a b) μ := by + rw [intervalIntegrable_iff_integrableOn_Icc_of_le hab, integrableOn_Icc_iff_integrableOn_Ico] + +theorem intervalIntegrable_iff_integrableOn_Ioo_of_le [NoAtoms μ] (hab : a ≤ b) : + IntervalIntegrable f μ a b ↔ IntegrableOn f (Ioo a b) μ := by + rw [intervalIntegrable_iff_integrableOn_Icc_of_le hab, integrableOn_Icc_iff_integrableOn_Ioo] /-- If a function is integrable with respect to a given measure `μ` then it is interval integrable with respect to `μ` on `uIcc a b`. -/ @@ -1197,7 +1205,8 @@ theorem continuousOn_primitive [NoAtoms μ] (h_int : IntegrableOn f (Icc a b) μ rw [continuousOn_congr this] intro x₀ _ refine' continuousWithinAt_primitive (measure_singleton x₀) _ - simp only [intervalIntegrable_iff_integrable_Ioc_of_le, min_eq_left, max_eq_right, h, min_self] + simp only [intervalIntegrable_iff_integrableOn_Ioc_of_le, min_eq_left, max_eq_right, h, + min_self] exact h_int.mono Ioc_subset_Icc_self le_rfl · rw [Icc_eq_empty h] exact continuousOn_empty _ diff --git a/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean b/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean index 7ed4718d1723a..db55576954577 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/NormedSpace.lean @@ -53,7 +53,7 @@ end ContinuousLinearEquiv variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [MeasurableSpace E] [BorelSpace E] [FiniteDimensional ℝ E] (μ : Measure E) [IsAddHaarMeasure μ] {F : Type*} [NormedAddCommGroup F] - [NormedSpace ℝ F] [CompleteSpace F] + [NormedSpace ℝ F] variable {s : Set E} @@ -62,6 +62,8 @@ integral of `f`. The formula we give works even when `f` is not integrable or `R thanks to the convention that a non-integrable function has integral zero. -/ theorem integral_comp_smul (f : E → F) (R : ℝ) : (∫ x, f (R • x) ∂μ) = |(R ^ finrank ℝ E)⁻¹| • ∫ x, f x ∂μ := by + by_cases hF : CompleteSpace F; swap + · simp [integral, hF] rcases eq_or_ne R 0 with (rfl | hR) · simp only [zero_smul, integral_const] rcases Nat.eq_zero_or_pos (finrank ℝ E) with (hE | hE) diff --git a/Mathlib/NumberTheory/ZetaFunction.lean b/Mathlib/NumberTheory/ZetaFunction.lean index ae85bd1b85b88..07afe9a77ea8c 100644 --- a/Mathlib/NumberTheory/ZetaFunction.lean +++ b/Mathlib/NumberTheory/ZetaFunction.lean @@ -172,8 +172,10 @@ theorem locally_integrable_zetaKernel₂ : LocallyIntegrableOn zetaKernel₂ (Io #align locally_integrable_zeta_kernel₂ locally_integrable_zetaKernel₂ /-- Functional equation for `zetaKernel₂`. -/ -theorem zetaKernel₂_one_div {t : ℝ} (ht : 0 < t) : +theorem zetaKernel₂_one_div {t : ℝ} (ht : 0 ≤ t) : zetaKernel₂ (1 / t) = sqrt t * zetaKernel₂ t := by + rcases ht.eq_or_lt with rfl|h't + · simp [zetaKernel₂, zetaKernel₁] have aux : ∀ {u : ℝ} (_ : 1 < u), zetaKernel₂ (1 / u) = sqrt u * zetaKernel₂ u := by intro u hu simp_rw [zetaKernel₂, Pi.add_apply] @@ -195,9 +197,9 @@ theorem zetaKernel₂_one_div {t : ℝ} (ht : 0 < t) : rcases lt_trichotomy 1 t with (h | h | h) · exact aux h · simp only [← h, div_self, Ne.def, one_ne_zero, not_false_iff, sqrt_one, ofReal_one, one_mul] - · have := aux (show 1 < 1 / t by rwa [lt_one_div (zero_lt_one' ℝ) ht, div_one]) + · have := aux (show 1 < 1 / t by rwa [lt_one_div (zero_lt_one' ℝ) h't, div_one]) rw [one_div_one_div] at this - rw [this, ← mul_assoc, ← ofReal_mul, ← sqrt_mul ht.le, mul_one_div_cancel ht.ne', sqrt_one, + rw [this, ← mul_assoc, ← ofReal_mul, ← sqrt_mul ht, mul_one_div_cancel h't.ne', sqrt_one, ofReal_one, one_mul] #align zeta_kernel₂_one_div zetaKernel₂_one_div @@ -240,7 +242,7 @@ theorem isBigO_zero_zetaKernel₂ : IsBigO (𝓝[>] 0) zetaKernel₂ fun t => ex simp_rw [← one_div] at h1 have h2 : zetaKernel₂ ∘ Div.div 1 =ᶠ[𝓝[>] 0] fun t => sqrt t * zetaKernel₂ t := eventually_of_mem self_mem_nhdsWithin fun t ht => by - dsimp only; rw [← zetaKernel₂_one_div ht]; rfl + dsimp only; rw [← zetaKernel₂_one_div (le_of_lt ht)]; rfl have h3 := h1.congr' h2 (EventuallyEq.refl _ _) have h4 := h3.mul (isBigO_refl (fun t : ℝ => 1 / (sqrt t : ℂ)) (𝓝[>] 0)).norm_right refine h4.congr' ?_ ?_ @@ -641,12 +643,12 @@ theorem riemannZeta_four : riemannZeta 4 = π ^ 4 / 90 := by `Λ₀(1 - s) = Λ₀ s`. -/ theorem riemannCompletedZeta₀_one_sub (s : ℂ) : riemannCompletedZeta₀ (1 - s) = riemannCompletedZeta₀ s := by - have := mellin_comp_rpow zetaKernel₂ (s / 2 - 1 / 2) neg_one_lt_zero.ne + have := mellin_comp_rpow zetaKernel₂ (s / 2 - 1 / 2) (-1) simp_rw [rpow_neg_one, ← one_div, abs_neg, abs_one, div_one, one_smul, ofReal_neg, ofReal_one, div_neg, div_one, neg_sub] at this conv_lhs => rw [riemannCompletedZeta₀, sub_div, ← this] refine set_integral_congr measurableSet_Ioi fun t ht => ?_ - simp_rw [zetaKernel₂_one_div ht, smul_eq_mul, ← mul_assoc, sqrt_eq_rpow, + simp_rw [zetaKernel₂_one_div (le_of_lt ht), smul_eq_mul, ← mul_assoc, sqrt_eq_rpow, ofReal_cpow (le_of_lt ht), ← cpow_add _ _ (ofReal_ne_zero.mpr <| ne_of_gt ht)] congr 2 push_cast diff --git a/Mathlib/Order/Filter/Interval.lean b/Mathlib/Order/Filter/Interval.lean index 23f60e8d167af..a5b3e3166251b 100644 --- a/Mathlib/Order/Filter/Interval.lean +++ b/Mathlib/Order/Filter/Interval.lean @@ -12,10 +12,41 @@ import Mathlib.Order.Filter.AtTopBot /-! # Convergence of intervals +## Motivation + +If a function tends to infinity somewhere, then its derivative is not integrable around this place. +One should be careful about this statement: "somewhere" could mean a point, but also convergence +from the left or from the right, or it could also be infinity, and "around this place" will refer +to these directed neighborhoods. Therefore, the above theorem has many variants. Instead of stating +all these variants, one can look for the common abstraction and have a single version. One has to +be careful: if one considers convergence along a sequence, then the function may tend to infinity +but have a derivative which is small along the sequence (with big jumps inbetween), so in the end +the derivative may be integrable on a neighborhood of the sequence. What really matters for such +calculus issues in terms of derivatives is that whole intervals are included in the sets we +consider. + +The right common abstraction is provided in this file, as the `TendstoIxxClass` typeclass. +It takes as parameters a class of bounded intervals and two real filters `l₁` and `l₂`. +An instance `TendstoIxxClass Icc l₁ l₂` registers that, if `aₙ` and `bₙ` are converging towards +the filter `l₁`, then the intervals `Icc aₙ bₙ` are eventually contained in any given set +belonging to `l₂`. For instance, for `l₁ = 𝓝[>] x` and `l₂ = 𝓝[≥] x`, the strict and large right +neighborhoods of `x` respectively, then given any large right neighborhood `s ∈ 𝓝[≥] x` and any two +sequences `xₙ` and `yₙ` converging strictly to the right of `x`, +then the interval `[xₙ, yₙ]` is eventually contained in `s`. Therefore, the instance +`TendstoIxxClass Icc (𝓝[>] x) (𝓝[≥] x)` holds. Note that one could have taken as +well `l₂ = 𝓝[>] x`, but that `l₁ = 𝓝[≥] x` and `l₂ = 𝓝[>] x` wouldn't work. + +With this formalism, the above theorem would read: if `TendstoIxxClass Icc l l` and `f` tends +to infinity along `l`, then its derivative is not integrable on any element of `l`. +Beyond this simple example, this typeclass plays a prominent role in generic formulations of +the fundamental theorem of calculus. + +## Main definition + If both `a` and `b` tend to some filter `l₁`, sometimes this implies that `Ixx a b` tends to `l₂.smallSets`, i.e., for any `s ∈ l₂` eventually `Ixx a b` becomes a subset of `s`. Here and below -`Ixx` is one of `Set.Icc`, `Set.Ico`, `Set.Ioc`, and `Set.Ioo`. We define `Filter.TendstoIxxClass -Ixx l₁ l₂` to be a typeclass representing this property. +`Ixx` is one of `Set.Icc`, `Set.Ico`, `Set.Ioc`, and `Set.Ioo`. +We define `Filter.TendstoIxxClass Ixx l₁ l₂` to be a typeclass representing this property. 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 diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean index 586b37fe8e26a..23a6b5c68250c 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean @@ -1347,6 +1347,30 @@ theorem Summable.countable_support [FirstCountableTopology G] [T1Space G] (hf : Summable f) : f.support.Countable := by simpa only [ker_nhds] using hf.tendsto_cofinite_zero.countable_compl_preimage_ker +theorem summable_const_iff [Infinite β] [T2Space G] (a : G) : + Summable (fun _ : β ↦ a) ↔ a = 0 := by + refine ⟨fun h ↦ ?_, ?_⟩ + · by_contra ha + have : {a}ᶜ ∈ 𝓝 0 := compl_singleton_mem_nhds (Ne.symm ha) + have : Finite β := by + simpa [← Set.finite_univ_iff] using h.tendsto_cofinite_zero this + exact not_finite β + · rintro rfl + exact summable_zero + +@[simp] +theorem tsum_const [T2Space G] : ∑' _ : β, (a : G) = Nat.card β • a := by + rcases finite_or_infinite β with hβ|hβ + · letI : Fintype β := Fintype.ofFinite β + rw [tsum_eq_sum (s := univ) (fun x hx ↦ (hx (mem_univ x)).elim)] + simp only [sum_const, Nat.card_eq_fintype_card] + rfl + · simp only [Nat.card_eq_zero_of_infinite, zero_smul] + rcases eq_or_ne a 0 with rfl|ha + · simp + · apply tsum_eq_zero_of_not_summable + simpa [summable_const_iff] using ha + end TopologicalGroup section ConstSMul From 58d258cfa010b770993287cf7a8c694044935172 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 20 Dec 2023 19:25:43 +0000 Subject: [PATCH 099/353] feat(Filter/{NAry,Pointwise}): add missing `NeBot` instances (#9055) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add missing `Filter.NeBot` instances for `Filter.map₂` and pointwise operations, rename `Filter.prod_neBot'` to `Filter.prod.instNeBot`. - Make `Filter.prod_eq_bot` a `simp` lemma. - Protect some lemmas. - Golf some proofs. - Make `Filter.map₂_left` and `Filter.map₂_right` take `NeBot` argument as an instance. --- Mathlib/Order/Filter/NAry.lean | 88 ++++++++--------------------- Mathlib/Order/Filter/Pointwise.lean | 48 ++++++++++++---- Mathlib/Order/Filter/Prod.lean | 7 ++- 3 files changed, 65 insertions(+), 78 deletions(-) diff --git a/Mathlib/Order/Filter/NAry.lean b/Mathlib/Order/Filter/NAry.lean index 39b454f9a2079..a8916ef2ecd52 100644 --- a/Mathlib/Order/Filter/NAry.lean +++ b/Mathlib/Order/Filter/NAry.lean @@ -100,94 +100,59 @@ theorem le_map₂_iff {h : Filter γ} : #align filter.le_map₂_iff Filter.le_map₂_iff @[simp] -theorem map₂_bot_left : map₂ m ⊥ g = ⊥ := - empty_mem_iff_bot.1 ⟨∅, univ, trivial, univ_mem, image2_empty_left.subset⟩ -#align filter.map₂_bot_left Filter.map₂_bot_left +theorem map₂_eq_bot_iff : map₂ m f g = ⊥ ↔ f = ⊥ ∨ g = ⊥ := by simp [← map_prod_eq_map₂] +#align filter.map₂_eq_bot_iff Filter.map₂_eq_bot_iff @[simp] -theorem map₂_bot_right : map₂ m f ⊥ = ⊥ := - empty_mem_iff_bot.1 ⟨univ, ∅, univ_mem, trivial, image2_empty_right.subset⟩ -#align filter.map₂_bot_right Filter.map₂_bot_right +theorem map₂_bot_left : map₂ m ⊥ g = ⊥ := map₂_eq_bot_iff.2 <| .inl rfl +#align filter.map₂_bot_left Filter.map₂_bot_left @[simp] -theorem map₂_eq_bot_iff : map₂ m f g = ⊥ ↔ f = ⊥ ∨ g = ⊥ := by - simp only [← empty_mem_iff_bot, mem_map₂_iff, subset_empty_iff, image2_eq_empty_iff] - constructor - · rintro ⟨s, t, hs, ht, rfl | rfl⟩ - · exact Or.inl hs - · exact Or.inr ht - · rintro (h | h) - · exact ⟨_, _, h, univ_mem, Or.inl rfl⟩ - · exact ⟨_, _, univ_mem, h, Or.inr rfl⟩ -#align filter.map₂_eq_bot_iff Filter.map₂_eq_bot_iff +theorem map₂_bot_right : map₂ m f ⊥ = ⊥ := map₂_eq_bot_iff.2 <| .inr rfl +#align filter.map₂_bot_right Filter.map₂_bot_right @[simp] -theorem map₂_neBot_iff : (map₂ m f g).NeBot ↔ f.NeBot ∧ g.NeBot := by - simp_rw [neBot_iff] - exact map₂_eq_bot_iff.not.trans not_or +theorem map₂_neBot_iff : (map₂ m f g).NeBot ↔ f.NeBot ∧ g.NeBot := by simp [neBot_iff, not_or] #align filter.map₂_ne_bot_iff Filter.map₂_neBot_iff -theorem NeBot.map₂ (hf : f.NeBot) (hg : g.NeBot) : (map₂ m f g).NeBot := +protected theorem NeBot.map₂ (hf : f.NeBot) (hg : g.NeBot) : (map₂ m f g).NeBot := map₂_neBot_iff.2 ⟨hf, hg⟩ #align filter.ne_bot.map₂ Filter.NeBot.map₂ --- Porting note: Why do I have to specify the `Filter` namespace for `map₂` here? -theorem NeBot.of_map₂_left (h : (Filter.map₂ m f g).NeBot) : f.NeBot := +instance map₂.neBot [NeBot f] [NeBot g] : NeBot (map₂ m f g) := .map₂ ‹_› ‹_› + +theorem NeBot.of_map₂_left (h : (map₂ m f g).NeBot) : f.NeBot := (map₂_neBot_iff.1 h).1 #align filter.ne_bot.of_map₂_left Filter.NeBot.of_map₂_left -theorem NeBot.of_map₂_right (h : (Filter.map₂ m f g).NeBot) : g.NeBot := +theorem NeBot.of_map₂_right (h : (map₂ m f g).NeBot) : g.NeBot := (map₂_neBot_iff.1 h).2 #align filter.ne_bot.of_map₂_right Filter.NeBot.of_map₂_right theorem map₂_sup_left : map₂ m (f₁ ⊔ f₂) g = map₂ m f₁ g ⊔ map₂ m f₂ g := by - ext u - constructor - · rintro ⟨s, t, ⟨h₁, h₂⟩, ht, hu⟩ - exact ⟨mem_of_superset (image2_mem_map₂ h₁ ht) hu, mem_of_superset (image2_mem_map₂ h₂ ht) hu⟩ - · rintro ⟨⟨s₁, t₁, hs₁, ht₁, hu₁⟩, s₂, t₂, hs₂, ht₂, hu₂⟩ - refine' ⟨s₁ ∪ s₂, t₁ ∩ t₂, union_mem_sup hs₁ hs₂, inter_mem ht₁ ht₂, _⟩ - rw [image2_union_left] - exact - union_subset ((image2_subset_left <| inter_subset_left _ _).trans hu₁) - ((image2_subset_left <| inter_subset_right _ _).trans hu₂) + simp_rw [← map_prod_eq_map₂, sup_prod, map_sup] #align filter.map₂_sup_left Filter.map₂_sup_left theorem map₂_sup_right : map₂ m f (g₁ ⊔ g₂) = map₂ m f g₁ ⊔ map₂ m f g₂ := by - ext u - constructor - · rintro ⟨s, t, hs, ⟨h₁, h₂⟩, hu⟩ - exact ⟨mem_of_superset (image2_mem_map₂ hs h₁) hu, mem_of_superset (image2_mem_map₂ hs h₂) hu⟩ - · rintro ⟨⟨s₁, t₁, hs₁, ht₁, hu₁⟩, s₂, t₂, hs₂, ht₂, hu₂⟩ - refine' ⟨s₁ ∩ s₂, t₁ ∪ t₂, inter_mem hs₁ hs₂, union_mem_sup ht₁ ht₂, _⟩ - rw [image2_union_right] - exact - union_subset ((image2_subset_right <| inter_subset_left _ _).trans hu₁) - ((image2_subset_right <| inter_subset_right _ _).trans hu₂) + simp_rw [← map_prod_eq_map₂, prod_sup, map_sup] #align filter.map₂_sup_right Filter.map₂_sup_right theorem map₂_inf_subset_left : map₂ m (f₁ ⊓ f₂) g ≤ map₂ m f₁ g ⊓ map₂ m f₂ g := - le_inf (map₂_mono_right inf_le_left) (map₂_mono_right inf_le_right) + Monotone.map_inf_le (fun _ _ ↦ map₂_mono_right) f₁ f₂ #align filter.map₂_inf_subset_left Filter.map₂_inf_subset_left theorem map₂_inf_subset_right : map₂ m f (g₁ ⊓ g₂) ≤ map₂ m f g₁ ⊓ map₂ m f g₂ := - le_inf (map₂_mono_left inf_le_left) (map₂_mono_left inf_le_right) + Monotone.map_inf_le (fun _ _ ↦ map₂_mono_left) g₁ g₂ #align filter.map₂_inf_subset_right Filter.map₂_inf_subset_right @[simp] -theorem map₂_pure_left : map₂ m (pure a) g = g.map fun b => m a b := - Filter.ext fun u => - ⟨fun ⟨s, t, hs, ht, hu⟩ => - mem_of_superset (image_mem_map ht) ((image_subset_image2_right <| mem_pure.1 hs).trans hu), - fun h => ⟨{a}, _, singleton_mem_pure, h, by rw [image2_singleton_left, image_subset_iff]⟩⟩ +theorem map₂_pure_left : map₂ m (pure a) g = g.map (m a) := by + rw [← map_prod_eq_map₂, pure_prod, map_map]; rfl #align filter.map₂_pure_left Filter.map₂_pure_left @[simp] -theorem map₂_pure_right : map₂ m f (pure b) = f.map fun a => m a b := - Filter.ext fun u => - ⟨fun ⟨s, t, hs, ht, hu⟩ => - mem_of_superset (image_mem_map hs) ((image_subset_image2_left <| mem_pure.1 ht).trans hu), - fun h => ⟨_, {b}, h, singleton_mem_pure, by rw [image2_singleton_right, image_subset_iff]⟩⟩ +theorem map₂_pure_right : map₂ m f (pure b) = f.map (m · b) := by + rw [← map_prod_eq_map₂, prod_pure, map_map]; rfl #align filter.map₂_pure_right Filter.map₂_pure_right theorem map₂_pure : map₂ m (pure a) (pure b) = pure (m a b) := by rw [map₂_pure_right, map_pure] @@ -200,23 +165,18 @@ theorem map₂_swap (m : α → β → γ) (f : Filter α) (g : Filter β) : #align filter.map₂_swap Filter.map₂_swap @[simp] -theorem map₂_left (h : g.NeBot) : map₂ (fun x _ => x) f g = f := by - ext u - refine' ⟨_, fun hu => ⟨_, _, hu, univ_mem, (image2_left <| h.nonempty_of_mem univ_mem).subset⟩⟩ - rintro ⟨s, t, hs, ht, hu⟩ - rw [image2_left (h.nonempty_of_mem ht)] at hu - exact mem_of_superset hs hu +theorem map₂_left [NeBot g] : map₂ (fun x _ => x) f g = f := by + rw [← map_prod_eq_map₂, map_fst_prod] #align filter.map₂_left Filter.map₂_left @[simp] -theorem map₂_right (h : f.NeBot) : map₂ (fun _ y => y) f g = g := by rw [map₂_swap, map₂_left h] +theorem map₂_right [NeBot f] : map₂ (fun _ y => y) f g = g := by rw [map₂_swap, map₂_left] #align filter.map₂_right Filter.map₂_right /-- The image of a ternary function `m : α → β → γ → δ` as a function `Filter α → Filter β → Filter γ → Filter δ`. Mathematically this should be thought of as the image of the corresponding function `α × β × γ → δ`. -/ -def map₃ (m : α → β → γ → δ) (f : Filter α) (g : Filter β) (h : Filter γ) : Filter δ - where +def map₃ (m : α → β → γ → δ) (f : Filter α) (g : Filter β) (h : Filter γ) : Filter δ where sets := { s | ∃ u v w, u ∈ f ∧ v ∈ g ∧ w ∈ h ∧ image3 m u v w ⊆ s } univ_sets := ⟨univ, univ, univ, univ_sets _, univ_sets _, univ_sets _, subset_univ _⟩ sets_of_superset hs hst := diff --git a/Mathlib/Order/Filter/Pointwise.lean b/Mathlib/Order/Filter/Pointwise.lean index 4ff5c60ceda8a..69a10231cf860 100644 --- a/Mathlib/Order/Filter/Pointwise.lean +++ b/Mathlib/Order/Filter/Pointwise.lean @@ -102,13 +102,13 @@ theorem principal_one : 𝓟 1 = (1 : Filter α) := #align filter.principal_one Filter.principal_one #align filter.principal_zero Filter.principal_zero -@[to_additive] -- TODO: make this a scoped instance in the `Pointwise` namespace +@[to_additive] theorem one_neBot : (1 : Filter α).NeBot := Filter.pure_neBot #align filter.one_ne_bot Filter.one_neBot #align filter.zero_ne_bot Filter.zero_neBot -scoped[Pointwise] attribute [instance] Filter.one_neBot +scoped[Pointwise] attribute [instance] one_neBot zero_neBot @[to_additive (attr := simp)] protected theorem map_one' (f : α → β) : (1 : Filter α).map f = pure (f 1) := @@ -224,10 +224,15 @@ theorem neBot_inv_iff : f⁻¹.NeBot ↔ NeBot f := #align filter.ne_bot_neg_iff Filter.neBot_neg_iff @[to_additive] -theorem NeBot.inv : f.NeBot → f⁻¹.NeBot := fun h => h.map _ +protected theorem NeBot.inv : f.NeBot → f⁻¹.NeBot := fun h => h.map _ #align filter.ne_bot.inv Filter.NeBot.inv #align filter.ne_bot.neg Filter.NeBot.neg +@[to_additive neg.instNeBot] +lemma inv.instNeBot [NeBot f] : NeBot f⁻¹ := .inv ‹_› + +scoped[Pointwise] attribute [instance] inv.instNeBot neg.instNeBot + end Inv section InvolutiveInv @@ -336,7 +341,7 @@ lemma mul_neBot_iff : (f * g).NeBot ↔ f.NeBot ∧ g.NeBot := #align filter.add_ne_bot_iff Filter.add_neBot_iff @[to_additive] -theorem NeBot.mul : NeBot f → NeBot g → NeBot (f * g) := +protected theorem NeBot.mul : NeBot f → NeBot g → NeBot (f * g) := NeBot.map₂ #align filter.ne_bot.mul Filter.NeBot.mul #align filter.ne_bot.add Filter.NeBot.add @@ -353,6 +358,11 @@ theorem NeBot.of_mul_right : (f * g).NeBot → g.NeBot := #align filter.ne_bot.of_mul_right Filter.NeBot.of_mul_right #align filter.ne_bot.of_add_right Filter.NeBot.of_add_right +@[to_additive add.instNeBot] +protected lemma mul.instNeBot [NeBot f] [NeBot g] : NeBot (f * g) := .mul ‹_› ‹_› + +scoped[Pointwise] attribute [instance] mul.instNeBot add.instNeBot + @[to_additive (attr := simp)] theorem pure_mul : pure a * g = g.map (a * ·) := map₂_pure_left @@ -418,7 +428,6 @@ end Mul /-! ### Filter subtraction/division -/ - section Div variable [Div α] {f f₁ f₂ g g₁ g₂ h : Filter α} {s t : Set α} {a b : α} @@ -470,14 +479,14 @@ theorem div_eq_bot_iff : f / g = ⊥ ↔ f = ⊥ ∨ g = ⊥ := #align filter.div_eq_bot_iff Filter.div_eq_bot_iff #align filter.sub_eq_bot_iff Filter.sub_eq_bot_iff -@[to_additive (attr := simp)] -- TODO: make this a scoped instance in the `Pointwise` namespace +@[to_additive (attr := simp)] theorem div_neBot_iff : (f / g).NeBot ↔ f.NeBot ∧ g.NeBot := map₂_neBot_iff #align filter.div_ne_bot_iff Filter.div_neBot_iff #align filter.sub_ne_bot_iff Filter.sub_neBot_iff @[to_additive] -theorem NeBot.div : NeBot f → NeBot g → NeBot (f / g) := +protected theorem NeBot.div : NeBot f → NeBot g → NeBot (f / g) := NeBot.map₂ #align filter.ne_bot.div Filter.NeBot.div #align filter.ne_bot.sub Filter.NeBot.sub @@ -494,6 +503,11 @@ theorem NeBot.of_div_right : (f / g).NeBot → g.NeBot := #align filter.ne_bot.of_div_right Filter.NeBot.of_div_right #align filter.ne_bot.of_sub_right Filter.NeBot.of_sub_right +@[to_additive sub.instNeBot] +lemma div.instNeBot [NeBot f] [NeBot g] : NeBot (f / g) := .div ‹_› ‹_› + +scoped[Pointwise] attribute [instance] div.instNeBot sub.instNeBot + @[to_additive (attr := simp)] theorem pure_div : pure a / g = g.map (a / ·) := map₂_pure_left @@ -832,7 +846,6 @@ variable [MulZeroClass α] {f g : Filter α} /-! Note that `Filter` is not a `MulZeroClass` because `0 * ⊥ ≠ 0`. -/ - theorem NeBot.mul_zero_nonneg (hf : f.NeBot) : 0 ≤ f * 0 := le_mul_iff.2 fun _ h₁ _ h₂ => let ⟨_, ha⟩ := hf.nonempty_of_mem h₁ @@ -1001,7 +1014,7 @@ theorem smul_neBot_iff : (f • g).NeBot ↔ f.NeBot ∧ g.NeBot := #align filter.vadd_ne_bot_iff Filter.vadd_neBot_iff @[to_additive] -theorem NeBot.smul : NeBot f → NeBot g → NeBot (f • g) := +protected theorem NeBot.smul : NeBot f → NeBot g → NeBot (f • g) := NeBot.map₂ #align filter.ne_bot.smul Filter.NeBot.smul #align filter.ne_bot.vadd Filter.NeBot.vadd @@ -1018,6 +1031,11 @@ theorem NeBot.of_smul_right : (f • g).NeBot → g.NeBot := #align filter.ne_bot.of_smul_right Filter.NeBot.of_smul_right #align filter.ne_bot.of_vadd_right Filter.NeBot.of_vadd_right +@[to_additive vadd.instNeBot] +lemma smul.instNeBot [NeBot f] [NeBot g] : NeBot (f • g) := .smul ‹_› ‹_› + +scoped[Pointwise] attribute [instance] smul.instNeBot vadd.instNeBot + @[to_additive (attr := simp)] theorem pure_smul : (pure a : Filter α) • g = g.map (a • ·) := map₂_pure_left @@ -1117,7 +1135,7 @@ theorem vsub_neBot_iff : (f -ᵥ g : Filter α).NeBot ↔ f.NeBot ∧ g.NeBot := map₂_neBot_iff #align filter.vsub_ne_bot_iff Filter.vsub_neBot_iff -theorem NeBot.vsub : NeBot f → NeBot g → NeBot (f -ᵥ g) := +protected theorem NeBot.vsub : NeBot f → NeBot g → NeBot (f -ᵥ g) := NeBot.map₂ #align filter.ne_bot.vsub Filter.NeBot.vsub @@ -1129,6 +1147,10 @@ theorem NeBot.of_vsub_right : (f -ᵥ g : Filter α).NeBot → g.NeBot := NeBot.of_map₂_right #align filter.ne_bot.of_vsub_right Filter.NeBot.of_vsub_right +lemma vsub.instNeBot [NeBot f] [NeBot g] : NeBot (f -ᵥ g) := .vsub ‹_› ‹_› + +scoped[Pointwise] attribute [instance] vsub.instNeBot + @[simp] theorem pure_vsub : (pure a : Filter β) -ᵥ g = g.map (a -ᵥ ·) := map₂_pure_left @@ -1225,6 +1247,11 @@ theorem NeBot.of_smul_filter : (a • f).NeBot → f.NeBot := #align filter.ne_bot.of_smul_filter Filter.NeBot.of_smul_filter #align filter.ne_bot.of_vadd_filter Filter.NeBot.of_vadd_filter +@[to_additive vadd_filter.instNeBot] +lemma smul_filter.instNeBot [NeBot f] : NeBot (a • f) := .smul_filter ‹_› + +scoped[Pointwise] attribute [instance] smul_filter.instNeBot vadd_filter.instNeBot + @[to_additive] theorem smul_filter_le_smul_filter (hf : f₁ ≤ f₂) : a • f₁ ≤ a • f₂ := map_mono hf @@ -1350,7 +1377,6 @@ Note that we have neither `SMulWithZero α (Filter β)` nor `SMulWithZero (Filte because `0 * ⊥ ≠ 0`. -/ - theorem NeBot.smul_zero_nonneg (hf : f.NeBot) : 0 ≤ f • (0 : Filter β) := le_smul_iff.2 fun _ h₁ _ h₂ => let ⟨_, ha⟩ := hf.nonempty_of_mem h₁ diff --git a/Mathlib/Order/Filter/Prod.lean b/Mathlib/Order/Filter/Prod.lean index 56db461ed0e58..e7deb41fa8b80 100644 --- a/Mathlib/Order/Filter/Prod.lean +++ b/Mathlib/Order/Filter/Prod.lean @@ -413,6 +413,7 @@ theorem prod_pure_pure {a : α} {b : β} : (pure a : Filter α) ×ˢ (pure b : Filter β) = pure (a, b) := by simp #align filter.prod_pure_pure Filter.prod_pure_pure +@[simp] theorem prod_eq_bot : f ×ˢ g = ⊥ ↔ f = ⊥ ∨ g = ⊥ := by simp_rw [← empty_mem_iff_bot, mem_prod_iff, subset_empty_iff, prod_eq_empty_iff, ← exists_prop, Subtype.exists', exists_or, exists_const, Subtype.exists, exists_prop, exists_eq_right] @@ -428,11 +429,11 @@ theorem prod_neBot : NeBot (f ×ˢ g) ↔ NeBot f ∧ NeBot g := by simp only [neBot_iff, Ne, prod_eq_bot, not_or] #align filter.prod_ne_bot Filter.prod_neBot -theorem NeBot.prod (hf : NeBot f) (hg : NeBot g) : NeBot (f ×ˢ g) := prod_neBot.2 ⟨hf, hg⟩ +protected theorem NeBot.prod (hf : NeBot f) (hg : NeBot g) : NeBot (f ×ˢ g) := prod_neBot.2 ⟨hf, hg⟩ #align filter.ne_bot.prod Filter.NeBot.prod -instance prod_neBot' [hf : NeBot f] [hg : NeBot g] : NeBot (f ×ˢ g) := hf.prod hg -#align filter.prod_ne_bot' Filter.prod_neBot' +instance prod.instNeBot [hf : NeBot f] [hg : NeBot g] : NeBot (f ×ˢ g) := hf.prod hg +#align filter.prod_ne_bot' Filter.prod.instNeBot @[simp] lemma disjoint_prod {f' : Filter α} {g' : Filter β} : From 96436702fcc78aecdf2d5d53a9dae698ee0ccb70 Mon Sep 17 00:00:00 2001 From: Jujian Zhang Date: Wed, 20 Dec 2023 19:25:44 +0000 Subject: [PATCH 100/353] feat(RingTheory/Artinian): the collection of maximal ideals in an artinian ring is finite (#9087) Co-PR: #9088 (minimal prime ideals in Noetherian ring are finite) --- Mathlib/RingTheory/Artinian.lean | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Mathlib/RingTheory/Artinian.lean b/Mathlib/RingTheory/Artinian.lean index 45ecbf69526b7..8cee2bae5f281 100644 --- a/Mathlib/RingTheory/Artinian.lean +++ b/Mathlib/RingTheory/Artinian.lean @@ -498,4 +498,27 @@ instance isMaximal_of_isPrime (p : Ideal R) [p.IsPrime] : p.IsMaximal := localization_surjective (nonZeroDivisors (R ⧸ p)) (FractionRing (R ⧸ p))⟩).isField _ <| Field.toIsField <| FractionRing (R ⧸ p) +lemma isPrime_iff_isMaximal (p : Ideal R) : p.IsPrime ↔ p.IsMaximal := + ⟨fun _ ↦ isMaximal_of_isPrime p, fun h ↦ h.isPrime⟩ + +variable (R) in +lemma primeSpectrum_finite : {I : Ideal R | I.IsPrime}.Finite := by + set Spec := {I : Ideal R | I.IsPrime} + obtain ⟨_, ⟨s, rfl⟩, H⟩ := set_has_minimal + (range (Finset.inf · Subtype.val : Finset Spec → Ideal R)) ⟨⊤, ∅, by simp⟩ + refine ⟨⟨s, fun p ↦ ?_⟩⟩ + classical + obtain ⟨q, hq1, hq2⟩ := p.2.inf_le'.mp <| inf_eq_right.mp <| + inf_le_right.eq_of_not_lt (H (p ⊓ s.inf Subtype.val) ⟨insert p s, by simp⟩) + rwa [← Subtype.ext <| (@isMaximal_of_isPrime _ _ _ _ q.2).eq_of_le p.2.1 hq2] + +variable (R) in +/-- +[Stacks Lemma 00J7](https://stacks.math.columbia.edu/tag/00J7) +-/ +lemma maximal_ideals_finite : {I : Ideal R | I.IsMaximal}.Finite := by + simp_rw [← isPrime_iff_isMaximal] + apply primeSpectrum_finite R + + end IsArtinianRing From d9b8c716a7ca6135a9b0007f7a516c4008e79390 Mon Sep 17 00:00:00 2001 From: David Loeffler Date: Wed, 20 Dec 2023 19:25:45 +0000 Subject: [PATCH 101/353] feat(NumberTheory/ZetaFunction): residue of Riemann zeta at s = 1 (#9165) We add the computation of the residue of the completed and non-completed Riemann zeta functions at `s = 1`. --- Mathlib/NumberTheory/ZetaFunction.lean | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Mathlib/NumberTheory/ZetaFunction.lean b/Mathlib/NumberTheory/ZetaFunction.lean index 07afe9a77ea8c..e6a04813ebfd8 100644 --- a/Mathlib/NumberTheory/ZetaFunction.lean +++ b/Mathlib/NumberTheory/ZetaFunction.lean @@ -799,3 +799,37 @@ theorem riemannZeta_neg_nat_eq_bernoulli (k : ℕ) : rw [inv_mul_cancel (ofReal_ne_zero.mpr <| pow_ne_zero _ pi_pos.ne'), inv_mul_cancel (ofReal_ne_zero.mpr <| pow_ne_zero _ two_ne_zero), one_mul, one_mul] #align riemann_zeta_neg_nat_eq_bernoulli riemannZeta_neg_nat_eq_bernoulli + +/-- The residue of `Λ(s)` at `s = 1` is equal to 1. -/ +lemma riemannCompletedZeta_residue_one : + Tendsto (fun s ↦ (s - 1) * riemannCompletedZeta s) (𝓝[≠] 1) (𝓝 1) := by + unfold riemannCompletedZeta + simp_rw [mul_add, mul_sub, (by simp : 𝓝 (1 : ℂ) = 𝓝 (0 - 0 + 1))] + refine ((Tendsto.sub ?_ ?_).mono_left nhdsWithin_le_nhds).add ?_ + · rw [(by simp : 𝓝 (0 : ℂ) = 𝓝 ((1 - 1) * riemannCompletedZeta₀ 1))] + apply ((continuous_sub_right _).mul differentiable_completed_zeta₀.continuous).tendsto + · rw [(by simp : 𝓝 (0 : ℂ) = 𝓝 ((1 - 1) * (1 / 1)))] + exact (((continuous_sub_right _).continuousAt).mul <| + continuousAt_const.div continuousAt_id one_ne_zero) + · refine (tendsto_const_nhds.mono_left nhdsWithin_le_nhds).congr' ?_ + refine eventually_nhdsWithin_of_forall (fun s hs ↦ ?_) + simpa using (div_self <| sub_ne_zero_of_ne <| Set.mem_compl_singleton_iff.mpr hs).symm + +/-- The residue of `ζ(s)` at `s = 1` is equal to 1. -/ +lemma riemannZeta_residue_one : Tendsto (fun s ↦ (s - 1) * riemannZeta s) (𝓝[≠] 1) (𝓝 1) := by + suffices : Tendsto (fun s => (s - 1) * + (π ^ (s / 2) * riemannCompletedZeta s / Gamma (s / 2))) (𝓝[≠] 1) (𝓝 1) + · refine this.congr' <| (eventually_ne_nhdsWithin one_ne_zero).mp (eventually_of_forall ?_) + intro x hx + simp [riemannZeta_def, Function.update_noteq hx] + have h0 : Tendsto (fun s ↦ π ^ (s / 2) : ℂ → ℂ) (𝓝[≠] 1) (𝓝 (π ^ (1 / 2 : ℂ))) + · refine ((continuousAt_id.div_const _).const_cpow ?_).tendsto.mono_left nhdsWithin_le_nhds + exact Or.inl <| ofReal_ne_zero.mpr pi_ne_zero + have h1 : Tendsto (fun s : ℂ ↦ 1 / Gamma (s / 2)) (𝓝[≠] 1) (𝓝 (1 / π ^ (1 / 2 : ℂ))) + · rw [← Complex.Gamma_one_half_eq] + refine (Continuous.tendsto ?_ _).mono_left nhdsWithin_le_nhds + simpa using differentiable_one_div_Gamma.continuous.comp (continuous_id.div_const _) + convert (riemannCompletedZeta_residue_one.mul h0).mul h1 using 2 with s + · ring + · have := fun h ↦ ofReal_ne_zero.mpr pi_ne_zero ((cpow_eq_zero_iff _ (1 / 2)).mp h).1 + field_simp From e4dff73fddfbed90924bfc66a42e490372b572a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 20 Dec 2023 20:21:09 +0000 Subject: [PATCH 102/353] doc: Explain relative Sylow theorems (#9158) Requested by @urkud --- Mathlib/GroupTheory/Sylow.lean | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/Mathlib/GroupTheory/Sylow.lean b/Mathlib/GroupTheory/Sylow.lean index 3b95deaa7c007..ce8e024089543 100644 --- a/Mathlib/GroupTheory/Sylow.lean +++ b/Mathlib/GroupTheory/Sylow.lean @@ -653,25 +653,31 @@ theorem exists_subgroup_card_pow_prime [Fintype G] (p : ℕ) {n : ℕ} [Fact p.P ⟨K, hK.1⟩ #align sylow.exists_subgroup_card_pow_prime Sylow.exists_subgroup_card_pow_prime -lemma exists_subgroup_card_pow_prime_of_le_card {m p : ℕ} (hp : p.Prime) (h : IsPGroup p G) - (hm : p ^ m ≤ Nat.card G) : ∃ H : Subgroup G, Nat.card H = p ^ m := by +/-- A special case of **Sylow's first theorem**. If `G` is a `p`-group of size at least `p ^ n` +then there is a subgroup of cardinality `p ^ n`. -/ +lemma exists_subgroup_card_pow_prime_of_le_card {n p : ℕ} (hp : p.Prime) (h : IsPGroup p G) + (hn : p ^ n ≤ Nat.card G) : ∃ H : Subgroup G, Nat.card H = p ^ n := by have : Fact p.Prime := ⟨hp⟩ - have : Finite G := Nat.finite_of_card_ne_zero $ by linarith [Nat.one_le_pow m p hp.pos] + have : Finite G := Nat.finite_of_card_ne_zero $ by linarith [Nat.one_le_pow n p hp.pos] cases nonempty_fintype G - obtain ⟨n, hn⟩ := h.exists_card_eq - simp_rw [Nat.card_eq_fintype_card] at hn hm ⊢ + obtain ⟨m, hm⟩ := h.exists_card_eq + simp_rw [Nat.card_eq_fintype_card] at hm hn ⊢ refine exists_subgroup_card_pow_prime _ ?_ - rw [hn] at hm ⊢ - exact pow_dvd_pow _ $ (pow_le_pow_iff_right hp.one_lt).1 hm - -lemma exists_subgroup_le_card_pow_prime_of_le_card {m p : ℕ} (hp : p.Prime) (h : IsPGroup p G) - {H : Subgroup G} (hm : p ^ m ≤ Nat.card H) : ∃ H' ≤ H, Nat.card H' = p ^ m := by - obtain ⟨H', H'card⟩ := exists_subgroup_card_pow_prime_of_le_card hp (h.to_subgroup H) hm + rw [hm] at hn ⊢ + exact pow_dvd_pow _ $ (pow_le_pow_iff_right hp.one_lt).1 hn + +/-- A special case of **Sylow's first theorem**. If `G` is a `p`-group and `H` a subgroup of size at +least `p ^ n` then there is a subgroup of `H` of cardinality `p ^ n`. -/ +lemma exists_subgroup_le_card_pow_prime_of_le_card {n p : ℕ} (hp : p.Prime) (h : IsPGroup p G) + {H : Subgroup G} (hn : p ^ n ≤ Nat.card H) : ∃ H' ≤ H, Nat.card H' = p ^ n := by + obtain ⟨H', H'card⟩ := exists_subgroup_card_pow_prime_of_le_card hp (h.to_subgroup H) hn refine ⟨H'.map H.subtype, map_subtype_le _, ?_⟩ rw [← H'card] let e : H' ≃* H'.map H.subtype := H'.equivMapOfInjective (Subgroup.subtype H) H.subtype_injective exact Nat.card_congr e.symm.toEquiv +/-- A special case of **Sylow's first theorem**. If `G` is a `p`-group and `H` a subgroup of size at +least `k` then there is a subgroup of `H` of cardinality between `k / p` and `k`. -/ lemma exists_subgroup_le_card_le {k p : ℕ} (hp : p.Prime) (h : IsPGroup p G) {H : Subgroup G} (hk : k ≤ Nat.card H) (hk₀ : k ≠ 0) : ∃ H' ≤ H, Nat.card H' ≤ k ∧ k < p * Nat.card H' := by obtain ⟨m, hmk, hkm⟩ : ∃ s, p ^ s ≤ k ∧ k < p ^ (s + 1) := From 56ce93a6be8d523581e416d982f29abf429226d8 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 20 Dec 2023 23:32:43 +0000 Subject: [PATCH 103/353] chore(UniformConvergenceTopology): use `variable`, fix types (#9132) * Use `variable`. * Add `toFun`/`ofFun` to abuse the definitional equality less often. * Review instances in `Topology.Algebra.UniformConvergence`. * Replace `*_apply` lemmas with `toFun_*`/`ofFun_*` lemmas. --- .../Topology/Algebra/UniformConvergence.lean | 150 ++++++++++++++---- .../UniformConvergenceTopology.lean | 70 ++++---- 2 files changed, 159 insertions(+), 61 deletions(-) diff --git a/Mathlib/Topology/Algebra/UniformConvergence.lean b/Mathlib/Topology/Algebra/UniformConvergence.lean index 694c1a0250a5e..5e927c0ac278e 100644 --- a/Mathlib/Topology/Algebra/UniformConvergence.lean +++ b/Mathlib/Topology/Algebra/UniformConvergence.lean @@ -50,16 +50,80 @@ uniform convergence, strong dual -/ -set_option autoImplicit true +open Filter +open scoped Topology Pointwise UniformConvergence +section AlgebraicInstances -open Filter +variable {α β ι R : Type*} {𝔖 : Set <| Set α} {x : α} -open Topology Pointwise UniformConvergence +@[to_additive] instance [One β] : One (α →ᵤ β) := Pi.instOne -section AlgebraicInstances +@[to_additive (attr := simp)] +lemma UniformFun.toFun_one [One β] : toFun (1 : α →ᵤ β) = 1 := rfl + +@[to_additive (attr := simp)] +lemma UniformFun.ofFun_one [One β] : ofFun (1 : α → β) = 1 := rfl + +@[to_additive] instance [One β] : One (α →ᵤ[𝔖] β) := Pi.instOne + +@[to_additive (attr := simp)] +lemma UniformOnFun.toFun_one [One β] : toFun 𝔖 (1 : α →ᵤ[𝔖] β) = 1 := rfl + +@[to_additive (attr := simp)] +lemma UniformOnFun.one_apply [One β] : ofFun 𝔖 (1 : α → β) = 1 := rfl + +@[to_additive] instance [Mul β] : Mul (α →ᵤ β) := Pi.instMul + +@[to_additive (attr := simp)] +lemma UniformFun.toFun_mul [Mul β] (f g : α →ᵤ β) : toFun (f * g) = toFun f * toFun g := rfl + +@[to_additive (attr := simp)] +lemma UniformFun.ofFun_mul [Mul β] (f g : α → β) : ofFun (f * g) = ofFun f * ofFun g := rfl + +@[to_additive] instance [Mul β] : Mul (α →ᵤ[𝔖] β) := Pi.instMul + +@[to_additive (attr := simp)] +lemma UniformOnFun.toFun_mul [Mul β] (f g : α →ᵤ[𝔖] β) : + toFun 𝔖 (f * g) = toFun 𝔖 f * toFun 𝔖 g := + rfl + +@[to_additive (attr := simp)] +lemma UniformOnFun.ofFun_mul [Mul β] (f g : α → β) : ofFun 𝔖 (f * g) = ofFun 𝔖 f * ofFun 𝔖 g := rfl + +@[to_additive] instance [Inv β] : Inv (α →ᵤ β) := Pi.instInv + +@[to_additive (attr := simp)] +lemma UniformFun.toFun_inv [Inv β] (f : α →ᵤ β) : toFun (f⁻¹) = (toFun f)⁻¹ := rfl + +@[to_additive (attr := simp)] +lemma UniformFun.ofFun_inv [Inv β] (f : α → β) : ofFun (f⁻¹) = (ofFun f)⁻¹ := rfl + +@[to_additive] instance [Inv β] : Inv (α →ᵤ[𝔖] β) := Pi.instInv + +@[to_additive (attr := simp)] +lemma UniformOnFun.toFun_inv [Inv β] (f : α →ᵤ[𝔖] β) : toFun 𝔖 (f⁻¹) = (toFun 𝔖 f)⁻¹ := rfl + +@[to_additive (attr := simp)] +lemma UniformOnFun.ofFun_inv [Inv β] (f : α → β) : ofFun 𝔖 (f⁻¹) = (ofFun 𝔖 f)⁻¹ := rfl -variable {α β ι R : Type*} {𝔖 : Set <| Set α} +@[to_additive] instance [Div β] : Div (α →ᵤ β) := Pi.instDiv + +@[to_additive (attr := simp)] +lemma UniformFun.toFun_div [Div β] (f g : α →ᵤ β) : toFun (f / g) = toFun f / toFun g := rfl + +@[to_additive (attr := simp)] +lemma UniformFun.ofFun_div [Div β] (f g : α → β) : ofFun (f / g) = ofFun f / ofFun g := rfl + +@[to_additive] instance [Div β] : Div (α →ᵤ[𝔖] β) := Pi.instDiv + +@[to_additive (attr := simp)] +lemma UniformOnFun.toFun_div [Div β] (f g : α →ᵤ[𝔖] β) : + toFun 𝔖 (f / g) = toFun 𝔖 f / toFun 𝔖 g := + rfl + +@[to_additive (attr := simp)] +lemma UniformOnFun.ofFun_div [Div β] (f g : α → β) : ofFun 𝔖 (f / g) = ofFun 𝔖 f / ofFun 𝔖 g := rfl @[to_additive] instance [Monoid β] : Monoid (α →ᵤ β) := @@ -93,37 +157,63 @@ instance [CommGroup β] : CommGroup (α →ᵤ β) := instance [CommGroup β] : CommGroup (α →ᵤ[𝔖] β) := Pi.commGroup -instance [Semiring R] [AddCommMonoid β] [Module R β] : Module R (α →ᵤ β) := - Pi.module _ _ _ +instance {M : Type*} [SMul M β] : SMul M (α →ᵤ β) := Pi.instSMul -instance [Semiring R] [AddCommMonoid β] [Module R β] : Module R (α →ᵤ[𝔖] β) := - Pi.module _ _ _ +@[simp] +lemma UniformFun.toFun_smul {M : Type*} [SMul M β] (c : M) (f : α →ᵤ β) : + toFun (c • f) = c • toFun f := + rfl --- Porting note: unfortunately `simp` will no longer use `Pi.one_apply` etc. --- on `α →ᵤ β` or `α →ᵤ[𝔖] β`, so we restate some of these here. More may be needed later. -@[to_additive (attr := simp)] -lemma UniformFun.one_apply [Monoid β] : (1 : α →ᵤ β) x = 1 := Pi.one_apply x +@[simp] +lemma UniformFun.ofFun_smul {M : Type*} [SMul M β] (c : M) (f : α → β) : + ofFun (c • f) = c • ofFun f := + rfl -@[to_additive (attr := simp)] -lemma UniformOnFun.one_apply [Monoid β] : (1 : α →ᵤ[𝔖] β) x = 1 := Pi.one_apply x +instance {M : Type*} [SMul M β] : SMul M (α →ᵤ[𝔖] β) := Pi.instSMul -@[to_additive (attr := simp)] -lemma UniformFun.mul_apply [Monoid β] : (f * g : α →ᵤ β) x = f x * g x := Pi.mul_apply f g x +@[simp] +lemma UniformOnFun.toFun_smul {M : Type*} [SMul M β] (c : M) (f : α →ᵤ[𝔖] β) : + toFun 𝔖 (c • f) = c • toFun 𝔖 f := + rfl -@[to_additive (attr := simp)] -lemma UniformOnFun.mul_apply [Monoid β] : (f * g : α →ᵤ[𝔖] β) x = f x * g x := Pi.mul_apply f g x +@[simp] +lemma UniformOnFun.ofFun_smul {M : Type*} [SMul M β] (c : M) (f : α → β) : + ofFun 𝔖 (c • f) = c • ofFun 𝔖 f := + rfl -@[to_additive (attr := simp)] -lemma UniformFun.inv_apply [Group β] : (f : α →ᵤ β)⁻¹ x = (f x)⁻¹ := Pi.inv_apply f x +instance {M N : Type*} [SMul M N] [SMul M β] [SMul N β] [IsScalarTower M N β] : + IsScalarTower M N (α →ᵤ β) := + Pi.isScalarTower -@[to_additive (attr := simp)] -lemma UniformOnFun.inv_apply [Group β] : (f : α →ᵤ[𝔖] β)⁻¹ x = (f x)⁻¹ := Pi.inv_apply f x +instance {M N : Type*} [SMul M N] [SMul M β] [SMul N β] [IsScalarTower M N β] : + IsScalarTower M N (α →ᵤ[𝔖] β) := + Pi.isScalarTower -@[to_additive (attr := simp)] -lemma UniformFun.div_apply [Group β] : (f / g : α →ᵤ β) x = f x / g x := Pi.div_apply f g x +instance {M N : Type*} [SMul M β] [SMul N β] [SMulCommClass M N β] : + SMulCommClass M N (α →ᵤ β) := + Pi.smulCommClass -@[to_additive (attr := simp)] -lemma UniformOnFun.div_apply [Group β] : (f / g : α →ᵤ[𝔖] β) x = f x / g x := Pi.div_apply f g x +instance {M N : Type*} [SMul M β] [SMul N β] [SMulCommClass M N β] : + SMulCommClass M N (α →ᵤ[𝔖] β) := + Pi.smulCommClass + +instance {M : Type*} [Monoid M] [MulAction M β] : MulAction M (α →ᵤ β) := Pi.mulAction _ + +instance {M : Type*} [Monoid M] [MulAction M β] : MulAction M (α →ᵤ[𝔖] β) := Pi.mulAction _ + +instance {M : Type*} [Monoid M] [AddMonoid β] [DistribMulAction M β] : + DistribMulAction M (α →ᵤ β) := + Pi.distribMulAction _ + +instance {M : Type*} [Monoid M] [AddMonoid β] [DistribMulAction M β] : + DistribMulAction M (α →ᵤ[𝔖] β) := + Pi.distribMulAction _ + +instance [Semiring R] [AddCommMonoid β] [Module R β] : Module R (α →ᵤ β) := + Pi.module _ _ _ + +instance [Semiring R] [AddCommMonoid β] [Module R β] : Module R (α →ᵤ[𝔖] β) := + Pi.module _ _ _ end AlgebraicInstances @@ -146,12 +236,12 @@ instance : UniformGroup (α →ᵤ G) := @[to_additive] protected theorem UniformFun.hasBasis_nhds_one_of_basis {p : ι → Prop} {b : ι → Set G} (h : (𝓝 1 : Filter G).HasBasis p b) : - (𝓝 1 : Filter (α →ᵤ G)).HasBasis p fun i => { f : α →ᵤ G | ∀ x, f x ∈ b i } := by + (𝓝 1 : Filter (α →ᵤ G)).HasBasis p fun i => { f : α →ᵤ G | ∀ x, toFun f x ∈ b i } := by have := h.comap fun p : G × G => p.2 / p.1 rw [← uniformity_eq_comap_nhds_one] at this convert UniformFun.hasBasis_nhds_of_basis α _ (1 : α →ᵤ G) this -- Porting note: removed `ext i f` here, as it has already been done by `convert`. - simp [UniformFun.gen] + simp #align uniform_fun.has_basis_nhds_one_of_basis UniformFun.hasBasis_nhds_one_of_basis #align uniform_fun.has_basis_nhds_zero_of_basis UniformFun.hasBasis_nhds_zero_of_basis @@ -181,7 +271,7 @@ protected theorem UniformOnFun.hasBasis_nhds_one_of_basis (𝔖 : Set <| Set α) (h𝔖₂ : DirectedOn (· ⊆ ·) 𝔖) {p : ι → Prop} {b : ι → Set G} (h : (𝓝 1 : Filter G).HasBasis p b) : (𝓝 1 : Filter (α →ᵤ[𝔖] G)).HasBasis (fun Si : Set α × ι => Si.1 ∈ 𝔖 ∧ p Si.2) fun Si => - { f : α →ᵤ[𝔖] G | ∀ x ∈ Si.1, f x ∈ b Si.2 } := by + { f : α →ᵤ[𝔖] G | ∀ x ∈ Si.1, toFun 𝔖 f x ∈ b Si.2 } := by have := h.comap fun p : G × G => p.1 / p.2 rw [← uniformity_eq_comap_nhds_one_swapped] at this convert UniformOnFun.hasBasis_nhds_of_basis α _ 𝔖 (1 : α →ᵤ[𝔖] G) h𝔖₁ h𝔖₂ this diff --git a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean index 934011ac899ef..c5f184f3f8286 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean @@ -165,32 +165,37 @@ scoped[UniformConvergence] notation:25 α " →ᵤ[" 𝔖 "] " β:0 => UniformOn open UniformConvergence -instance {α β} [Nonempty β] : Nonempty (α →ᵤ β) := - Pi.Nonempty +variable {α β : Type*} {𝔖 : Set (Set α)} -instance {α β 𝔖} [Nonempty β] : Nonempty (α →ᵤ[𝔖] β) := - Pi.Nonempty +instance [Nonempty β] : Nonempty (α →ᵤ β) := Pi.Nonempty + +instance [Nonempty β] : Nonempty (α →ᵤ[𝔖] β) := Pi.Nonempty /-- Reinterpret `f : α → β` as an element of `α →ᵤ β`. -/ -def UniformFun.ofFun {α β} : (α → β) ≃ (α →ᵤ β) := +def UniformFun.ofFun : (α → β) ≃ (α →ᵤ β) := ⟨fun x => x, fun x => x, fun _ => rfl, fun _ => rfl⟩ #align uniform_fun.of_fun UniformFun.ofFun /-- Reinterpret `f : α → β` as an element of `α →ᵤ[𝔖] β`. -/ -def UniformOnFun.ofFun {α β} (𝔖) : (α → β) ≃ (α →ᵤ[𝔖] β) := +def UniformOnFun.ofFun (𝔖) : (α → β) ≃ (α →ᵤ[𝔖] β) := ⟨fun x => x, fun x => x, fun _ => rfl, fun _ => rfl⟩ #align uniform_on_fun.of_fun UniformOnFun.ofFun /-- Reinterpret `f : α →ᵤ β` as an element of `α → β`. -/ -def UniformFun.toFun {α β} : (α →ᵤ β) ≃ (α → β) := +def UniformFun.toFun : (α →ᵤ β) ≃ (α → β) := UniformFun.ofFun.symm #align uniform_fun.to_fun UniformFun.toFun /-- Reinterpret `f : α →ᵤ[𝔖] β` as an element of `α → β`. -/ -def UniformOnFun.toFun {α β} (𝔖) : (α →ᵤ[𝔖] β) ≃ (α → β) := +def UniformOnFun.toFun (𝔖) : (α →ᵤ[𝔖] β) ≃ (α → β) := (UniformOnFun.ofFun 𝔖).symm #align uniform_on_fun.to_fun UniformOnFun.toFun +@[simp] lemma UniformFun.toFun_ofFun (f : α → β) : toFun (ofFun f) = f := rfl +@[simp] lemma UniformFun.ofFun_toFun (f : α →ᵤ β) : ofFun (toFun f) = f := rfl +@[simp] lemma UniformOnFun.toFun_ofFun (f : α → β) : toFun 𝔖 (ofFun 𝔖 f) = f := rfl +@[simp] lemma UniformOnFun.ofFun_toFun (f : α →ᵤ[𝔖] β) : ofFun 𝔖 (toFun 𝔖 f) = f := rfl + -- Note: we don't declare a `CoeFun` instance because Lean wouldn't insert it when writing -- `f x` (because of definitional equality with `α → β`). end TypeAlias @@ -206,7 +211,7 @@ variable {s s' : Set α} {x : α} {p : Filter ι} {g : ι → α} /-- Basis sets for the uniformity of uniform convergence: `gen α β V` is the set of pairs `(f, g)` of functions `α →ᵤ β` such that `∀ x, (f x, g x) ∈ V`. -/ protected def gen (V : Set (β × β)) : Set ((α →ᵤ β) × (α →ᵤ β)) := - { uv : (α →ᵤ β) × (α →ᵤ β) | ∀ x, (uv.1 x, uv.2 x) ∈ V } + { uv : (α →ᵤ β) × (α →ᵤ β) | ∀ x, (toFun uv.1 x, toFun uv.2 x) ∈ V } #align uniform_fun.gen UniformFun.gen /-- If `𝓕` is a filter on `β × β`, then the set of all `UniformFun.gen α β V` for @@ -248,7 +253,7 @@ The exact definition of the lower adjoint `l` is not interesting; we will only u (in `UniformFun.mono` and `UniformFun.iInf_eq`) and that `l (Filter.map (Prod.map f f) 𝓕) = Filter.map (Prod.map ((∘) f) ((∘) f)) (l 𝓕)` for each `𝓕 : Filter (γ × γ)` and `f : γ → α` (in `UniformFun.comap_eq`). -/ -local notation "lower_adjoint" => fun 𝓐 => map (UniformFun.phi α β) (𝓐 ×ˢ ⊤) +local notation "lowerAdjoint" => fun 𝓐 => map (UniformFun.phi α β) (𝓐 ×ˢ ⊤) /-- The function `UniformFun.filter α β : Filter (β × β) → Filter ((α →ᵤ β) × (α →ᵤ β))` has a lower adjoint `l` (in the sense of `GaloisConnection`). The exact definition of `l` is not @@ -256,7 +261,7 @@ interesting; we will only use that it exists (in `UniformFun.mono` and `UniformFun.iInf_eq`) and that `l (Filter.map (Prod.map f f) 𝓕) = Filter.map (Prod.map ((∘) f) ((∘) f)) (l 𝓕)` for each `𝓕 : Filter (γ × γ)` and `f : γ → α` (in `UniformFun.comap_eq`). -/ -protected theorem gc : GaloisConnection lower_adjoint fun 𝓕 => UniformFun.filter α β 𝓕 := by +protected theorem gc : GaloisConnection lowerAdjoint fun 𝓕 => UniformFun.filter α β 𝓕 := by intro 𝓐 𝓕 symm calc @@ -271,7 +276,7 @@ protected theorem gc : GaloisConnection lower_adjoint fun 𝓕 => UniformFun.fil { uvx : ((α →ᵤ β) × (α →ᵤ β)) × α | (uvx.1.1 uvx.2, uvx.1.2 uvx.2) ∈ U } ∈ 𝓐 ×ˢ (⊤ : Filter α) := forall₂_congr fun U _hU => mem_prod_top.symm - _ ↔ lower_adjoint 𝓐 ≤ 𝓕 := Iff.rfl + _ ↔ lowerAdjoint 𝓐 ≤ 𝓕 := Iff.rfl #align uniform_fun.gc UniformFun.gc variable [UniformSpace β] @@ -305,7 +310,7 @@ local notation "𝒰(" α ", " β ", " u ")" => @UniformFun.uniformSpace α β u /-- By definition, the uniformity of `α →ᵤ β` admits the family `{(f, g) | ∀ x, (f x, g x) ∈ V}` for `V ∈ 𝓤 β` as a filter basis. -/ protected theorem hasBasis_uniformity : - (𝓤 (α →ᵤ β)).HasBasis (fun V => V ∈ 𝓤 β) (UniformFun.gen α β) := + (𝓤 (α →ᵤ β)).HasBasis (· ∈ 𝓤 β) (UniformFun.gen α β) := (UniformFun.isBasis_gen α β (𝓤 β)).hasBasis #align uniform_fun.has_basis_uniformity UniformFun.hasBasis_uniformity @@ -349,6 +354,11 @@ theorem uniformContinuous_eval (x : α) : variable {β} +@[simp] +protected lemma mem_gen {f g : α →ᵤ β} {V : Set (β × β)} : + (f, g) ∈ UniformFun.gen α β V ↔ ∀ x, (toFun f x, toFun g x) ∈ V := + .rfl + /-- If `u₁` and `u₂` are two uniform structures on `γ` and `u₁ ≤ u₂`, then `𝒰(α, γ, u₁) ≤ 𝒰(α, γ, u₂)`. -/ protected theorem mono : Monotone (@UniformFun.uniformSpace α γ) := fun _ _ hu => @@ -428,7 +438,7 @@ uniform convergence. More precisely, for any `f : γ → α`, the function `(· ∘ f) : (α →ᵤ β) → (γ →ᵤ β)` is uniformly continuous. -/ protected theorem precomp_uniformContinuous {f : γ → α} : - UniformContinuous fun g : α →ᵤ β => ofFun (g ∘ f) := by + UniformContinuous fun g : α →ᵤ β => ofFun (toFun g ∘ f) := by -- Here we simply go back to filter bases. rw [uniformContinuous_iff] change @@ -440,18 +450,12 @@ protected theorem precomp_uniformContinuous {f : γ → α} : /-- Turn a bijection `γ ≃ α` into a uniform isomorphism `(γ →ᵤ β) ≃ᵤ (α →ᵤ β)` by pre-composing. -/ -protected def congrLeft (e : γ ≃ α) : (γ →ᵤ β) ≃ᵤ (α →ᵤ β) := - { Equiv.arrowCongr e (Equiv.refl _) with - uniformContinuous_toFun := UniformFun.precomp_uniformContinuous - uniformContinuous_invFun := UniformFun.precomp_uniformContinuous } +protected def congrLeft (e : γ ≃ α) : (γ →ᵤ β) ≃ᵤ (α →ᵤ β) where + toEquiv := e.arrowCongr (.refl _) + uniformContinuous_toFun := UniformFun.precomp_uniformContinuous + uniformContinuous_invFun := UniformFun.precomp_uniformContinuous #align uniform_fun.congr_left UniformFun.congrLeft -/-- The topology of uniform convergence is T₂. -/ -instance [T2Space β] : T2Space (α →ᵤ β) where - t2 f g h := by - obtain ⟨x, hx⟩ := not_forall.mp (mt funext h) - exact separated_by_continuous (uniformContinuous_eval β x).continuous hx - /-- The natural map `UniformFun.toFun` from `α →ᵤ β` to `α → β` is uniformly continuous. In other words, the uniform structure of uniform convergence is finer than that of pointwise @@ -463,12 +467,16 @@ protected theorem uniformContinuous_toFun : UniformContinuous (toFun : (α → exact uniformContinuous_eval β x #align uniform_fun.uniform_continuous_to_fun UniformFun.uniformContinuous_toFun +/-- The topology of uniform convergence is T₂. -/ +instance [T2Space β] : T2Space (α →ᵤ β) := + .of_injective_continuous toFun.injective UniformFun.uniformContinuous_toFun.continuous + /-- The topology of uniform convergence indeed gives the same notion of convergence as `TendstoUniformly`. -/ protected theorem tendsto_iff_tendstoUniformly {F : ι → α →ᵤ β} {f : α →ᵤ β} : - Tendsto F p (𝓝 f) ↔ TendstoUniformly F f p := by + Tendsto F p (𝓝 f) ↔ TendstoUniformly (toFun ∘ F) (toFun f) p := by rw [(UniformFun.hasBasis_nhds α β f).tendsto_right_iff, TendstoUniformly] - simp only [mem_setOf, UniformFun.gen] + simp only [mem_setOf, UniformFun.gen, Function.comp_def] #align uniform_fun.tendsto_iff_tendsto_uniformly UniformFun.tendsto_iff_tendstoUniformly /-- The natural bijection between `α → β × γ` and `(α → β) × (α → γ)`, upgraded to a uniform @@ -479,7 +487,7 @@ protected def uniformEquivProdArrow [UniformSpace γ] : (α →ᵤ β × γ) ≃ -- But `uβ × uγ` is defined as `comap fst uβ ⊓ comap snd uγ`, so we just have to apply -- `UniformFun.inf_eq` and `UniformFun.comap_eq`, which leaves us to check -- that some square commutes. - Equiv.toUniformEquivOfUniformInducing (Equiv.arrowProdEquivProdArrow _ _ _) $ by + Equiv.toUniformEquivOfUniformInducing (Equiv.arrowProdEquivProdArrow _ _ _) <| by constructor change comap (Prod.map (Equiv.arrowProdEquivProdArrow _ _ _) (Equiv.arrowProdEquivProdArrow _ _ _)) @@ -537,7 +545,7 @@ local notation "𝒰(" α ", " β ", " u ")" => @UniformFun.uniformSpace α β u `∀ x ∈ S, (f x, g x) ∈ V`. Note that the family `𝔖 : Set (Set α)` is only used to specify which type alias of `α → β` to use here. -/ protected def gen (𝔖) (S : Set α) (V : Set (β × β)) : Set ((α →ᵤ[𝔖] β) × (α →ᵤ[𝔖] β)) := - { uv : (α →ᵤ[𝔖] β) × (α →ᵤ[𝔖] β) | ∀ x ∈ S, (uv.1 x, uv.2 x) ∈ V } + { uv : (α →ᵤ[𝔖] β) × (α →ᵤ[𝔖] β) | ∀ x ∈ S, (toFun 𝔖 uv.1 x, toFun 𝔖 uv.2 x) ∈ V } #align uniform_on_fun.gen UniformOnFun.gen /-- For `S : Set α` and `V : Set (β × β)`, we have @@ -596,8 +604,8 @@ of `S.restrict : (α →ᵤ[𝔖] β) → (↥S →ᵤ β)` of restriction to `S the topology of uniform convergence. -/ protected theorem topologicalSpace_eq : UniformOnFun.topologicalSpace α β 𝔖 = - ⨅ (s : Set α) (_ : s ∈ 𝔖), TopologicalSpace.induced (s.restrict ∘ UniformFun.toFun) - (UniformFun.topologicalSpace s β) := by + ⨅ (s : Set α) (_ : s ∈ 𝔖), TopologicalSpace.induced + (UniformFun.ofFun ∘ s.restrict ∘ toFun 𝔖) (UniformFun.topologicalSpace s β) := by simp only [UniformOnFun.topologicalSpace, UniformSpace.toTopologicalSpace_iInf] rfl #align uniform_on_fun.topological_space_eq UniformOnFun.topologicalSpace_eq @@ -829,7 +837,7 @@ protected theorem uniformContinuous_toFun (h : ⋃₀ 𝔖 = univ) : /-- Convergence in the topology of `𝔖`-convergence means uniform convergence on `S` (in the sense of `TendstoUniformlyOn`) for all `S ∈ 𝔖`. -/ protected theorem tendsto_iff_tendstoUniformlyOn {F : ι → α →ᵤ[𝔖] β} {f : α →ᵤ[𝔖] β} : - Tendsto F p (𝓝 f) ↔ ∀ s ∈ 𝔖, TendstoUniformlyOn F f p s := by + Tendsto F p (𝓝 f) ↔ ∀ s ∈ 𝔖, TendstoUniformlyOn (toFun 𝔖 ∘ F) (toFun 𝔖 f) p s := by rw [UniformOnFun.topologicalSpace_eq, nhds_iInf, tendsto_iInf] refine' forall_congr' fun s => _ rw [nhds_iInf, tendsto_iInf] From 979574679a2cd5e540a7bdb2dd5c8d0752ffc87a Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 21 Dec 2023 04:20:55 +0000 Subject: [PATCH 104/353] chore: bump Std to leanprover/std4#277 (#9172) Co-authored-by: Scott Morrison --- Mathlib/Data/List/Basic.lean | 21 ---------- Mathlib/Data/List/Zip.lean | 78 ------------------------------------ lake-manifest.json | 2 +- 3 files changed, 1 insertion(+), 100 deletions(-) diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index 3e7ff55772748..46f67f53d9fc1 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -2106,31 +2106,10 @@ theorem cons_nthLe_drop_succ {l : List α} {n : ℕ} (hn : n < l.length) : #align list.cons_nth_le_drop_succ List.cons_nthLe_drop_succ #align list.drop_nil List.drop_nil - -@[simp] -theorem drop_one : ∀ l : List α, drop 1 l = tail l - | [] | _ :: _ => rfl #align list.drop_one List.drop_one - -theorem drop_add : ∀ (m n) (l : List α), drop (m + n) l = drop m (drop n l) - | _, 0, _ => rfl - | _, _ + 1, [] => drop_nil.symm - | m, n + 1, _ :: _ => drop_add m n _ #align list.drop_add List.drop_add - -@[simp] -theorem drop_left : ∀ l₁ l₂ : List α, drop (length l₁) (l₁ ++ l₂) = l₂ - | [], _ => rfl - | _ :: l₁, l₂ => drop_left l₁ l₂ #align list.drop_left List.drop_left - -theorem drop_left' {l₁ l₂ : List α} {n} (h : length l₁ = n) : drop n (l₁ ++ l₂) = l₂ := by - rw [← h]; apply drop_left #align list.drop_left' List.drop_left' - -theorem drop_eq_get_cons : ∀ {n} {l : List α} (h), drop n l = get l ⟨n, h⟩ :: drop (n + 1) l - | 0, _ :: _, _ => rfl - | n + 1, _ :: _, _ => @drop_eq_get_cons n _ _ #align list.drop_eq_nth_le_cons List.drop_eq_get_consₓ -- nth_le vs get #align list.drop_length List.drop_length diff --git a/Mathlib/Data/List/Zip.lean b/Mathlib/Data/List/Zip.lean index 09deeb716d8f5..dba949738c56a 100644 --- a/Mathlib/Data/List/Zip.lean +++ b/Mathlib/Data/List/Zip.lean @@ -34,12 +34,7 @@ variable {α : Type u} {β γ δ ε : Type*} #align list.zip_cons_cons List.zip_cons_cons #align list.zip_with_nil_left List.zipWith_nil_left #align list.zip_with_nil_right List.zipWith_nil_right - -@[simp] -theorem zipWith_eq_nil_iff {f : α → β → γ} {l l'} : zipWith f l l' = [] ↔ l = [] ∨ l' = [] := by - cases l <;> cases l' <;> simp #align list.zip_with_eq_nil_iff List.zipWith_eq_nil_iff - #align list.zip_nil_left List.zip_nil_left #align list.zip_nil_right List.zip_nil_right @@ -86,35 +81,14 @@ theorem lt_length_right_of_zip {i : ℕ} {l : List α} {l' : List β} (h : i < ( lt_length_right_of_zipWith h #align list.lt_length_right_of_zip List.lt_length_right_of_zip -theorem zip_append : - ∀ {l₁ r₁ : List α} {l₂ r₂ : List β} (_h : length l₁ = length l₂), - zip (l₁ ++ r₁) (l₂ ++ r₂) = zip l₁ l₂ ++ zip r₁ r₂ - | [], r₁, l₂, r₂, h => by simp only [eq_nil_of_length_eq_zero h.symm]; rfl - | l₁, r₁, [], r₂, h => by simp only [eq_nil_of_length_eq_zero h]; rfl - | a :: l₁, r₁, b :: l₂, r₂, h => by - simp only [cons_append, zip_cons_cons, zip_append (succ.inj h)] #align list.zip_append List.zip_append - #align list.zip_map List.zip_map #align list.zip_map_left List.zip_map_left #align list.zip_map_right List.zip_map_right #align list.zip_with_map List.zipWith_map #align list.zip_with_map_left List.zipWith_map_left #align list.zip_with_map_right List.zipWith_map_right - -theorem zip_map' (f : α → β) (g : α → γ) : - ∀ l : List α, zip (l.map f) (l.map g) = l.map fun a => (f a, g a) - | [] => rfl - | a :: l => by simp only [map, zip_cons_cons, zip_map'] #align list.zip_map' List.zip_map' - -theorem map_zipWith {δ : Type*} (f : α → β) (g : γ → δ → α) (l : List γ) (l' : List δ) : - map f (zipWith g l l') = zipWith (fun x y => f (g x y)) l l' := by - induction' l with hd tl hl generalizing l' - · simp - · cases l' - · simp - · simp [hl] #align list.map_zip_with List.map_zipWith theorem mem_zip {a b} : ∀ {l₁ : List α} {l₂ : List β}, (a, b) ∈ zip l₁ l₂ → a ∈ l₁ ∧ b ∈ l₂ @@ -125,30 +99,9 @@ theorem mem_zip {a b} : ∀ {l₁ : List α} {l₂ : List β}, (a, b) ∈ zip l exact ⟨Mem.tail _ this.1, Mem.tail _ this.2⟩ #align list.mem_zip List.mem_zip -theorem map_fst_zip : - ∀ (l₁ : List α) (l₂ : List β), l₁.length ≤ l₂.length → map Prod.fst (zip l₁ l₂) = l₁ - | [], bs, _ => rfl - | _ :: as, _ :: bs, h => by - simp? [succ_le_succ_iff] at h says simp only [length_cons, succ_le_succ_iff] at h - change _ :: map Prod.fst (zip as bs) = _ :: as - rw [map_fst_zip as bs h] - | a :: as, [], h => by simp at h #align list.map_fst_zip List.map_fst_zip - -theorem map_snd_zip : - ∀ (l₁ : List α) (l₂ : List β), l₂.length ≤ l₁.length → map Prod.snd (zip l₁ l₂) = l₂ - | _, [], _ => by - rw [zip_nil_right] - rfl - | [], b :: bs, h => by simp at h - | a :: as, b :: bs, h => by - simp? [succ_le_succ_iff] at h says simp only [length_cons, succ_le_succ_iff] at h - change _ :: map Prod.snd (zip as bs) = _ :: bs - rw [map_snd_zip as bs h] #align list.map_snd_zip List.map_snd_zip - #align list.unzip_nil List.unzip_nil - #align list.unzip_cons List.unzip_cons theorem unzip_eq_map : ∀ l : List (α × β), unzip l = (l.map Prod.fst, l.map Prod.snd) @@ -413,40 +366,9 @@ section Distrib variable (f : α → β → γ) (l : List α) (l' : List β) (n : ℕ) -theorem zipWith_distrib_take : (zipWith f l l').take n = zipWith f (l.take n) (l'.take n) := by - induction' l with hd tl hl generalizing l' n - · simp - · cases l' - · simp - · cases n - · simp - · simp [hl] #align list.zip_with_distrib_take List.zipWith_distrib_take - -theorem zipWith_distrib_drop : (zipWith f l l').drop n = zipWith f (l.drop n) (l'.drop n) := by - induction' l with hd tl hl generalizing l' n - · simp - · cases l' - · simp - · cases n - · simp - · simp [hl] #align list.zip_with_distrib_drop List.zipWith_distrib_drop - -theorem zipWith_distrib_tail : (zipWith f l l').tail = zipWith f l.tail l'.tail := by - simp_rw [← drop_one, zipWith_distrib_drop] #align list.zip_with_distrib_tail List.zipWith_distrib_tail - -theorem zipWith_append (f : α → β → γ) (l la : List α) (l' lb : List β) - (h : l.length = l'.length) : - zipWith f (l ++ la) (l' ++ lb) = zipWith f l l' ++ zipWith f la lb := by - induction' l with hd tl hl generalizing l' - · have : l' = [] := eq_nil_of_length_eq_zero (by simpa using h.symm) - simp [this] - · cases l' - · simp at h - · simp only [add_left_inj, length] at h - simp [hl _ h] #align list.zip_with_append List.zipWith_append theorem zipWith_distrib_reverse (h : l.length = l'.length) : diff --git a/lake-manifest.json b/lake-manifest.json index 2a1a96e4db936..543fe5d5d97ea 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "71e11a6be0e43dabcba416e1af15b5bbbbfc9dde", + "rev": "cdc1e3de736cef839a003c9e509fdeb21d602e39", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", From b5787177720048590b1114b2643661e1c2ddb9c1 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 21 Dec 2023 18:10:11 +1100 Subject: [PATCH 105/353] bump std --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index fa9c8e2a37858..c469f1966ca80 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "f6dd208c78ee34449a029951d16a8fd161959385", + "rev": "c9f4e961a72fef4fd0d038b7c6d33848bcd1caad", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "nightly-testing", From e352bb79f198b8bf40d2e471d40fd81198ded2bc Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 21 Dec 2023 07:24:09 +0000 Subject: [PATCH 106/353] chore: bump Std to leanprover/std4#463 (#9175) Co-authored-by: Scott Morrison --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index 543fe5d5d97ea..a50b5b4603b15 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "cdc1e3de736cef839a003c9e509fdeb21d602e39", + "rev": "5bf9172331fb4de21647a919c64d3569839b63c6", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", From 0f61adf9110971622f041a027c59fe4a1061e2df Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 21 Dec 2023 19:20:40 +1100 Subject: [PATCH 107/353] bump toolchain --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 2b934e4208fd3..ab0fdcb8b0063 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-20 +leanprover/lean4:nightly-2023-12-21 From 4cf009544549e218641180e9d1ea8d220a71476e Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Thu, 21 Dec 2023 08:37:10 +0000 Subject: [PATCH 108/353] feat(Topology/Compact): an infinite set has an accumulation point (#9173) Add more versions of this statement. Also remove `simp` from `Filter.disjoint_cofinite_{left,right}` as RHS is not much simpler than LHS. --- Mathlib/Order/Filter/Cofinite.lean | 28 ++++++++++++++----- Mathlib/Topology/Compactness/Compact.lean | 33 ++++++++++++++++------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/Mathlib/Order/Filter/Cofinite.lean b/Mathlib/Order/Filter/Cofinite.lean index 5654ad5b45923..2275cbf66e058 100644 --- a/Mathlib/Order/Filter/Cofinite.lean +++ b/Mathlib/Order/Filter/Cofinite.lean @@ -65,10 +65,20 @@ theorem cofinite_eq_bot [Finite α] : @cofinite α = ⊥ := cofinite_eq_bot_iff. theorem frequently_cofinite_iff_infinite {p : α → Prop} : (∃ᶠ x in cofinite, p x) ↔ Set.Infinite { x | p x } := by - simp only [Filter.Frequently, Filter.Eventually, mem_cofinite, compl_setOf, not_not, - Set.Infinite] + simp only [Filter.Frequently, eventually_cofinite, not_not, Set.Infinite] #align filter.frequently_cofinite_iff_infinite Filter.frequently_cofinite_iff_infinite +lemma frequently_cofinite_mem_iff_infinite {s : Set α} : (∃ᶠ x in cofinite, x ∈ s) ↔ s.Infinite := + frequently_cofinite_iff_infinite + +alias ⟨_, _root_.Set.Infinite.frequently_cofinite⟩ := frequently_cofinite_mem_iff_infinite + +@[simp] +lemma cofinite_inf_principal_neBot_iff {s : Set α} : (cofinite ⊓ 𝓟 s).NeBot ↔ s.Infinite := + frequently_mem_iff_neBot.symm.trans frequently_cofinite_mem_iff_infinite + +alias ⟨_, _root_.Set.Infinite.cofinite_inf_principal_neBot⟩ := cofinite_inf_principal_neBot_iff + theorem _root_.Set.Finite.compl_mem_cofinite {s : Set α} (hs : s.Finite) : sᶜ ∈ @cofinite α := mem_cofinite.2 <| (compl_compl s).symm ▸ hs #align set.finite.compl_mem_cofinite Set.Finite.compl_mem_cofinite @@ -124,14 +134,10 @@ theorem coprodᵢ_cofinite {α : ι → Type*} [Finite ι] : set_option linter.uppercaseLean3 false in #align filter.Coprod_cofinite Filter.coprodᵢ_cofinite -@[simp] theorem disjoint_cofinite_left : Disjoint cofinite l ↔ ∃ s ∈ l, Set.Finite s := by - simp only [hasBasis_cofinite.disjoint_iff l.basis_sets, id, disjoint_compl_left_iff_subset] - exact ⟨fun ⟨s, hs, t, ht, hts⟩ => ⟨t, ht, hs.subset hts⟩, - fun ⟨s, hs, hsf⟩ => ⟨s, hsf, s, hs, Subset.rfl⟩⟩ + simp [l.basis_sets.disjoint_iff_right] #align filter.disjoint_cofinite_left Filter.disjoint_cofinite_left -@[simp] theorem disjoint_cofinite_right : Disjoint l cofinite ↔ ∃ s ∈ l, Set.Finite s := disjoint_comm.trans disjoint_cofinite_left #align filter.disjoint_cofinite_right Filter.disjoint_cofinite_right @@ -152,6 +158,14 @@ end Filter open Filter +lemma Set.Finite.cofinite_inf_principal_compl {s : Set α} (hs : s.Finite) : + cofinite ⊓ 𝓟 sᶜ = cofinite := by + simpa using hs.compl_mem_cofinite + +lemma Set.Finite.cofinite_inf_principal_diff {s t : Set α} (ht : t.Finite) : + cofinite ⊓ 𝓟 (s \ t) = cofinite ⊓ 𝓟 s := by + rw [diff_eq, ← inf_principal, ← inf_assoc, inf_right_comm, ht.cofinite_inf_principal_compl] + /-- For natural numbers the filters `Filter.cofinite` and `Filter.atTop` coincide. -/ theorem Nat.cofinite_eq_atTop : @cofinite ℕ = atTop := by refine' le_antisymm _ atTop_le_cofinite diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index 5bcdfe33ff9af..821878173534c 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.lean @@ -796,12 +796,29 @@ theorem finite_of_compact_of_discrete [CompactSpace X] [DiscreteTopology X] : Fi Finite.of_finite_univ <| isCompact_univ.finite_of_discrete #align finite_of_compact_of_discrete finite_of_compact_of_discrete +lemma Set.Infinite.exists_accPt_cofinite_inf_principal_of_subset_isCompact + {K : Set X} (hs : s.Infinite) (hK : IsCompact K) (hsub : s ⊆ K) : + ∃ x ∈ K, AccPt x (cofinite ⊓ 𝓟 s) := + (@hK _ hs.cofinite_inf_principal_neBot (inf_le_right.trans <| principal_mono.2 hsub)).imp + fun x hx ↦ by rwa [acc_iff_cluster, inf_comm, inf_right_comm, + (finite_singleton _).cofinite_inf_principal_compl] + +lemma Set.Infinite.exists_accPt_of_subset_isCompact {K : Set X} (hs : s.Infinite) + (hK : IsCompact K) (hsub : s ⊆ K) : ∃ x ∈ K, AccPt x (𝓟 s) := + let ⟨x, hxK, hx⟩ := hs.exists_accPt_cofinite_inf_principal_of_subset_isCompact hK hsub + ⟨x, hxK, hx.mono inf_le_right⟩ + +lemma Set.Infinite.exists_accPt_cofinite_inf_principal [CompactSpace X] (hs : s.Infinite) : + ∃ x, AccPt x (cofinite ⊓ 𝓟 s) := by + simpa only [mem_univ, true_and] + using hs.exists_accPt_cofinite_inf_principal_of_subset_isCompact isCompact_univ s.subset_univ + +lemma Set.Infinite.exists_accPt_principal [CompactSpace X] (hs : s.Infinite) : ∃ x, AccPt x (𝓟 s) := + hs.exists_accPt_cofinite_inf_principal.imp fun _x hx ↦ hx.mono inf_le_right + theorem exists_nhds_ne_neBot (X : Type*) [TopologicalSpace X] [CompactSpace X] [Infinite X] : - ∃ x : X, (𝓝[≠] x).NeBot := by - by_contra! H - simp_rw [not_neBot] at H - haveI := discreteTopology_iff_nhds_ne.2 H - exact Infinite.not_finite (finite_of_compact_of_discrete : Finite X) + ∃ z : X, (𝓝[≠] z).NeBot := by + simpa [AccPt] using (@infinite_univ X _).exists_accPt_principal #align exists_nhds_ne_ne_bot exists_nhds_ne_neBot theorem finite_cover_nhds_interior [CompactSpace X] {U : X → Set X} (hU : ∀ x, U x ∈ 𝓝 x) : @@ -937,10 +954,8 @@ theorem IsCompact.finite (hs : IsCompact s) (hs' : DiscreteTopology s) : s.Finit #align is_compact.finite IsCompact.finite theorem exists_nhds_ne_inf_principal_neBot (hs : IsCompact s) (hs' : s.Infinite) : - ∃ x ∈ s, (𝓝[≠] x ⊓ 𝓟 s).NeBot := by - by_contra! H - simp_rw [not_neBot] at H - exact hs' (hs.finite <| discreteTopology_subtype_iff.mpr H) + ∃ z ∈ s, (𝓝[≠] z ⊓ 𝓟 s).NeBot := + hs'.exists_accPt_of_subset_isCompact hs Subset.rfl #align exists_nhds_ne_inf_principal_ne_bot exists_nhds_ne_inf_principal_neBot protected theorem ClosedEmbedding.noncompactSpace [NoncompactSpace X] {f : X → Y} From e7c657f3b4b6f175895c3c1143a5275d24ba418c Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Thu, 21 Dec 2023 09:38:26 +0000 Subject: [PATCH 109/353] chore(Perm/Basic): golf (#9174) Golf 3 proofs --- Mathlib/GroupTheory/Perm/Basic.lean | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/Mathlib/GroupTheory/Perm/Basic.lean b/Mathlib/GroupTheory/Perm/Basic.lean index d36e7691affe9..52537e2fe1920 100644 --- a/Mathlib/GroupTheory/Perm/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Basic.lean @@ -570,30 +570,18 @@ theorem swap_eq_one_iff {i j : α} : swap i j = (1 : Perm α) ↔ i = j := swap_eq_refl_iff #align equiv.swap_eq_one_iff Equiv.swap_eq_one_iff -theorem swap_mul_eq_iff {i j : α} {σ : Perm α} : swap i j * σ = σ ↔ i = j := - ⟨fun h => by - -- Porting note: added `_root_.` - have swap_id : swap i j = 1 := mul_right_cancel (_root_.trans h (one_mul σ).symm) - rw [← swap_apply_right i j, swap_id] - rfl, - fun h => by erw [h, swap_self, one_mul]⟩ +theorem swap_mul_eq_iff {i j : α} {σ : Perm α} : swap i j * σ = σ ↔ i = j := by + rw [mul_left_eq_self, swap_eq_one_iff] #align equiv.swap_mul_eq_iff Equiv.swap_mul_eq_iff -theorem mul_swap_eq_iff {i j : α} {σ : Perm α} : σ * swap i j = σ ↔ i = j := - ⟨fun h => by - -- Porting note: added `_root_.` - have swap_id : swap i j = 1 := mul_left_cancel (_root_.trans h (one_mul σ).symm) - rw [← swap_apply_right i j, swap_id] - rfl, - fun h => by erw [h, swap_self, mul_one]⟩ +theorem mul_swap_eq_iff {i j : α} {σ : Perm α} : σ * swap i j = σ ↔ i = j := by + rw [mul_right_eq_self, swap_eq_one_iff] #align equiv.mul_swap_eq_iff Equiv.mul_swap_eq_iff -theorem swap_mul_swap_mul_swap {x y z : α} (hwz : x ≠ y) (hxz : x ≠ z) : - swap y z * swap x y * swap y z = swap z x := - Equiv.ext fun n => by - simp only [swap_apply_def, Perm.mul_apply] - -- Porting note: was `cc` - split_ifs <;> aesop +theorem swap_mul_swap_mul_swap {x y z : α} (hxy : x ≠ y) (hxz : x ≠ z) : + swap y z * swap x y * swap y z = swap z x := by + nth_rewrite 2 [← swap_inv] + rw [← swap_apply_apply, swap_apply_left, swap_apply_of_ne_of_ne hxy hxz, swap_comm] #align equiv.swap_mul_swap_mul_swap Equiv.swap_mul_swap_mul_swap end Swap From c0d0c1418a22171af1a376f31f4cf9447b274c0a Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 21 Dec 2023 22:21:44 +1100 Subject: [PATCH 110/353] merge lean-pr-testing-2964 --- Mathlib/Tactic/Widget/Calc.lean | 2 +- Mathlib/Tactic/Widget/Congrm.lean | 3 ++- Mathlib/Tactic/Widget/Conv.lean | 3 ++- Mathlib/Tactic/Widget/Gcongr.lean | 3 ++- lake-manifest.json | 6 +++--- lakefile.lean | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Mathlib/Tactic/Widget/Calc.lean b/Mathlib/Tactic/Widget/Calc.lean index 634be8df3c637..0e2a1c8d4b2cf 100644 --- a/Mathlib/Tactic/Widget/Calc.lean +++ b/Mathlib/Tactic/Widget/Calc.lean @@ -137,6 +137,6 @@ elab_rules : tactic let json := open scoped Std.Json in json% {"replaceRange": $(replaceRange), "isFirst": $(isFirst), "indent": $(indent)} - ProofWidgets.savePanelWidgetInfo proofTerm `CalcPanel (pure json) + Widget.savePanelWidgetInfo CalcPanel.javascriptHash (pure json) proofTerm isFirst := false evalCalc (← `(tactic|calc%$calcstx $stx)) diff --git a/Mathlib/Tactic/Widget/Congrm.lean b/Mathlib/Tactic/Widget/Congrm.lean index abf8365734b0f..9095c828b36ae 100644 --- a/Mathlib/Tactic/Widget/Congrm.lean +++ b/Mathlib/Tactic/Widget/Congrm.lean @@ -51,4 +51,5 @@ open scoped Json in subexpressions in the goal.-/ elab stx:"congrm?" : tactic => do let some replaceRange := (← getFileMap).rangeOfStx? stx | return - savePanelWidgetInfo stx ``CongrmSelectionPanel $ pure $ json% { replaceRange: $(replaceRange) } + Widget.savePanelWidgetInfo CongrmSelectionPanel.javascriptHash + (pure $ json% { replaceRange: $(replaceRange) }) stx diff --git a/Mathlib/Tactic/Widget/Conv.lean b/Mathlib/Tactic/Widget/Conv.lean index aa268c2bdcdf2..aabc847b6ac06 100644 --- a/Mathlib/Tactic/Widget/Conv.lean +++ b/Mathlib/Tactic/Widget/Conv.lean @@ -133,4 +133,5 @@ open scoped Json in in the goal.-/ elab stx:"conv?" : tactic => do let some replaceRange := (← getFileMap).rangeOfStx? stx | return - savePanelWidgetInfo stx ``ConvSelectionPanel $ pure $ json% { replaceRange: $(replaceRange) } + Widget.savePanelWidgetInfo ConvSelectionPanel.javascriptHash + (pure $ json% { replaceRange: $(replaceRange) }) stx diff --git a/Mathlib/Tactic/Widget/Gcongr.lean b/Mathlib/Tactic/Widget/Gcongr.lean index df7ce0c32a9c9..f4fb3cc4788f6 100644 --- a/Mathlib/Tactic/Widget/Gcongr.lean +++ b/Mathlib/Tactic/Widget/Gcongr.lean @@ -49,4 +49,5 @@ open scoped Json in subexpressions in the goal.-/ elab stx:"gcongr?" : tactic => do let some replaceRange := (← getFileMap).rangeOfStx? stx | return - savePanelWidgetInfo stx ``GCongrSelectionPanel $ pure $ json% { replaceRange: $(replaceRange) } + Widget.savePanelWidgetInfo GCongrSelectionPanel.javascriptHash + (pure $ json% { replaceRange: $(replaceRange) }) stx diff --git a/lake-manifest.json b/lake-manifest.json index c469f1966ca80..b5fa37304a995 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "c9f4e961a72fef4fd0d038b7c6d33848bcd1caad", + "rev": "dddfaf4346e3355a5ca9119fabda05b47eefe8f5", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "nightly-testing", @@ -31,10 +31,10 @@ {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, - "rev": "909febc72b4f64628f8d35cd0554f8a90b6e0749", + "rev": "bf61e90de075abfa27f638922e7aafafdce77c44", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.23", + "inputRev": "v0.0.24-pre2", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover/lean4-cli", diff --git a/lakefile.lean b/lakefile.lean index 735fa58298481..29d557badf7f5 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -29,7 +29,7 @@ require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" require std from git "https://github.com/leanprover/std4" @ "nightly-testing" require Qq from git "https://github.com/leanprover-community/quote4" @ "master" require aesop from git "https://github.com/leanprover-community/aesop" @ "master" -require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.23" +require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.24-pre2" require Cli from git "https://github.com/leanprover/lean4-cli" @ "main" /-! From 7ab29418357366001b8ecc5679c730d32698fc1b Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Thu, 21 Dec 2023 15:05:02 +0000 Subject: [PATCH 111/353] feat(Order/RelIso): define missing instances (#9170) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define `EmbeddingLike (r ↪r s) α β` and `EquivLike (r ≃r s) α β`. --- Mathlib/Order/RelIso/Basic.lean | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Mathlib/Order/RelIso/Basic.lean b/Mathlib/Order/RelIso/Basic.lean index d28b054b1e351..ed1445b4c1519 100644 --- a/Mathlib/Order/RelIso/Basic.lean +++ b/Mathlib/Order/RelIso/Basic.lean @@ -230,7 +230,7 @@ instance : Coe (r ↪r s) (r →r s) := -- instance : CoeFun (r ↪r s) fun _ => α → β := -- ⟨fun o => o.toEmbedding⟩ --- TODO: define and instantiate a `RelEmbeddingClass` when `EmbeddingLike` is defined +-- TODO: define and instantiate a `RelEmbeddingClass` instance : RelHomClass (r ↪r s) r s where coe := fun x => x.toFun coe_injective' f g h := by @@ -239,15 +239,11 @@ instance : RelHomClass (r ↪r s) r s where congr map_rel f a b := Iff.mpr (map_rel_iff' f) - -/-- See Note [custom simps projection]. We specify this explicitly because we have a coercion not -given by the `FunLike` instance. Todo: remove that instance? --/ -def Simps.apply (h : r ↪r s) : α → β := - h - initialize_simps_projections RelEmbedding (toFun → apply) +instance : EmbeddingLike (r ↪r s) α β where + injective' f := f.inj' + @[simp] theorem coe_toEmbedding : ((f : r ↪r s).toEmbedding : α → β) = f := rfl @@ -261,7 +257,7 @@ theorem injective (f : r ↪r s) : Injective f := f.inj' #align rel_embedding.injective RelEmbedding.injective -@[simp] theorem inj (f : r ↪r s) {a b} : f a = f b ↔ a = b := f.injective.eq_iff +theorem inj (f : r ↪r s) {a b} : f a = f b ↔ a = b := f.injective.eq_iff #align rel_embedding.inj RelEmbedding.inj theorem map_rel_iff (f : r ↪r s) {a b} : s (f a) (f b) ↔ r a b := @@ -638,12 +634,19 @@ instance : CoeOut (r ≃r s) (r ↪r s) := -- instance : CoeFun (r ≃r s) fun _ => α → β := -- ⟨fun f => f⟩ --- TODO: define and instantiate a `RelIsoClass` when `EquivLike` is defined +-- TODO: define and instantiate a `RelIsoClass` instance : RelHomClass (r ≃r s) r s where coe := fun x => x coe_injective' := Equiv.coe_fn_injective.comp toEquiv_injective map_rel f _ _ := Iff.mpr (map_rel_iff' f) +instance : EquivLike (r ≃r s) α β where + coe f := f + inv f := f.toEquiv.symm + left_inv f := f.left_inv + right_inv f := f.right_inv + coe_injective' _ _ hf _ := FunLike.ext' hf + --Porting note: helper instance -- see Note [function coercion] instance : CoeFun (r ≃r s) fun _ => α → β := From 850c6404726dcb10ca053c6080be7e8368093523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Thu, 21 Dec 2023 16:16:26 +0000 Subject: [PATCH 112/353] refactor: use the new homology API for the four and the five lemmas (#9022) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR refactors the four and the five lemmas so as to use the new homology API. The files `Algebra.Homology.ShortExact.Abelian` and `Algebra.Homology.ShortExact.Preadditive` are also removed because the content of these files has become redundant with the new homology API. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- Mathlib.lean | 2 - .../Category/ModuleCat/Biproducts.lean | 22 +- Mathlib/Algebra/Category/ModuleCat/Free.lean | 174 +++++---- Mathlib/Algebra/Homology/ExactSequence.lean | 22 +- .../Algebra/Homology/ShortExact/Abelian.lean | 93 ----- .../Homology/ShortExact/Preadditive.lean | 332 ------------------ .../Abelian/DiagramLemmas/Four.lean | 283 ++++++--------- Mathlib/CategoryTheory/ComposableArrows.lean | 15 + .../Topology/Category/Profinite/Nobeling.lean | 18 +- 9 files changed, 251 insertions(+), 710 deletions(-) delete mode 100644 Mathlib/Algebra/Homology/ShortExact/Abelian.lean delete mode 100644 Mathlib/Algebra/Homology/ShortExact/Preadditive.lean diff --git a/Mathlib.lean b/Mathlib.lean index b907ebbf3fcd7..5c18650f47447 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -267,8 +267,6 @@ import Mathlib.Algebra.Homology.ShortComplex.QuasiIso import Mathlib.Algebra.Homology.ShortComplex.RightHomology import Mathlib.Algebra.Homology.ShortComplex.ShortExact import Mathlib.Algebra.Homology.ShortComplex.SnakeLemma -import Mathlib.Algebra.Homology.ShortExact.Abelian -import Mathlib.Algebra.Homology.ShortExact.Preadditive import Mathlib.Algebra.Homology.Single import Mathlib.Algebra.Homology.SingleHomology import Mathlib.Algebra.Invertible.Basic diff --git a/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean b/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean index 75d0a330ccd8a..65ad14c580895 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean @@ -6,7 +6,7 @@ Authors: Scott Morrison import Mathlib.Algebra.Group.Pi import Mathlib.CategoryTheory.Limits.Shapes.Biproducts import Mathlib.Algebra.Category.ModuleCat.Abelian -import Mathlib.Algebra.Homology.ShortExact.Abelian +import Mathlib.Algebra.Homology.ShortComplex.ModuleCat #align_import algebra.category.Module.biproducts from "leanprover-community/mathlib"@"f0c8bf9245297a541f468be517f1bde6195105e9" @@ -161,24 +161,26 @@ variable {j : A →ₗ[R] M} {g : M →ₗ[R] B} open ModuleCat + /-- The isomorphism `A × B ≃ₗ[R] M` coming from a right split exact sequence `0 ⟶ A ⟶ M ⟶ B ⟶ 0` of modules.-/ noncomputable def lequivProdOfRightSplitExact {f : B →ₗ[R] M} (hj : Function.Injective j) (exac : LinearMap.range j = LinearMap.ker g) (h : g.comp f = LinearMap.id) : (A × B) ≃ₗ[R] M := - (({ right_split := ⟨ModuleCat.asHom f, h⟩ - mono := (ModuleCat.mono_iff_injective <| asHom j).mpr hj - exact := (exact_iff _ _).mpr exac } : RightSplit _ _).splitting.iso.trans <| - biprodIsoProd _ _).toLinearEquiv.symm -#align lequiv_prod_of_right_split_exact lequivProdOfRightSplitExact + ((ShortComplex.Splitting.ofExactOfSection _ + (ShortComplex.Exact.moduleCat_of_range_eq_ker (ModuleCat.ofHom j) + (ModuleCat.ofHom g) exac) (asHom f) h + (by simpa only [ModuleCat.mono_iff_injective])).isoBinaryBiproduct ≪≫ + biprodIsoProd _ _ ).symm.toLinearEquiv /-- The isomorphism `A × B ≃ₗ[R] M` coming from a left split exact sequence `0 ⟶ A ⟶ M ⟶ B ⟶ 0` of modules.-/ noncomputable def lequivProdOfLeftSplitExact {f : M →ₗ[R] A} (hg : Function.Surjective g) (exac : LinearMap.range j = LinearMap.ker g) (h : f.comp j = LinearMap.id) : (A × B) ≃ₗ[R] M := - (({ left_split := ⟨ModuleCat.asHom f, h⟩ - epi := (ModuleCat.epi_iff_surjective <| asHom g).mpr hg - exact := (exact_iff _ _).mpr exac } : LeftSplit _ _).splitting.iso.trans <| - biprodIsoProd _ _).toLinearEquiv.symm + ((ShortComplex.Splitting.ofExactOfRetraction _ + (ShortComplex.Exact.moduleCat_of_range_eq_ker (ModuleCat.ofHom j) + (ModuleCat.ofHom g) exac) (ModuleCat.ofHom f) h + (by simpa only [ModuleCat.epi_iff_surjective] using hg)).isoBinaryBiproduct ≪≫ + biprodIsoProd _ _).symm.toLinearEquiv #align lequiv_prod_of_left_split_exact lequivProdOfLeftSplitExact end SplitExact diff --git a/Mathlib/Algebra/Category/ModuleCat/Free.lean b/Mathlib/Algebra/Category/ModuleCat/Free.lean index ade8d87225c2f..8c7e71bae019f 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Free.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Free.lean @@ -5,7 +5,7 @@ Authors: Dagur Asgeirsson -/ import Mathlib.Algebra.Category.ModuleCat.Abelian import Mathlib.Algebra.Category.ModuleCat.Adjunctions -import Mathlib.Algebra.Homology.ShortExact.Preadditive +import Mathlib.Algebra.Homology.ShortComplex.ModuleCat import Mathlib.LinearAlgebra.FreeModule.Basic import Mathlib.LinearAlgebra.FreeModule.Finite.Rank import Mathlib.LinearAlgebra.Dimension @@ -18,13 +18,13 @@ This file proves results about linear independence and span in exact sequences o ## Main theorems -* `linearIndependent_shortExact`: Given a short exact sequence `0 ⟶ N ⟶ M ⟶ P ⟶ 0` of - `R`-modules and linearly independent families `v : ι → N` and `w : ι' → M`, we get a linearly - independent family `ι ⊕ ι' → M` -* `span_rightExact`: Given an exact sequence `N ⟶ M ⟶ P ⟶ 0` of `R`-modules and spanning - families `v : ι → N` and `w : ι' → M`, we get a spanning family `ι ⊕ ι' → M` +* `linearIndependent_shortExact`: Given a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` of + `R`-modules and linearly independent families `v : ι → X₁` and `w : ι' → X₃`, we get a linearly + independent family `ι ⊕ ι' → X₂` +* `span_rightExact`: Given an exact sequence `X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` of `R`-modules and spanning + families `v : ι → X₁` and `w : ι' → X₃`, we get a spanning family `ι ⊕ ι' → X₂` * Using `linearIndependent_shortExact` and `span_rightExact`, we prove `free_shortExact`: In a - short exact sequence `0 ⟶ N ⟶ M ⟶ P ⟶ 0` where `N` and `P` are free, `M` is free as well. + short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` where `X₁` and `X₃` are free, `X₂` is free as well. ## Tags linear algebra, module, free @@ -33,97 +33,96 @@ linear algebra, module, free set_option autoImplicit true +open CategoryTheory + namespace ModuleCat -variable {ι ι' R : Type*}[Ring R] {N P : ModuleCat R} {v : ι → N} +variable {ι ι' R : Type*} [Ring R] {S : ShortComplex (ModuleCat R)} + (hS : S.Exact) (hS' : S.ShortExact) {v : ι → S.X₁} open CategoryTheory Submodule Set section LinearIndependent -variable (hv : LinearIndependent R v) {M : ModuleCat R} - {u : ι ⊕ ι' → M} {f : N ⟶ M} {g : M ⟶ P} - (hw : LinearIndependent R (g ∘ u ∘ Sum.inr)) - (hm : Mono f) (he : Exact f g) (huv : u ∘ Sum.inl = f ∘ v) +variable (hv : LinearIndependent R v) {u : ι ⊕ ι' → S.X₂} + (hw : LinearIndependent R (S.g ∘ u ∘ Sum.inr)) + (hm : Mono S.f) (huv : u ∘ Sum.inl = S.f ∘ v) theorem disjoint_span_sum : Disjoint (span R (range (u ∘ Sum.inl))) (span R (range (u ∘ Sum.inr))) := by rw [huv, disjoint_comm] refine' Disjoint.mono_right (span_mono (range_comp_subset_range _ _)) _ - rw [← LinearMap.range_coe, (span_eq (LinearMap.range f)), (exact_iff _ _).mp he] + rw [← LinearMap.range_coe, (span_eq (LinearMap.range S.f)), hS.moduleCat_range_eq_ker] exact range_ker_disjoint hw /-- In the commutative diagram ``` f g - 0 --→ N --→ M --→ P - ↑ ↑ ↑ - v| u| w| - ι → ι ⊕ ι' ← ι' + 0 --→ X₁ --→ X₂ --→ X₃ + ↑ ↑ ↑ + v| u| w| + ι → ι ⊕ ι' ← ι' ``` where the top row is an exact sequence of modules and the maps on the bottom are `Sum.inl` and `Sum.inr`. If `u` is injective and `v` and `w` are linearly independent, then `u` is linearly independent. -/ -theorem linearIndependent_leftExact : LinearIndependent R u := - linearIndependent_sum.mpr - ⟨(congr_arg (fun f ↦ LinearIndependent R f) huv).mpr - ((LinearMap.linearIndependent_iff (f : N →ₗ[R] M) - (LinearMap.ker_eq_bot.mpr ((mono_iff_injective _).mp hm))).mpr hv), - LinearIndependent.of_comp g hw, disjoint_span_sum hw he huv⟩ - -/-- Given a short exact sequence `0 ⟶ N ⟶ M ⟶ P ⟶ 0` of `R`-modules and linearly independent +theorem linearIndependent_leftExact : LinearIndependent R u := by + rw [linearIndependent_sum] + refine' ⟨_, LinearIndependent.of_comp S.g hw, disjoint_span_sum hS hw huv⟩ + rw [huv, LinearMap.linearIndependent_iff S.f]; swap + · rw [LinearMap.ker_eq_bot, ← mono_iff_injective] + infer_instance + exact hv + +/-- Given a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` of `R`-modules and linearly independent families `v : ι → N` and `w : ι' → P`, we get a linearly independent family `ι ⊕ ι' → M` -/ -theorem linearIndependent_shortExact {w : ι' → P} - (hw : LinearIndependent R w) (hse : ShortExact f g) : - LinearIndependent R (Sum.elim (f ∘ v) (g.toFun.invFun ∘ w)) := by - refine' linearIndependent_leftExact hv _ hse.mono hse.exact _ - · simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, Sum.elim_comp_inr] - rwa [← Function.comp.assoc, Function.RightInverse.comp_eq_id (Function.rightInverse_invFun - ((epi_iff_surjective _).mp hse.epi)), - Function.comp.left_id] - · simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, Sum.elim_comp_inl] +theorem linearIndependent_shortExact {w : ι' → S.X₃} (hw : LinearIndependent R w) : + LinearIndependent R (Sum.elim (S.f ∘ v) (S.g.toFun.invFun ∘ w)) := by + apply linearIndependent_leftExact hS'.exact hv _ hS'.mono_f rfl + dsimp + convert hw + ext + apply Function.rightInverse_invFun ((epi_iff_surjective _).mp hS'.epi_g) end LinearIndependent section Span -variable {M : ModuleCat R} {u : ι⊕ ι' → M} {f : N ⟶ M} {g : M ⟶ P} /-- In the commutative diagram ``` f g - N --→ M --→ P - ↑ ↑ ↑ -v| u| w| - ι → ι ⊕ ι' ← ι' + X₁ --→ X₂ --→ X₃ + ↑ ↑ ↑ +v| u| w| + ι → ι ⊕ ι' ← ι' ``` where the top row is an exact sequence of modules and the maps on the bottom are `Sum.inl` and -`Sum.inr`. If `v` spans `N` and `w` spans `P`, then `u` spans `M`. -/ -theorem span_exact (he : Exact f g) (huv : u ∘ Sum.inl = f ∘ v) +`Sum.inr`. If `v` spans `X₁` and `w` spans `X₃`, then `u` spans `X₂`. -/ +theorem span_exact (huv : u ∘ Sum.inl = S.f ∘ v) (hv : ⊤ ≤ span R (range v)) - (hw : ⊤ ≤ span R (range (g ∘ u ∘ Sum.inr))) : + (hw : ⊤ ≤ span R (range (S.g ∘ u ∘ Sum.inr))) : ⊤ ≤ span R (range u) := by intro m _ - have hgm : g m ∈ span R (range (g ∘ u ∘ Sum.inr)) := hw mem_top + have hgm : S.g m ∈ span R (range (S.g ∘ u ∘ Sum.inr)) := hw mem_top rw [Finsupp.mem_span_range_iff_exists_finsupp] at hgm obtain ⟨cm, hm⟩ := hgm - let m' : M := Finsupp.sum cm fun j a ↦ a • (u (Sum.inr j)) - have hsub : m - m' ∈ LinearMap.range f - · rw [(exact_iff _ _).mp he] + let m' : S.X₂ := Finsupp.sum cm fun j a ↦ a • (u (Sum.inr j)) + have hsub : m - m' ∈ LinearMap.range S.f + · rw [hS.moduleCat_range_eq_ker] simp only [LinearMap.mem_ker, map_sub, sub_eq_zero] rw [← hm, map_finsupp_sum] - simp only [Function.comp_apply, map_smul] + simp only [Function.comp_apply, SMulHomClass.map_smul] obtain ⟨n, hnm⟩ := hsub have hn : n ∈ span R (range v) := hv mem_top rw [Finsupp.mem_span_range_iff_exists_finsupp] at hn obtain ⟨cn, hn⟩ := hn rw [← hn, map_finsupp_sum] at hnm rw [← sub_add_cancel m m', ← hnm,] - simp only [map_smul] - have hn' : (Finsupp.sum cn fun a b ↦ b • f (v a)) = - (Finsupp.sum cn fun a b ↦ b • u (Sum.inl a)) := by - congr with a b - rw [← Function.comp_apply (f := f) (g := v), ← huv, Function.comp_apply] + simp only [SMulHomClass.map_smul] + have hn' : (Finsupp.sum cn fun a b ↦ b • S.f (v a)) = + (Finsupp.sum cn fun a b ↦ b • u (Sum.inl a)) := + by congr; ext a b; change b • (S.f ∘ v) a = _; rw [← huv]; rfl rw [hn'] apply add_mem · rw [Finsupp.mem_span_range_iff_exists_finsupp] @@ -133,12 +132,12 @@ theorem span_exact (he : Exact f g) (huv : u ∘ Sum.inl = f ∘ v) use cm.mapDomain (Sum.inr) rw [Finsupp.sum_mapDomain_index_inj Sum.inr_injective] -/-- Given an exact sequence `N ⟶ M ⟶ P ⟶ 0` of `R`-modules and spanning - families `v : ι → N` and `w : ι' → P`, we get a spanning family `ι ⊕ ι' → M` -/ -theorem span_rightExact {w : ι' → P} (hv : ⊤ ≤ span R (range v)) - (hw : ⊤ ≤ span R (range w)) (hE : Epi g) (he : Exact f g) : - ⊤ ≤ span R (range (Sum.elim (f ∘ v) (g.toFun.invFun ∘ w))) := by - refine' span_exact he _ hv _ +/-- Given an exact sequence `X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` of `R`-modules and spanning + families `v : ι → X₁` and `w : ι' → X₃`, we get a spanning family `ι ⊕ ι' → X₂` -/ +theorem span_rightExact {w : ι' → S.X₃} (hv : ⊤ ≤ span R (range v)) + (hw : ⊤ ≤ span R (range w)) (hE : Epi S.g) : + ⊤ ≤ span R (range (Sum.elim (S.f ∘ v) (S.g.toFun.invFun ∘ w))) := by + refine' span_exact hS _ hv _ · simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, Sum.elim_comp_inl] · convert hw simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, Sum.elim_comp_inr] @@ -148,39 +147,38 @@ theorem span_rightExact {w : ι' → P} (hv : ⊤ ≤ span R (range v)) end Span -/-- In a short exact sequence `0 ⟶ N ⟶ M ⟶ P ⟶ 0`, given bases for `N` and `P` indexed by `ι` and - `ι'` respectively, we get a basis for `M` indexed by `ι ⊕ ι'`. -/ +/-- In a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0`, given bases for `X₁` and `X₃` +indexed by `ι` and `ι'` respectively, we get a basis for `X₂` indexed by `ι ⊕ ι'`. -/ noncomputable -def Basis.ofShortExact {M : ModuleCat R} {f : N ⟶ M} {g : M ⟶ P} (h : ShortExact f g) - (bN : Basis ι R N) (bP : Basis ι' R P) : Basis (ι ⊕ ι') R M := - Basis.mk (linearIndependent_shortExact bN.linearIndependent bP.linearIndependent h) - (span_rightExact (le_of_eq (bN.span_eq.symm)) (le_of_eq (bP.span_eq.symm)) h.epi h.exact) - -/-- In a short exact sequence `0 ⟶ N ⟶ M ⟶ P ⟶ 0`, if `N` and `P` are free, then `M` is free.-/ -theorem free_shortExact {M : ModuleCat R} {f : N ⟶ M} - {g : M ⟶ P} (h : ShortExact f g) [Module.Free R N] [Module.Free R P] : - Module.Free R M := - Module.Free.of_basis (Basis.ofShortExact h (Module.Free.chooseBasis R N) - (Module.Free.chooseBasis R P)) - -theorem free_shortExact_rank_add {M : ModuleCat R} {f : N ⟶ M} - {g : M ⟶ P} (h : ShortExact f g) [Module.Free R N] [Module.Free R P] [StrongRankCondition R] : - Module.rank R M = Module.rank R N + Module.rank R P := by - haveI := free_shortExact h - rw [Module.Free.rank_eq_card_chooseBasisIndex, Module.Free.rank_eq_card_chooseBasisIndex R N, - Module.Free.rank_eq_card_chooseBasisIndex R P, Cardinal.add_def, Cardinal.eq] - exact ⟨Basis.indexEquiv (Module.Free.chooseBasis R M) (Basis.ofShortExact h - (Module.Free.chooseBasis R N) (Module.Free.chooseBasis R P))⟩ - -theorem free_shortExact_finrank_add {M : ModuleCat R} {f : N ⟶ M} - {g : M ⟶ P} (h : ShortExact f g) [Module.Free R N] [Module.Finite R N] - [Module.Free R P] [Module.Finite R P] - (hN : FiniteDimensional.finrank R N = n) - (hP : FiniteDimensional.finrank R P = p) +def Basis.ofShortExact + (bN : Basis ι R S.X₁) (bP : Basis ι' R S.X₃) : Basis (ι ⊕ ι') R S.X₂ := + Basis.mk (linearIndependent_shortExact hS' bN.linearIndependent bP.linearIndependent) + (span_rightExact hS'.exact (le_of_eq (bN.span_eq.symm)) (le_of_eq (bP.span_eq.symm)) hS'.epi_g) + +/-- In a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0`, if `X₁` and `X₃` are free, +then `X₂` is free.-/ +theorem free_shortExact [Module.Free R S.X₁] [Module.Free R S.X₃] : + Module.Free R S.X₂ := + Module.Free.of_basis (Basis.ofShortExact hS' (Module.Free.chooseBasis R S.X₁) + (Module.Free.chooseBasis R S.X₃)) + +theorem free_shortExact_rank_add [Module.Free R S.X₁] [Module.Free R S.X₃] + [StrongRankCondition R] : + Module.rank R S.X₂ = Module.rank R S.X₁ + Module.rank R S.X₃ := by + haveI := free_shortExact hS' + rw [Module.Free.rank_eq_card_chooseBasisIndex, Module.Free.rank_eq_card_chooseBasisIndex R S.X₁, + Module.Free.rank_eq_card_chooseBasisIndex R S.X₃, Cardinal.add_def, Cardinal.eq] + exact ⟨Basis.indexEquiv (Module.Free.chooseBasis R S.X₂) (Basis.ofShortExact hS' + (Module.Free.chooseBasis R S.X₁) (Module.Free.chooseBasis R S.X₃))⟩ + +theorem free_shortExact_finrank_add [Module.Free R S.X₁] [Module.Free R S.X₃] + [Module.Finite R S.X₁] [Module.Finite R S.X₃] + (hN : FiniteDimensional.finrank R S.X₁ = n) + (hP : FiniteDimensional.finrank R S.X₃ = p) [StrongRankCondition R] : - FiniteDimensional.finrank R M = n + p := by + FiniteDimensional.finrank R S.X₂ = n + p := by apply FiniteDimensional.finrank_eq_of_rank_eq - rw [free_shortExact_rank_add h, ← hN, ← hP] + rw [free_shortExact_rank_add hS', ← hN, ← hP] simp only [Nat.cast_add, FiniteDimensional.finrank_eq_rank] end ModuleCat diff --git a/Mathlib/Algebra/Homology/ExactSequence.lean b/Mathlib/Algebra/Homology/ExactSequence.lean index 5061b0fd0d976..e650d84e71005 100644 --- a/Mathlib/Algebra/Homology/ExactSequence.lean +++ b/Mathlib/Algebra/Homology/ExactSequence.lean @@ -100,7 +100,7 @@ structure Exact extends S.IsComplex : Prop where variable {S} -lemma IsExact.exact' (hS : S.Exact) (i j k : ℕ) (hij : i + 1 = j := by linarith) +lemma Exact.exact' (hS : S.Exact) (i j k : ℕ) (hij : i + 1 = j := by linarith) (hjk : j + 1 = k := by linarith) (hk : k ≤ n := by linarith) : (S.sc' hS.toIsComplex i j k).Exact := by subst hij hjk @@ -237,6 +237,26 @@ lemma exact_of_δ₀ {S : ComposableArrows C (n + 2)} rw [exact_iff_δ₀] constructor <;> assumption +lemma exact_iff_δlast {n : ℕ} (S : ComposableArrows C (n + 2)) : + S.Exact ↔ S.δlast.Exact ∧ (mk₂ (S.map' n (n + 1)) (S.map' (n + 1) (n + 2))).Exact := by + constructor + · intro h + constructor + · exact Exact.mk (IsComplex.mk (fun i hi => h.toIsComplex.zero i)) + (fun i hi => h.exact i) + · rw [exact₂_iff]; swap + · rw [isComplex₂_iff] + exact h.toIsComplex.zero n + exact h.exact n (by linarith) + · rintro ⟨h, h'⟩ + refine' Exact.mk (IsComplex.mk (fun i hi => _)) (fun i hi => _) + · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith) + · exact h.toIsComplex.zero i + · exact h'.toIsComplex.zero 0 + · obtain hi | rfl := LE.le.lt_or_eq (show i ≤ n by linarith) + · exact h.exact i + · exact h'.exact 0 + end ComposableArrows end CategoryTheory diff --git a/Mathlib/Algebra/Homology/ShortExact/Abelian.lean b/Mathlib/Algebra/Homology/ShortExact/Abelian.lean deleted file mode 100644 index d42dc461b74cb..0000000000000 --- a/Mathlib/Algebra/Homology/ShortExact/Abelian.lean +++ /dev/null @@ -1,93 +0,0 @@ -/- -Copyright (c) 2021 Johan Commelin. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Johan Commelin, Andrew Yang, Pierre-Alexandre Bazin --/ -import Mathlib.Algebra.Homology.ShortExact.Preadditive -import Mathlib.CategoryTheory.Abelian.DiagramLemmas.Four - -#align_import algebra.homology.short_exact.abelian from "leanprover-community/mathlib"@"356447fe00e75e54777321045cdff7c9ea212e60" - -/-! -# Short exact sequences in abelian categories - -In an abelian category, a left-split or right-split short exact sequence admits a splitting. --/ - - -noncomputable section - -open CategoryTheory CategoryTheory.Limits CategoryTheory.Preadditive - -variable {𝒜 : Type*} [Category 𝒜] - -namespace CategoryTheory - -variable {A B C A' B' C' : 𝒜} {f : A ⟶ B} {g : B ⟶ C} {f' : A' ⟶ B'} {g' : B' ⟶ C'} - -variable [Abelian 𝒜] - -open ZeroObject - -theorem isIso_of_shortExact_of_isIso_of_isIso (h : ShortExact f g) (h' : ShortExact f' g') - (i₁ : A ⟶ A') (i₂ : B ⟶ B') (i₃ : C ⟶ C') - (comm₁ : i₁ ≫ f' = f ≫ i₂ := by aesop_cat) - (comm₂ : i₂ ≫ g' = g ≫ i₃ := by aesop_cat) [IsIso i₁] [IsIso i₃] : IsIso i₂ := by - obtain ⟨_⟩ := h - obtain ⟨_⟩ := h' - refine @Abelian.isIso_of_epi_of_isIso_of_isIso_of_mono 𝒜 _ _ 0 _ _ _ 0 _ _ _ 0 f g 0 f' g' - 0 i₁ i₂ i₃ ?_ comm₁ comm₂ 0 0 0 0 0 ?_ ?_ ?_ ?_ ?_ ?_ ?_ _ _ _ _ - all_goals try simp - all_goals try assumption - all_goals try apply exact_zero_left_of_mono - all_goals rwa [← epi_iff_exact_zero_right ] -#align category_theory.is_iso_of_short_exact_of_is_iso_of_is_iso CategoryTheory.isIso_of_shortExact_of_isIso_of_isIso - -/-- To construct a splitting of `A -f⟶ B -g⟶ C` it suffices to supply -a *morphism* `i : B ⟶ A ⊞ C` such that `f ≫ i` is the canonical map `biprod.inl : A ⟶ A ⊞ C` and -`i ≫ q = g`, where `q` is the canonical map `biprod.snd : A ⊞ C ⟶ C`, -together with proofs that `f` is mono and `g` is epi. - -The morphism `i` is then automatically an isomorphism. -/ -def Splitting.mk' (h : ShortExact f g) (i : B ⟶ A ⊞ C) (h1 : f ≫ i = biprod.inl) - (h2 : i ≫ biprod.snd = g) : Splitting f g := - have : IsIso i := isIso_of_shortExact_of_isIso_of_isIso h ⟨exact_inl_snd A C⟩ (𝟙 _) i (𝟙 _) - { iso := asIso i - comp_iso_eq_inl := h1 - iso_comp_snd_eq := h2 } -#align category_theory.splitting.mk' CategoryTheory.Splitting.mk' - -/-- To construct a splitting of `A -f⟶ B -g⟶ C` it suffices to supply -a *morphism* `i : A ⊞ C ⟶ B` such that `p ≫ i = f` where `p` is the canonical map -`biprod.inl : A ⟶ A ⊞ C`, and `i ≫ g` is the canonical map `biprod.snd : A ⊞ C ⟶ C`, -together with proofs that `f` is mono and `g` is epi. - -The morphism `i` is then automatically an isomorphism. -/ -def Splitting.mk'' (h : ShortExact f g) (i : A ⊞ C ⟶ B) (h1 : biprod.inl ≫ i = f) - (h2 : i ≫ g = biprod.snd) : Splitting f g := - have : IsIso i := isIso_of_shortExact_of_isIso_of_isIso ⟨exact_inl_snd A C⟩ h (𝟙 _) i (𝟙 _) - { iso := (asIso i).symm - comp_iso_eq_inl := by rw [Iso.symm_hom, asIso_inv, IsIso.comp_inv_eq, h1] - iso_comp_snd_eq := by rw [Iso.symm_hom, asIso_inv, IsIso.inv_comp_eq, h2] } -#align category_theory.splitting.mk'' CategoryTheory.Splitting.mk'' - -/-- A short exact sequence that is left split admits a splitting. -/ -def LeftSplit.splitting {f : A ⟶ B} {g : B ⟶ C} (h : LeftSplit f g) : Splitting f g := - Splitting.mk' h.shortExact (biprod.lift h.left_split.choose g) - (by - ext - · simpa only [biprod.inl_fst, biprod.lift_fst, Category.assoc] using h.left_split.choose_spec - · simp only [biprod.inl_snd, biprod.lift_snd, Category.assoc, h.exact.w]) - (by simp only [biprod.lift_snd]) -#align category_theory.left_split.splitting CategoryTheory.LeftSplit.splitting - -/-- A short exact sequence that is right split admits a splitting. -/ -def RightSplit.splitting {f : A ⟶ B} {g : B ⟶ C} (h : RightSplit f g) : Splitting f g := - Splitting.mk'' h.shortExact (biprod.desc f h.right_split.choose) (biprod.inl_desc _ _) - (by - ext - · rw [biprod.inl_snd, ← Category.assoc, biprod.inl_desc, h.exact.w] - · rw [biprod.inr_snd, ← Category.assoc, biprod.inr_desc, h.right_split.choose_spec]) -#align category_theory.right_split.splitting CategoryTheory.RightSplit.splitting - -end CategoryTheory diff --git a/Mathlib/Algebra/Homology/ShortExact/Preadditive.lean b/Mathlib/Algebra/Homology/ShortExact/Preadditive.lean deleted file mode 100644 index 418e43bf81f0e..0000000000000 --- a/Mathlib/Algebra/Homology/ShortExact/Preadditive.lean +++ /dev/null @@ -1,332 +0,0 @@ -/- -Copyright (c) 2021 Johan Commelin. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Johan Commelin, Andrew Yang --/ -import Mathlib.Algebra.Homology.Exact -import Mathlib.CategoryTheory.Preadditive.AdditiveFunctor - -#align_import algebra.homology.short_exact.preadditive from "leanprover-community/mathlib"@"14b69e9f3c16630440a2cbd46f1ddad0d561dee7" - -/-! -# Short exact sequences, and splittings. - -`CategoryTheory.ShortExact f g` is the proposition that `0 ⟶ A -f⟶ B -g⟶ C ⟶ 0` is an exact -sequence. - -We define when a short exact sequence is left-split, right-split, and split. - -## See also - -In `Mathlib.Algebra.Homology.ShortExact.Abelian` we show that in an abelian category a left-split -short exact sequences admits a splitting. - --/ - - -noncomputable section - -open CategoryTheory CategoryTheory.Limits CategoryTheory.Preadditive - -variable {𝒜 : Type*} [Category 𝒜] - -namespace CategoryTheory - -variable {A B C A' B' C' : 𝒜} (f : A ⟶ B) (g : B ⟶ C) (f' : A' ⟶ B') (g' : B' ⟶ C') - -section HasZeroMorphisms - -variable [HasZeroMorphisms 𝒜] [HasKernels 𝒜] [HasImages 𝒜] - -/-- If `f : A ⟶ B` and `g : B ⟶ C` then `short_exact f g` is the proposition saying - the resulting diagram `0 ⟶ A ⟶ B ⟶ C ⟶ 0` is an exact sequence. -/ -structure ShortExact : Prop where - [mono : Mono f] - [epi : Epi g] - exact : Exact f g -#align category_theory.short_exact CategoryTheory.ShortExact - -/-- An exact sequence `A -f⟶ B -g⟶ C` is *left split* -if there exists a morphism `φ : B ⟶ A` such that `f ≫ φ = 𝟙 A` and `g` is epi. - -Such a sequence is automatically short exact (i.e., `f` is mono). -/ -structure LeftSplit : Prop where - left_split : ∃ φ : B ⟶ A, f ≫ φ = 𝟙 A - [epi : Epi g] - exact : Exact f g -#align category_theory.left_split CategoryTheory.LeftSplit - -theorem LeftSplit.shortExact {f : A ⟶ B} {g : B ⟶ C} (h : LeftSplit f g) : ShortExact f g where - mono := let ⟨_φ, hφ⟩ := h.left_split; mono_of_mono_fac hφ - __ := h -#align category_theory.left_split.short_exact CategoryTheory.LeftSplit.shortExact - -/-- An exact sequence `A -f⟶ B -g⟶ C` is *right split* -if there exists a morphism `φ : C ⟶ B` such that `f ≫ φ = 𝟙 A` and `f` is mono. - -Such a sequence is automatically short exact (i.e., `g` is epi). -/ -structure RightSplit : Prop where - right_split : ∃ χ : C ⟶ B, χ ≫ g = 𝟙 C - [mono : Mono f] - exact : Exact f g -#align category_theory.right_split CategoryTheory.RightSplit - -theorem RightSplit.shortExact {f : A ⟶ B} {g : B ⟶ C} (h : RightSplit f g) : ShortExact f g where - epi := let ⟨_χ, hχ⟩ := h.right_split; epi_of_epi_fac hχ - __ := h -#align category_theory.right_split.short_exact CategoryTheory.RightSplit.shortExact - -end HasZeroMorphisms - -section Preadditive - -variable [Preadditive 𝒜] - -/-- An exact sequence `A -f⟶ B -g⟶ C` is *split* if there exist -`φ : B ⟶ A` and `χ : C ⟶ B` such that: -* `f ≫ φ = 𝟙 A` -* `χ ≫ g = 𝟙 C` -* `f ≫ g = 0` -* `χ ≫ φ = 0` -* `φ ≫ f + g ≫ χ = 𝟙 B` - -Such a sequence is automatically short exact (i.e., `f` is mono and `g` is epi). -/ -structure Split : Prop where - split : ∃ (φ : B ⟶ A) (χ : C ⟶ B), - f ≫ φ = 𝟙 A ∧ χ ≫ g = 𝟙 C ∧ f ≫ g = 0 ∧ χ ≫ φ = 0 ∧ φ ≫ f + g ≫ χ = 𝟙 B -#align category_theory.split CategoryTheory.Split - -variable [HasKernels 𝒜] [HasImages 𝒜] - -theorem exact_of_split {A B C : 𝒜} {f : A ⟶ B} {g : B ⟶ C} {χ : C ⟶ B} {φ : B ⟶ A} (hfg : f ≫ g = 0) - (H : φ ≫ f + g ≫ χ = 𝟙 B) : Exact f g where - w := hfg - epi := by - set ψ : (kernelSubobject g : 𝒜) ⟶ imageSubobject f := - Subobject.arrow _ ≫ φ ≫ factorThruImageSubobject f - suffices : ψ ≫ imageToKernel f g hfg = 𝟙 _ - · exact epi_of_epi_fac this - rw [← cancel_mono (Subobject.arrow _)] - simp only [imageToKernel_arrow, imageSubobject_arrow_comp, Category.id_comp, Category.assoc] - calc - (kernelSubobject g).arrow ≫ φ ≫ f = (kernelSubobject g).arrow ≫ 𝟙 B := by - rw [← H, Preadditive.comp_add] - simp only [add_zero, zero_comp, kernelSubobject_arrow_comp_assoc] - _ = (kernelSubobject g).arrow := Category.comp_id _ -#align category_theory.exact_of_split CategoryTheory.exact_of_split - -section - -variable {f g} - -theorem Split.exact (h : Split f g) : Exact f g := by - obtain ⟨φ, χ, -, -, h1, -, h2⟩ := h - exact exact_of_split h1 h2 -#align category_theory.split.exact CategoryTheory.Split.exact - -theorem Split.leftSplit (h : Split f g) : LeftSplit f g where - left_split := let ⟨φ, _χ, h1, _⟩ := h; ⟨φ, h1⟩ - epi := let ⟨_φ, _χ, _, h2, _⟩ := h; epi_of_epi_fac h2 - exact := h.exact -#align category_theory.split.left_split CategoryTheory.Split.leftSplit - -theorem Split.rightSplit (h : Split f g) : RightSplit f g where - right_split := let ⟨_φ, χ, _, h1, _⟩ := h; ⟨χ, h1⟩ - mono := let ⟨_φ, _χ, h1, _⟩ := h; mono_of_mono_fac h1 - exact := h.exact -#align category_theory.split.right_split CategoryTheory.Split.rightSplit - -theorem Split.shortExact (h : Split f g) : ShortExact f g := - h.leftSplit.shortExact -#align category_theory.split.short_exact CategoryTheory.Split.shortExact - -end - -theorem Split.map {𝒜 ℬ : Type*} [Category 𝒜] [Preadditive 𝒜] [Category ℬ] [Preadditive ℬ] - (F : 𝒜 ⥤ ℬ) [Functor.Additive F] {A B C : 𝒜} {f : A ⟶ B} {g : B ⟶ C} (h : Split f g) : - Split (F.map f) (F.map g) := by - obtain ⟨φ, χ, h1, h2, h3, h4, h5⟩ := h - refine ⟨⟨F.map φ, F.map χ, ?_⟩⟩ - simp only [← F.map_comp, ← F.map_id] - rw [← F.map_add] -- porting note: `simp only` fails to use this lemma - simp only [F.map_zero, *, true_and] -#align category_theory.split.map CategoryTheory.Split.map - -/-- The sequence `A ⟶ A ⊞ B ⟶ B` is exact. -/ -theorem exact_inl_snd [HasBinaryBiproducts 𝒜] (A B : 𝒜) : - Exact (biprod.inl : A ⟶ A ⊞ B) biprod.snd := - exact_of_split biprod.inl_snd biprod.total -#align category_theory.exact_inl_snd CategoryTheory.exact_inl_snd - -/-- The sequence `B ⟶ A ⊞ B ⟶ A` is exact. -/ -theorem exact_inr_fst [HasBinaryBiproducts 𝒜] (A B : 𝒜) : - Exact (biprod.inr : B ⟶ A ⊞ B) biprod.fst := - exact_of_split biprod.inr_fst ((add_comm _ _).trans biprod.total) -#align category_theory.exact_inr_fst CategoryTheory.exact_inr_fst - -end Preadditive - -/-- A *splitting* of a sequence `A -f⟶ B -g⟶ C` is an isomorphism -to the short exact sequence `0 ⟶ A ⟶ A ⊞ C ⟶ C ⟶ 0` such that -the vertical maps on the left and the right are the identity. -/ --- porting note: was @[nolint has_nonempty_instance] -structure Splitting [HasZeroMorphisms 𝒜] [HasBinaryBiproducts 𝒜] where - iso : B ≅ A ⊞ C - comp_iso_eq_inl : f ≫ iso.hom = biprod.inl - iso_comp_snd_eq : iso.hom ≫ biprod.snd = g -#align category_theory.splitting CategoryTheory.Splitting - -variable {f g} - -namespace Splitting - -section HasZeroMorphisms - -variable [HasZeroMorphisms 𝒜] [HasBinaryBiproducts 𝒜] - -attribute [reassoc (attr := simp)] comp_iso_eq_inl iso_comp_snd_eq - -variable (h : Splitting f g) - -@[reassoc (attr := simp)] -theorem inl_comp_iso_eq : biprod.inl ≫ h.iso.inv = f := by rw [Iso.comp_inv_eq, h.comp_iso_eq_inl] -#align category_theory.splitting.inl_comp_iso_eq CategoryTheory.Splitting.inl_comp_iso_eq - -@[reassoc (attr := simp)] -theorem iso_comp_eq_snd : h.iso.inv ≫ g = biprod.snd := by rw [Iso.inv_comp_eq, h.iso_comp_snd_eq] -#align category_theory.splitting.iso_comp_eq_snd CategoryTheory.Splitting.iso_comp_eq_snd - -/-- If `h` is a splitting of `A -f⟶ B -g⟶ C`, -then `h.section : C ⟶ B` is the morphism satisfying `h.section ≫ g = 𝟙 C`. -/ -def «section» : C ⟶ B := biprod.inr ≫ h.iso.inv -#align category_theory.splitting.section CategoryTheory.Splitting.section - -/-- If `h` is a splitting of `A -f⟶ B -g⟶ C`, -then `h.retraction : B ⟶ A` is the morphism satisfying `f ≫ h.retraction = 𝟙 A`. -/ -def retraction : B ⟶ A := h.iso.hom ≫ biprod.fst -#align category_theory.splitting.retraction CategoryTheory.Splitting.retraction - -@[reassoc (attr := simp)] -theorem section_π : h.section ≫ g = 𝟙 C := by simp [Splitting.section] -#align category_theory.splitting.section_π CategoryTheory.Splitting.section_π - -@[reassoc (attr := simp)] -theorem ι_retraction : f ≫ h.retraction = 𝟙 A := by simp [retraction] -#align category_theory.splitting.ι_retraction CategoryTheory.Splitting.ι_retraction - -@[reassoc (attr := simp)] -theorem section_retraction : h.section ≫ h.retraction = 0 := by - delta Splitting.section retraction - simp -#align category_theory.splitting.section_retraction CategoryTheory.Splitting.section_retraction - -/-- The retraction in a splitting is a split mono. -/ -protected def splitMono : SplitMono f := - ⟨h.retraction, by simp⟩ -#align category_theory.splitting.split_mono CategoryTheory.Splitting.splitMono - -/-- The section in a splitting is a split epi. -/ -protected def splitEpi : SplitEpi g := - ⟨h.section, by simp⟩ -#align category_theory.splitting.split_epi CategoryTheory.Splitting.splitEpi - -@[reassoc (attr := simp)] -theorem inr_iso_inv : biprod.inr ≫ h.iso.inv = h.section := - rfl -#align category_theory.splitting.inr_iso_inv CategoryTheory.Splitting.inr_iso_inv - -@[reassoc (attr := simp)] -theorem iso_hom_fst : h.iso.hom ≫ biprod.fst = h.retraction := - rfl -#align category_theory.splitting.iso_hom_fst CategoryTheory.Splitting.iso_hom_fst - -/-- A short exact sequence of the form `X -f⟶ Y -0⟶ Z` where `f` is an iso and `Z` is zero -has a splitting. -/ -def splittingOfIsIsoZero {X Y Z : 𝒜} (f : X ⟶ Y) [IsIso f] (hZ : IsZero Z) : - Splitting f (0 : Y ⟶ Z) := - ⟨(asIso f).symm ≪≫ isoBiprodZero hZ, by simp [hZ.eq_of_tgt _ 0], by simp⟩ -#align category_theory.splitting.splitting_of_is_iso_zero CategoryTheory.Splitting.splittingOfIsIsoZero - -protected theorem mono : Mono f := mono_of_mono_fac h.ι_retraction -#align category_theory.splitting.mono CategoryTheory.Splitting.mono - -protected theorem epi : Epi g := epi_of_epi_fac h.section_π -#align category_theory.splitting.epi CategoryTheory.Splitting.epi - -instance : Mono h.section := by - delta Splitting.section - infer_instance - -instance : Epi h.retraction := by - delta retraction - apply epi_comp - -end HasZeroMorphisms - -section Preadditive - -variable [Preadditive 𝒜] [HasBinaryBiproducts 𝒜] - -variable (h : Splitting f g) - -theorem split_add : h.retraction ≫ f + g ≫ h.section = 𝟙 _ := by - delta Splitting.section retraction - rw [← cancel_mono h.iso.hom, ← cancel_epi h.iso.inv] - simp only [Category.comp_id, Category.id_comp, Category.assoc, Iso.inv_hom_id_assoc, - Iso.inv_hom_id, Limits.biprod.total, Preadditive.comp_add, Preadditive.add_comp, - Splitting.comp_iso_eq_inl, Splitting.iso_comp_eq_snd_assoc] -#align category_theory.splitting.split_add CategoryTheory.Splitting.split_add - -@[reassoc] -theorem retraction_ι_eq_id_sub : h.retraction ≫ f = 𝟙 _ - g ≫ h.section := - eq_sub_iff_add_eq.mpr h.split_add -#align category_theory.splitting.retraction_ι_eq_id_sub CategoryTheory.Splitting.retraction_ι_eq_id_sub - -@[reassoc] -theorem π_section_eq_id_sub : g ≫ h.section = 𝟙 _ - h.retraction ≫ f := - eq_sub_iff_add_eq.mpr ((add_comm _ _).trans h.split_add) -#align category_theory.splitting.π_section_eq_id_sub CategoryTheory.Splitting.π_section_eq_id_sub - -theorem splittings_comm (h h' : Splitting f g) : - h'.section ≫ h.retraction = -h.section ≫ h'.retraction := by - haveI := h.mono - rw [← cancel_mono f] - simp [retraction_ι_eq_id_sub] -#align category_theory.splitting.splittings_comm CategoryTheory.Splitting.splittings_comm - -theorem split : Split f g := - ⟨⟨h.retraction, h.section, h.ι_retraction, h.section_π, by - rw [← h.inl_comp_iso_eq, Category.assoc, h.iso_comp_eq_snd, biprod.inl_snd], - h.section_retraction, h.split_add⟩⟩ -#align category_theory.splitting.split CategoryTheory.Splitting.split - -@[reassoc] -theorem comp_eq_zero : f ≫ g = 0 := - h.split.1.choose_spec.choose_spec.2.2.1 -#align category_theory.splitting.comp_eq_zero CategoryTheory.Splitting.comp_eq_zero - -variable [HasKernels 𝒜] [HasImages 𝒜] [HasZeroObject 𝒜] [HasCokernels 𝒜] - -protected theorem exact : Exact f g := by - rw [exact_iff_exact_of_iso f g (biprod.inl : A ⟶ A ⊞ C) (biprod.snd : A ⊞ C ⟶ C) _ _ _] - · exact exact_inl_snd _ _ - · refine Arrow.isoMk (Iso.refl _) h.iso ?_ - simp only [Iso.refl_hom, Arrow.mk_hom, Category.id_comp, comp_iso_eq_inl] - rfl - · refine Arrow.isoMk h.iso (Iso.refl _) ?_ - dsimp - simp - · rfl -#align category_theory.splitting.exact CategoryTheory.Splitting.exact - -protected theorem shortExact : ShortExact f g where - mono := h.mono - epi := h.epi - exact := h.exact -#align category_theory.splitting.short_exact CategoryTheory.Splitting.shortExact - -end Preadditive - -end Splitting - -end CategoryTheory diff --git a/Mathlib/CategoryTheory/Abelian/DiagramLemmas/Four.lean b/Mathlib/CategoryTheory/Abelian/DiagramLemmas/Four.lean index 3fb884973adaf..00e434699c44d 100644 --- a/Mathlib/CategoryTheory/Abelian/DiagramLemmas/Four.lean +++ b/Mathlib/CategoryTheory/Abelian/DiagramLemmas/Four.lean @@ -1,16 +1,17 @@ /- 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, Joël Riou -/ -import Mathlib.CategoryTheory.Abelian.Pseudoelements +import Mathlib.Algebra.Homology.ExactSequence +import Mathlib.CategoryTheory.Abelian.Refinements #align_import category_theory.abelian.diagram_lemmas.four from "leanprover-community/mathlib"@"d34cbcf6c94953e965448c933cd9cc485115ebbd" /-! # The four and five lemmas -Consider the following commutative diagram with exact rows in an abelian category: +Consider the following commutative diagram with exact rows in an abelian category `C`: ``` A ---f--> B ---g--> C ---h--> D ---i--> E @@ -30,19 +31,13 @@ We show: ## Implementation details -To show the mono version, we use pseudoelements. For the epi version, we use a completely different -arrow-theoretic proof. In theory, it should be sufficient to have one version and the other should -follow automatically by duality. In practice, mathlib's knowledge about duality isn't quite at the -point where this is doable easily. +The diagram of the five lemmas is given by a morphism in the category `ComposableArrows C 4` +between two objects which satisfy `ComposableArrows.Exact`. Similarly, the two versions of the +four lemma are stated in terms of the category `ComposableArrows C 3`. -However, one key duality statement about exactness is needed in the proof of the epi version of the -four lemma: we need to know that exactness of a pair `(f, g)`, which we defined via the map from -the image of `f` to the kernel of `g`, is the same as "co-exactness", defined via the map from the -cokernel of `f` to the coimage of `g` (more precisely, we only need the consequence that if `(f, g)` -is exact, then the factorization of `g` through the cokernel of `f` is monomorphic). Luckily, in the -case of abelian categories, we have the characterization that `(f, g)` is exact if and only if -`f ≫ g = 0` and `kernel.ι g ≫ cokernel.π f = 0`, and the latter condition is self dual, so the -equivalence of exactness and co-exactness follows easily. +The five lemmas is deduced from the two versions of the four lemma. Both of these versions +are proved separately. It would be easy to deduce the epi version from the mono version +using duality, but this would require lengthy API developments for `ComposableArrows` (TODO). ## Tags @@ -50,169 +45,109 @@ four lemma, five lemma, diagram lemma, diagram chase -/ -open CategoryTheory hiding comp_apply - -open CategoryTheory.Abelian.Pseudoelement - -open CategoryTheory.Limits - -universe v u - -variable {V : Type u} [Category.{v} V] [Abelian V] - -attribute [local instance] Preadditive.hasEqualizers_of_hasKernels - -open Pseudoelement - -namespace CategoryTheory.Abelian - -variable {A B C D A' B' C' D' : V} - -variable {f : A ⟶ B} {g : B ⟶ C} {h : C ⟶ D} - -variable {f' : A' ⟶ B'} {g' : B' ⟶ C'} {h' : C' ⟶ D'} - -variable {α : A ⟶ A'} {β : B ⟶ B'} {γ : C ⟶ C'} {δ : D ⟶ D'} - -variable (comm₁ : α ≫ f' = f ≫ β) (comm₂ : β ≫ g' = g ≫ γ) (comm₃ : γ ≫ h' = h ≫ δ) - -section - -variable (hfg : Exact f g) (hgh : Exact g h) (hf'g' : Exact f' g') - -/-- The four lemma, mono version. For names of objects and morphisms, refer to the following - diagram: - -``` -A ---f--> B ---g--> C ---h--> D -| | | | -α β γ δ -| | | | -v v v v -A' --f'-> B' --g'-> C' --h'-> D' -``` --/ -theorem mono_of_epi_of_mono_of_mono (hα : Epi α) (hβ : Mono β) (hδ : Mono δ) : Mono γ := - mono_of_zero_of_map_zero _ fun c hc => - have : h c = 0 := - suffices δ (h c) = 0 from zero_of_map_zero _ (pseudo_injective_of_mono _) _ this - calc - δ (h c) = h' (γ c) := by rw [← Pseudoelement.comp_apply, ← comm₃, Pseudoelement.comp_apply] - _ = h' 0 := by rw [hc] - _ = 0 := apply_zero _ - Exists.elim ((pseudo_exact_of_exact hgh).2 _ this) fun b hb => - have : g' (β b) = 0 := - calc - g' (β b) = γ (g b) := by rw [← Pseudoelement.comp_apply, comm₂, Pseudoelement.comp_apply] - _ = γ c := by rw [hb] - _ = 0 := hc - Exists.elim ((pseudo_exact_of_exact hf'g').2 _ this) fun a' ha' => - Exists.elim (pseudo_surjective_of_epi α a') fun a ha => - have : f a = b := - suffices β (f a) = β b from pseudo_injective_of_mono _ this - calc - β (f a) = f' (α a) := by - rw [← Pseudoelement.comp_apply, ← comm₁, Pseudoelement.comp_apply] - _ = f' a' := by rw [ha] - _ = β b := ha' - calc - c = g b := hb.symm - _ = g (f a) := by rw [this] - _ = 0 := (pseudo_exact_of_exact hfg).1 _ -#align category_theory.abelian.mono_of_epi_of_mono_of_mono CategoryTheory.Abelian.mono_of_epi_of_mono_of_mono - -end - -section - -variable (hgh : Exact g h) (hf'g' : Exact f' g') (hg'h' : Exact g' h') - -/-- The four lemma, epi version. For names of objects and morphisms, refer to the following - diagram: - -``` -A ---f--> B ---g--> C ---h--> D -| | | | -α β γ δ -| | | | -v v v v -A' --f'-> B' --g'-> C' --h'-> D' -``` --/ -theorem epi_of_epi_of_epi_of_mono (hα : Epi α) (hγ : Epi γ) (hδ : Mono δ) : Epi β := - Preadditive.epi_of_cancel_zero _ fun {R} r hβr => by - have hf'r : f' ≫ r = 0 := - Limits.zero_of_epi_comp α <| - calc - α ≫ f' ≫ r = f ≫ β ≫ r := by rw [reassoc_of% comm₁] - _ = f ≫ 0 := by rw [hβr] - _ = 0 := HasZeroMorphisms.comp_zero _ _ - let y : R ⟶ pushout r g' := pushout.inl - let z : C' ⟶ pushout r g' := pushout.inr - -- Porting note: Added instance for `Mono (cokernel.desc f' g' hf'g'.w)` - have : Mono (cokernel.desc f' g' hf'g'.w) := mono_cokernel_desc_of_exact _ _ hf'g' - have : Mono y := - mono_inl_of_factor_thru_epi_mono_factorization r g' (cokernel.π f') - (cokernel.desc f' g' hf'g'.w) (by simp) (cokernel.desc f' r hf'r) (by simp) _ - (colimit.isColimit _) - have hz : g ≫ γ ≫ z = 0 := - calc - g ≫ γ ≫ z = β ≫ g' ≫ z := by rw [← reassoc_of% comm₂] - _ = β ≫ r ≫ y := by rw [← pushout.condition] - _ = 0 ≫ y := by rw [reassoc_of% hβr] - _ = 0 := HasZeroMorphisms.zero_comp _ _ - let v : pushout r g' ⟶ pushout (γ ≫ z) (h ≫ δ) := pushout.inl - let w : D' ⟶ pushout (γ ≫ z) (h ≫ δ) := pushout.inr - -- Porting note: Added instance for `Mono (cokernel.desc g h hgh.w)` - have : Mono (cokernel.desc g h hgh.w) := mono_cokernel_desc_of_exact _ _ hgh - have : Mono v := - mono_inl_of_factor_thru_epi_mono_factorization _ _ (cokernel.π g) - (cokernel.desc g h hgh.w ≫ δ) (by simp) (cokernel.desc _ _ hz) (by simp) _ - (colimit.isColimit _) - have hzv : z ≫ v = h' ≫ w := - (cancel_epi γ).1 <| - calc - γ ≫ z ≫ v = h ≫ δ ≫ w := by rw [← Category.assoc, pushout.condition, Category.assoc] - _ = γ ≫ h' ≫ w := by rw [reassoc_of% comm₃] - suffices (r ≫ y) ≫ v = 0 from zero_of_comp_mono _ (zero_of_comp_mono _ this) - calc - (r ≫ y) ≫ v = g' ≫ z ≫ v := by rw [pushout.condition, Category.assoc] - _ = g' ≫ h' ≫ w := by rw [hzv] - _ = 0 ≫ w := (hg'h'.w_assoc _) - _ = 0 := HasZeroMorphisms.zero_comp _ _ -#align category_theory.abelian.epi_of_epi_of_epi_of_mono CategoryTheory.Abelian.epi_of_epi_of_epi_of_mono - -end +namespace CategoryTheory + +open Category Limits Preadditive + +namespace Abelian + +variable {C : Type*} [Category C] [Abelian C] + +open ComposableArrows + +section Four + +variable {R₁ R₂ : ComposableArrows C 3} (φ : R₁ ⟶ R₂) + +theorem mono_of_epi_of_mono_of_mono' (hR₁ : R₁.map' 0 2 = 0) + (hR₁' : (mk₂ (R₁.map' 1 2) (R₁.map' 2 3)).Exact) + (hR₂ : (mk₂ (R₂.map' 0 1) (R₂.map' 1 2)).Exact) + (h₀ : Epi (app' φ 0)) (h₁ : Mono (app' φ 1)) (h₃ : Mono (app' φ 3)) : + Mono (app' φ 2) := by + apply mono_of_cancel_zero + intro A f₂ h₁ + have h₂ : f₂ ≫ R₁.map' 2 3 = 0 := by + rw [← cancel_mono (app' φ 3 _), assoc, NatTrans.naturality, reassoc_of% h₁, + zero_comp, zero_comp] + obtain ⟨A₁, π₁, _, f₁, hf₁⟩ := (hR₁'.exact 0).exact_up_to_refinements f₂ h₂ + dsimp at hf₁ + have h₃ : (f₁ ≫ app' φ 1) ≫ R₂.map' 1 2 = 0 := by + rw [assoc, ← NatTrans.naturality, ← reassoc_of% hf₁, h₁, comp_zero] + obtain ⟨A₂, π₂, _, g₀, hg₀⟩ := (hR₂.exact 0).exact_up_to_refinements _ h₃ + obtain ⟨A₃, π₃, _, f₀, hf₀⟩ := surjective_up_to_refinements_of_epi (app' φ 0 _) g₀ + have h₄ : f₀ ≫ R₁.map' 0 1 = π₃ ≫ π₂ ≫ f₁ := by + rw [← cancel_mono (app' φ 1 _), assoc, assoc, assoc, NatTrans.naturality, + ← reassoc_of% hf₀, hg₀] + rfl + rw [← cancel_epi π₁, comp_zero, hf₁, ← cancel_epi π₂, ← cancel_epi π₃, comp_zero, + comp_zero, ← reassoc_of% h₄, ← R₁.map'_comp 0 1 2, hR₁, comp_zero] +#align category_theory.abelian.mono_of_epi_of_mono_of_mono CategoryTheory.Abelian.mono_of_epi_of_mono_of_mono' + +theorem mono_of_epi_of_mono_of_mono (hR₁ : R₁.Exact) (hR₂ : R₂.Exact) + (h₀ : Epi (app' φ 0)) (h₁ : Mono (app' φ 1)) (h₃ : Mono (app' φ 3)) : + Mono (app' φ 2) := + mono_of_epi_of_mono_of_mono' φ + (by simpa only [R₁.map'_comp 0 1 2] using hR₁.toIsComplex.zero 0) + (hR₁.exact 1).exact_toComposableArrows (hR₂.exact 0).exact_toComposableArrows h₀ h₁ h₃ + +attribute [local instance] epi_comp + +theorem epi_of_epi_of_epi_of_mono' + (hR₁ : (mk₂ (R₁.map' 1 2) (R₁.map' 2 3)).Exact) + (hR₂ : (mk₂ (R₂.map' 0 1) (R₂.map' 1 2)).Exact) (hR₂' : R₂.map' 1 3 = 0) + (h₀ : Epi (app' φ 0)) (h₂ : Epi (app' φ 2)) (h₃ : Mono (app' φ 3)) : + Epi (app' φ 1) := by + rw [epi_iff_surjective_up_to_refinements] + intro A g₁ + obtain ⟨A₁, π₁, _, f₂, h₁⟩ := + surjective_up_to_refinements_of_epi (app' φ 2 _) (g₁ ≫ R₂.map' 1 2) + have h₂ : f₂ ≫ R₁.map' 2 3 = 0 := by + rw [← cancel_mono (app' φ 3 _), assoc, zero_comp, NatTrans.naturality, ← reassoc_of% h₁, + ← R₂.map'_comp 1 2 3, hR₂', comp_zero, comp_zero] + obtain ⟨A₂, π₂, _, f₁, h₃⟩ := (hR₁.exact 0).exact_up_to_refinements _ h₂ + dsimp at f₁ h₃ + have h₄ : (π₂ ≫ π₁ ≫ g₁ - f₁ ≫ app' φ 1) ≫ R₂.map' 1 2 = 0 := by + rw [sub_comp, assoc, assoc, assoc, ← NatTrans.naturality, ← reassoc_of% h₃, h₁, sub_self] + obtain ⟨A₃, π₃, _, g₀, h₅⟩ := (hR₂.exact 0).exact_up_to_refinements _ h₄ + dsimp at g₀ h₅ + rw [comp_sub] at h₅ + obtain ⟨A₄, π₄, _, f₀, h₆⟩ := surjective_up_to_refinements_of_epi (app' φ 0 _) g₀ + refine' ⟨A₄, π₄ ≫ π₃ ≫ π₂ ≫ π₁, inferInstance, + π₄ ≫ π₃ ≫ f₁ + f₀ ≫ (by exact R₁.map' 0 1), _⟩ + rw [assoc, assoc, assoc, add_comp, assoc, assoc, assoc, NatTrans.naturality, + ← reassoc_of% h₆, ← h₅, comp_sub] + dsimp + rw [add_sub_cancel'_right] +#align category_theory.abelian.epi_of_epi_of_epi_of_mono CategoryTheory.Abelian.epi_of_epi_of_epi_of_mono' + +theorem epi_of_epi_of_epi_of_mono (hR₁ : R₁.Exact) (hR₂ : R₂.Exact) + (h₀ : Epi (app' φ 0)) (h₂ : Epi (app' φ 2)) (h₃ : Mono (app' φ 3)) : + Epi (app' φ 1) := + epi_of_epi_of_epi_of_mono' φ (hR₁.exact 1).exact_toComposableArrows + (hR₂.exact 0).exact_toComposableArrows + (by simpa only [R₂.map'_comp 1 2 3] using hR₂.toIsComplex.zero 1) h₀ h₂ h₃ + +end Four section Five -variable {E E' : V} {i : D ⟶ E} {i' : D' ⟶ E'} {ε : E ⟶ E'} (comm₄ : δ ≫ i' = i ≫ ε) - -variable (hfg : Exact f g) (hgh : Exact g h) (hhi : Exact h i) - -variable (hf'g' : Exact f' g') (hg'h' : Exact g' h') (hh'i' : Exact h' i') - -variable [Epi α] [IsIso β] [IsIso δ] [Mono ε] - -/-- The five lemma. For names of objects and morphisms, refer to the following diagram: - -``` -A ---f--> B ---g--> C ---h--> D ---i--> E -| | | | | -α β γ δ ε -| | | | | -v v v v v -A' --f'-> B' --g'-> C' --h'-> D' --i'-> E' -``` --/ -theorem isIso_of_epi_of_isIso_of_isIso_of_mono : IsIso γ := - have : Mono γ := by - apply mono_of_epi_of_mono_of_mono comm₁ comm₂ comm₃ hfg hgh hf'g' <;> infer_instance - have : Epi γ := by - apply epi_of_epi_of_epi_of_mono comm₂ comm₃ comm₄ hhi hg'h' hh'i' <;> infer_instance - isIso_of_mono_of_epi _ +variable {R₁ R₂ : ComposableArrows C 4} (hR₁ : R₁.Exact) (hR₂ : R₂.Exact) (φ : R₁ ⟶ R₂) + +/-- The five lemma. -/ +theorem isIso_of_epi_of_isIso_of_isIso_of_mono (h₀ : Epi (app' φ 0)) (h₁ : IsIso (app' φ 1)) + (h₂ : IsIso (app' φ 3)) (h₃ : Mono (app' φ 4)) : IsIso (app' φ 2) := by + dsimp at h₀ h₁ h₂ h₃ + have : Mono (app' φ 2) := by + apply mono_of_epi_of_mono_of_mono (δlastFunctor.map φ) (R₁.exact_iff_δlast.1 hR₁).1 + (R₂.exact_iff_δlast.1 hR₂).1 <;> dsimp <;> infer_instance + have : Epi (app' φ 2) := by + apply epi_of_epi_of_epi_of_mono (δ₀Functor.map φ) (R₁.exact_iff_δ₀.1 hR₁).2 + (R₂.exact_iff_δ₀.1 hR₂).2 <;> dsimp <;> infer_instance + apply isIso_of_mono_of_epi #align category_theory.abelian.is_iso_of_is_iso_of_is_iso_of_is_iso_of_is_iso CategoryTheory.Abelian.isIso_of_epi_of_isIso_of_isIso_of_mono end Five -end CategoryTheory.Abelian +end Abelian + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/ComposableArrows.lean b/Mathlib/CategoryTheory/ComposableArrows.lean index 6c8ad28cc5cd9..0e9f965290538 100644 --- a/Mathlib/CategoryTheory/ComposableArrows.lean +++ b/Mathlib/CategoryTheory/ComposableArrows.lean @@ -445,6 +445,21 @@ abbrev δ₀ (F : ComposableArrows C (n + 1)) := δ₀Functor.obj F @[simp] lemma precomp_δ₀ {X : C} (f : X ⟶ F.left) : (F.precomp f).δ₀ = F := rfl +/-- The functor `Fin n ⥤ Fin (n + 1)` which sends `i` to `i.castSucc`. -/ +@[simps] +def _root_.Fin.castSuccFunctor (n : ℕ) : Fin n ⥤ Fin (n + 1) where + obj i := i.castSucc + map hij := hij + +/-- The functor `ComposableArrows C (n + 1) ⥤ ComposableArrows C n` which forgets +the last arrow. -/ +@[simps!] +def δlastFunctor : ComposableArrows C (n + 1) ⥤ ComposableArrows C n := + whiskerLeftFunctor (Fin.castSuccFunctor (n + 1)) + +/-- The `ComposableArrows C n` obtained by forgetting the first arrow. -/ +abbrev δlast (F : ComposableArrows C (n + 1)) := δlastFunctor.obj F + section variable {F G : ComposableArrows C (n + 1)} diff --git a/Mathlib/Topology/Category/Profinite/Nobeling.lean b/Mathlib/Topology/Category/Profinite/Nobeling.lean index 3c3fabb1a78a8..ff6e389613661 100644 --- a/Mathlib/Topology/Category/Profinite/Nobeling.lean +++ b/Mathlib/Topology/Category/Profinite/Nobeling.lean @@ -1367,13 +1367,11 @@ theorem succ_mono : CategoryTheory.Mono (ModuleCat.ofHom (πs C o)) := by exact injective_πs _ _ theorem succ_exact : - CategoryTheory.Exact (ModuleCat.ofHom (πs C o)) (ModuleCat.ofHom (Linear_CC' C hsC ho)) := by - rw [ModuleCat.exact_iff] - ext f - rw [LinearMap.mem_ker, LinearMap.mem_range] - refine ⟨fun ⟨y, hy⟩ ↦ ?_, fun hf ↦ ?_⟩ - · simpa only [ModuleCat.ofHom, ← hy] using CC_comp_zero _ _ _ y - · exact CC_exact _ hC _ ho hf + (ShortComplex.mk (ModuleCat.ofHom (πs C o)) (ModuleCat.ofHom (Linear_CC' C hsC ho)) + (by ext; apply CC_comp_zero)).Exact := by + rw [ShortComplex.moduleCat_exact_iff] + intro f + exact CC_exact C hC hsC ho end ExactSequence @@ -1639,7 +1637,7 @@ theorem maxTail_isGood (l : MaxProducts C ho) rw [Products.max_eq_o_cons_tail ho p hp.1 hp.2.1] rfl have hse := succ_exact C hC hsC ho - rw [ModuleCat.exact_iff] at hse + rw [ShortComplex.moduleCat_exact_iff_range_eq_ker] at hse dsimp [ModuleCat.ofHom] at hse -- Rewrite `this` using exact sequence manipulations to conclude that a term is in the range of @@ -1754,8 +1752,8 @@ theorem GoodProducts.linearIndependentAux (μ : Ordinal) : P I μ := by have ho' : o < Ordinal.type (·<· : I → I → Prop) := lt_of_lt_of_le (Order.lt_succ _) ho rw [linearIndependent_iff_sum C hsC ho'] - refine ModuleCat.linearIndependent_leftExact ?_ ?_ (succ_mono C o) (succ_exact C hC hsC ho') - (square_commutes C ho') + refine' ModuleCat.linearIndependent_leftExact (succ_exact C hC hsC ho') ?_ ?_ (succ_mono C o) + (square_commutes C ho') · exact h (le_of_lt ho') (π C (ord I · < o)) (isClosed_proj C o hC) (contained_proj C o) · exact linearIndependent_comp_of_eval C hC hsC ho' (span (π C (ord I · < o)) (isClosed_proj C o hC)) (h (le_of_lt ho') (C' C ho') (isClosed_C' C hC ho') From 3fca282c58b247f313d18951a2f93d8341cd48a7 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Thu, 21 Dec 2023 16:16:27 +0000 Subject: [PATCH 113/353] chore: remove uses of `cases'` (#9171) I literally went through and regex'd some uses of `cases'`, replacing them with `rcases`; this is meant to be a low effort PR as I hope that tools can do this in the future. `rcases` is an easier replacement than `cases`, though with better tools we could in future do a second pass converting simple `rcases` added here (and existing ones) to `cases`. --- Archive/Arithcc.lean | 2 +- Archive/Imo/Imo2011Q5.lean | 2 +- .../SeminormLatticeNotDistrib.lean | 4 +-- Counterexamples/SorgenfreyLine.lean | 2 +- Mathlib/Algebra/BigOperators/Ring.lean | 2 +- .../Computation/Translations.lean | 10 +++--- Mathlib/Algebra/GeomSum.lean | 2 +- Mathlib/Algebra/GroupPower/Lemmas.lean | 6 ++-- Mathlib/Algebra/Homology/LocalCohomology.lean | 2 +- Mathlib/Algebra/Lie/Nilpotent.lean | 2 +- Mathlib/Algebra/Module/Torsion.lean | 2 +- Mathlib/Algebra/Order/Field/Basic.lean | 2 +- Mathlib/Algebra/Order/Floor.lean | 6 ++-- Mathlib/Algebra/Order/Group/Abs.lean | 4 +-- .../Algebra/Order/Monoid/Canonical/Defs.lean | 4 +-- Mathlib/Algebra/Order/Monoid/MinMax.lean | 3 +- Mathlib/Algebra/Order/Ring/Abs.lean | 2 +- Mathlib/Algebra/Order/Sub/Canonical.lean | 6 ++-- Mathlib/Algebra/Order/ToIntervalMod.lean | 2 +- Mathlib/Algebra/Polynomial/BigOperators.lean | 2 +- Mathlib/Algebra/Tropical/Basic.lean | 6 ++-- Mathlib/AlgebraicGeometry/Properties.lean | 2 +- .../AlgebraicTopology/SimplexCategory.lean | 2 +- Mathlib/Analysis/Analytic/Basic.lean | 2 +- Mathlib/Analysis/Asymptotics/Asymptotics.lean | 2 +- Mathlib/Analysis/BoundedVariation.lean | 2 +- .../Analysis/BoxIntegral/Partition/Basic.lean | 2 +- Mathlib/Analysis/Calculus/Darboux.lean | 3 +- Mathlib/Analysis/Calculus/Deriv/ZPow.lean | 2 +- .../ApproximatesLinearOn.lean | 2 +- .../Calculus/LocalExtr/Polynomial.lean | 2 +- .../Analysis/Complex/PhragmenLindelof.lean | 4 +-- Mathlib/Analysis/Complex/Schwarz.lean | 2 +- Mathlib/Analysis/Convex/Integral.lean | 6 ++-- Mathlib/Analysis/Convex/Segment.lean | 4 +-- .../Convex/SpecificFunctions/Basic.lean | 2 +- .../Convex/SpecificFunctions/Deriv.lean | 4 +-- .../Analysis/Convex/StrictConvexSpace.lean | 2 +- Mathlib/Analysis/MeanInequalities.lean | 4 +-- Mathlib/Analysis/Normed/Group/AddCircle.lean | 2 +- Mathlib/Analysis/Normed/Group/Basic.lean | 2 +- Mathlib/Analysis/NormedSpace/AddTorsor.lean | 2 +- Mathlib/Analysis/NormedSpace/RieszLemma.lean | 2 +- Mathlib/Analysis/ODE/PicardLindelof.lean | 2 +- Mathlib/Analysis/PSeries.lean | 2 +- .../Analysis/SpecialFunctions/CompareExp.lean | 2 +- .../SpecialFunctions/Complex/Arg.lean | 8 ++--- .../Analysis/SpecialFunctions/Integrals.lean | 2 +- .../SpecialFunctions/Polynomials.lean | 2 +- .../Analysis/SpecialFunctions/Pow/Real.lean | 4 +-- .../Trigonometric/Arctan.lean | 2 +- .../Trigonometric/Inverse.lean | 6 ++-- Mathlib/Combinatorics/Hindman.lean | 2 +- Mathlib/Computability/TuringMachine.lean | 6 ++-- Mathlib/Control/LawfulFix.lean | 2 +- Mathlib/Data/Fin/Basic.lean | 4 +-- Mathlib/Data/Finset/PiInduction.lean | 2 +- Mathlib/Data/Finset/Powerset.lean | 16 ++++----- Mathlib/Data/Fintype/Card.lean | 2 +- Mathlib/Data/Int/Log.lean | 16 ++++----- Mathlib/Data/List/Basic.lean | 4 +-- Mathlib/Data/List/Intervals.lean | 10 +++--- Mathlib/Data/List/Rotate.lean | 8 ++--- Mathlib/Data/Nat/Cast/Order.lean | 2 +- Mathlib/Data/Nat/Choose/Basic.lean | 4 +-- Mathlib/Data/Nat/Digits.lean | 2 +- Mathlib/Data/Nat/Fib/Basic.lean | 2 +- Mathlib/Data/Nat/GCD/Basic.lean | 2 +- Mathlib/Data/Nat/Log.lean | 8 ++--- Mathlib/Data/Nat/Order/Basic.lean | 8 ++--- Mathlib/Data/Nat/Order/Lemmas.lean | 2 +- Mathlib/Data/Nat/Prime.lean | 4 +-- Mathlib/Data/Nat/Squarefree.lean | 8 ++--- Mathlib/Data/Ordmap/Ordset.lean | 20 +++++------ Mathlib/Data/Pi/Lex.lean | 2 +- Mathlib/Data/Polynomial/Derivative.lean | 2 +- Mathlib/Data/Polynomial/Expand.lean | 2 +- Mathlib/Data/Rat/NNRat.lean | 2 +- Mathlib/Data/Rat/Order.lean | 2 +- Mathlib/Data/Real/ENNReal.lean | 2 +- Mathlib/Data/Real/NNReal.lean | 4 +-- Mathlib/Data/Real/Sqrt.lean | 4 +-- Mathlib/Data/Set/Finite.lean | 2 +- Mathlib/Data/Set/Intervals/Basic.lean | 24 ++++++------- .../Set/Intervals/OrdConnectedComponent.lean | 6 ++-- Mathlib/Data/Set/Intervals/ProjIcc.lean | 2 +- .../Data/Set/Intervals/UnorderedInterval.lean | 4 +-- Mathlib/Data/Set/Prod.lean | 4 +-- Mathlib/Dynamics/Ergodic/AddCircle.lean | 2 +- Mathlib/Dynamics/PeriodicPts.lean | 2 +- Mathlib/FieldTheory/IsAlgClosed/Basic.lean | 2 +- Mathlib/FieldTheory/IsSepClosed.lean | 2 +- Mathlib/FieldTheory/Minpoly/Basic.lean | 2 +- Mathlib/Geometry/Manifold/ChartedSpace.lean | 2 +- Mathlib/GroupTheory/Perm/List.lean | 6 ++-- .../AffineSpace/AffineSubspace.lean | 2 +- Mathlib/LinearAlgebra/AffineSpace/Basis.lean | 2 +- .../AffineSpace/Combination.lean | 2 +- Mathlib/LinearAlgebra/Basis.lean | 2 +- Mathlib/LinearAlgebra/LinearPMap.lean | 2 +- Mathlib/LinearAlgebra/Matrix/Adjugate.lean | 2 +- .../LinearAlgebra/Matrix/Charpoly/Coeff.lean | 2 +- .../Matrix/NonsingularInverse.lean | 2 +- Mathlib/LinearAlgebra/Matrix/Polynomial.lean | 2 +- Mathlib/LinearAlgebra/Matrix/ZPow.lean | 2 +- .../Constructions/BorelSpace/Basic.lean | 2 +- Mathlib/MeasureTheory/Constructions/Pi.lean | 4 +-- .../MeasureTheory/Covering/LiminfLimsup.lean | 2 +- Mathlib/MeasureTheory/Function/Floor.lean | 4 +-- .../MeasureTheory/Function/LpSeminorm.lean | 4 +-- Mathlib/MeasureTheory/Function/LpSpace.lean | 2 +- .../Function/StronglyMeasurable/Basic.lean | 2 +- Mathlib/MeasureTheory/Group/AddCircle.lean | 2 +- Mathlib/MeasureTheory/Integral/Average.lean | 4 +-- .../Integral/CircleIntegral.lean | 2 +- .../Integral/DivergenceTheorem.lean | 2 +- .../Integral/FundThmCalculus.lean | 4 +-- .../Integral/IntervalAverage.lean | 2 +- .../Integral/IntervalIntegral.lean | 6 ++-- Mathlib/MeasureTheory/Integral/Lebesgue.lean | 2 +- .../MeasureTheory/MeasurableSpace/Basic.lean | 4 +-- Mathlib/MeasureTheory/Measure/Content.lean | 2 +- .../MeasureTheory/Measure/Haar/OfBasis.lean | 6 ++-- .../MeasureTheory/Measure/MeasureSpace.lean | 2 +- .../MeasureTheory/Measure/OuterMeasure.lean | 10 +++--- Mathlib/MeasureTheory/Measure/Regular.lean | 2 +- Mathlib/MeasureTheory/Measure/Restrict.lean | 2 +- Mathlib/MeasureTheory/Measure/Stieltjes.lean | 6 ++-- Mathlib/ModelTheory/FinitelyGenerated.lean | 2 +- Mathlib/NumberTheory/Dioph.lean | 2 +- .../DiophantineApproximation.lean | 4 +-- .../NumberTheory/LegendreSymbol/Basic.lean | 2 +- .../NumberTheory/LegendreSymbol/GaussSum.lean | 2 +- .../LegendreSymbol/JacobiSymbol.lean | 2 +- .../LegendreSymbol/QuadraticReciprocity.lean | 4 +-- .../NumberTheory/Liouville/LiouvilleWith.lean | 2 +- Mathlib/NumberTheory/Pell.lean | 6 ++-- Mathlib/NumberTheory/PellMatiyasevic.lean | 4 +-- Mathlib/NumberTheory/PythagoreanTriples.lean | 2 +- Mathlib/Order/Atoms.lean | 4 +-- Mathlib/Order/Bounds/Basic.lean | 4 +-- Mathlib/Order/Circular.lean | 4 +-- Mathlib/Order/CompactlyGenerated.lean | 2 +- .../ConditionallyCompleteLattice/Basic.lean | 4 +-- Mathlib/Order/Filter/Bases.lean | 2 +- Mathlib/Order/Filter/FilterProduct.lean | 4 +-- Mathlib/Order/Filter/Interval.lean | 2 +- Mathlib/Order/Height.lean | 2 +- Mathlib/Order/LiminfLimsup.lean | 2 +- Mathlib/Order/MinMax.lean | 6 ++-- Mathlib/Order/ModularLattice.lean | 2 +- Mathlib/Order/OmegaCompletePartialOrder.lean | 2 +- Mathlib/Order/OrderIsoNat.lean | 2 +- Mathlib/Order/SuccPred/Basic.lean | 4 +-- Mathlib/Order/SuccPred/IntervalSucc.lean | 2 +- .../Order/SuccPred/LinearLocallyFinite.lean | 14 ++++---- Mathlib/Order/SuccPred/Relation.lean | 2 +- .../Probability/Kernel/Disintegration.lean | 3 -- Mathlib/Probability/Moments.lean | 2 +- Mathlib/Probability/Process/HittingTime.lean | 16 ++++----- Mathlib/Probability/Process/Stopping.lean | 2 +- Mathlib/RingTheory/Artinian.lean | 2 +- .../DiscreteValuationRing/TFAE.lean | 2 +- Mathlib/RingTheory/Ideal/Operations.lean | 2 +- .../RingTheory/Localization/Away/Basic.lean | 2 +- Mathlib/RingTheory/Noetherian.lean | 2 +- Mathlib/RingTheory/Polynomial/Basic.lean | 4 +-- .../RingTheory/Polynomial/Hermite/Basic.lean | 2 +- Mathlib/RingTheory/Polynomial/Nilpotent.lean | 2 +- Mathlib/RingTheory/RootsOfUnity/Basic.lean | 4 +-- Mathlib/RingTheory/Valuation/Basic.lean | 4 +-- .../RingTheory/Valuation/ValuationRing.lean | 8 ++--- .../Valuation/ValuationSubring.lean | 2 +- Mathlib/SetTheory/Cardinal/Divisibility.lean | 4 +-- Mathlib/SetTheory/Cardinal/Ordinal.lean | 36 +++++++++---------- Mathlib/SetTheory/Ordinal/Arithmetic.lean | 2 +- .../SetTheory/Ordinal/CantorNormalForm.lean | 2 +- Mathlib/SetTheory/Ordinal/Exponential.lean | 8 ++--- Mathlib/SetTheory/Ordinal/FixedPoint.lean | 8 ++--- Mathlib/SetTheory/Ordinal/Notation.lean | 2 +- Mathlib/SetTheory/Ordinal/Principal.lean | 4 +-- Mathlib/SetTheory/Ordinal/Topology.lean | 2 +- Mathlib/Topology/Algebra/Order/Compact.lean | 2 +- .../Algebra/Order/IntermediateValue.lean | 4 +-- Mathlib/Topology/Algebra/ValuedField.lean | 2 +- Mathlib/Topology/Constructions.lean | 2 +- Mathlib/Topology/FiberBundle/Basic.lean | 4 +-- Mathlib/Topology/Maps.lean | 2 +- Mathlib/Topology/MetricSpace/Baire.lean | 2 +- Mathlib/Topology/MetricSpace/Cauchy.lean | 2 +- .../MetricSpace/HausdorffDistance.lean | 14 ++++---- Mathlib/Topology/MetricSpace/Kuratowski.lean | 2 +- .../Topology/MetricSpace/PseudoMetric.lean | 4 +-- Mathlib/Topology/Metrizable/Uniformity.lean | 2 +- Mathlib/Topology/Metrizable/Urysohn.lean | 2 +- Mathlib/Topology/Order/Basic.lean | 2 +- Mathlib/Topology/Separation.lean | 2 +- Mathlib/Topology/TietzeExtension.lean | 6 ++-- Mathlib/Topology/UniformSpace/Cauchy.lean | 2 +- 199 files changed, 370 insertions(+), 381 deletions(-) diff --git a/Archive/Arithcc.lean b/Archive/Arithcc.lean index 0ce0533334b10..fc77d0c0749f0 100644 --- a/Archive/Arithcc.lean +++ b/Archive/Arithcc.lean @@ -272,7 +272,7 @@ theorem stateEq_implies_write_eq {t : Register} {ζ₁ ζ₂ : State} (h : ζ₁ constructor; · exact h.1 intro r hr have hr : r ≤ t := Register.le_of_lt_succ hr - cases' lt_or_eq_of_le hr with hr hr + rcases lt_or_eq_of_le hr with hr | hr · cases' h with _ h specialize h r hr simp_all diff --git a/Archive/Imo/Imo2011Q5.lean b/Archive/Imo/Imo2011Q5.lean index 3e11565bff1f8..d0db9a19b3dcd 100644 --- a/Archive/Imo/Imo2011Q5.lean +++ b/Archive/Imo/Imo2011Q5.lean @@ -24,7 +24,7 @@ open Int theorem imo2011_q5 (f : ℤ → ℤ) (hpos : ∀ n : ℤ, 0 < f n) (hdvd : ∀ m n : ℤ, f (m - n) ∣ f m - f n) : ∀ m n : ℤ, f m ≤ f n → f m ∣ f n := by intro m n h_fm_le_fn - cases' lt_or_eq_of_le h_fm_le_fn with h_fm_lt_fn h_fm_eq_fn + rcases lt_or_eq_of_le h_fm_le_fn with h_fm_lt_fn | h_fm_eq_fn · -- m < n let d := f m - f (m - n) have h_fn_dvd_d : f n ∣ d := by diff --git a/Counterexamples/SeminormLatticeNotDistrib.lean b/Counterexamples/SeminormLatticeNotDistrib.lean index 7a8c94ec5dee4..c582a4684ee37 100644 --- a/Counterexamples/SeminormLatticeNotDistrib.lean +++ b/Counterexamples/SeminormLatticeNotDistrib.lean @@ -57,8 +57,8 @@ theorem not_distrib : ¬(p ⊔ q1) ⊓ (p ⊔ q2) ≤ p ⊔ q1 ⊓ q2 := by apply c; nth_rw 1 [← eq_one] apply le_trans _ (le_sup_inf _) apply le_ciInf; intro x - cases' le_or_lt x.fst (1 / 3) with h1 h1 - · cases' le_or_lt x.snd (2 / 3) with h2 h2 + rcases le_or_lt x.fst (1 / 3) with h1 | h1 + · rcases le_or_lt x.snd (2 / 3) with h2 | h2 · calc 4 / 3 = 4 * (1 - 2 / 3) := by norm_num _ ≤ 4 * (1 - x.snd) := (mul_le_mul_left zero_lt_four).mpr (sub_le_sub_left h2 _) diff --git a/Counterexamples/SorgenfreyLine.lean b/Counterexamples/SorgenfreyLine.lean index 8f441f057a736..dd630c6794655 100644 --- a/Counterexamples/SorgenfreyLine.lean +++ b/Counterexamples/SorgenfreyLine.lean @@ -204,7 +204,7 @@ instance : T5Space ℝₗ := by (bUnion_mem_nhdsSet fun y hy => (isOpen_Ico y (Y y)).mem_nhds <| left_mem_Ico.2 (hY y hy)) simp only [disjoint_iUnion_left, disjoint_iUnion_right, Ico_disjoint_Ico] intro y hy x hx - cases' le_total x y with hle hle + rcases le_total x y with hle | hle · calc min (X x) (Y y) ≤ X x := min_le_left _ _ _ ≤ y := (not_lt.1 fun hyx => (hXd x hx).le_bot ⟨⟨hle, hyx⟩, subset_closure hy⟩) diff --git a/Mathlib/Algebra/BigOperators/Ring.lean b/Mathlib/Algebra/BigOperators/Ring.lean index 78aeedd4dfe40..8019d55d222ed 100644 --- a/Mathlib/Algebra/BigOperators/Ring.lean +++ b/Mathlib/Algebra/BigOperators/Ring.lean @@ -227,7 +227,7 @@ variable {R : Type*} [CommRing R] theorem prod_range_cast_nat_sub (n k : ℕ) : ∏ i in range k, (n - i : R) = (∏ i in range k, (n - i) : ℕ) := by rw [prod_natCast] - cases' le_or_lt k n with hkn hnk + rcases le_or_lt k n with hkn | hnk · exact prod_congr rfl fun i hi => (Nat.cast_sub <| (mem_range.1 hi).le.trans hkn).symm · rw [← mem_range] at hnk rw [prod_eq_zero hnk, prod_eq_zero hnk] <;> simp diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean b/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean index 7f86a23c6ec88..2c5183b0d9618 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean @@ -131,13 +131,13 @@ theorem stream_succ (h : Int.fract v ≠ 0) (n : ℕ) : induction' n with n ih · have H : (IntFractPair.of v).fr = Int.fract v := rfl rw [stream_zero, stream_succ_of_some (stream_zero v) (ne_of_eq_of_ne H h), H] - · cases' eq_or_ne (IntFractPair.stream (Int.fract v)⁻¹ n) none with hnone hsome + · rcases eq_or_ne (IntFractPair.stream (Int.fract v)⁻¹ n) none with hnone | hsome · rw [hnone] at ih rw [succ_nth_stream_eq_none_iff.mpr (Or.inl hnone), succ_nth_stream_eq_none_iff.mpr (Or.inl ih)] · obtain ⟨p, hp⟩ := Option.ne_none_iff_exists'.mp hsome rw [hp] at ih - cases' eq_or_ne p.fr 0 with hz hnz + rcases eq_or_ne p.fr 0 with hz | hnz · rw [stream_eq_none_of_fr_eq_zero hp hz, stream_eq_none_of_fr_eq_zero ih hz] · rw [stream_succ_of_some hp hnz, stream_succ_of_some ih hnz] #align generalized_continued_fraction.int_fract_pair.stream_succ GeneralizedContinuedFraction.IntFractPair.stream_succ @@ -298,11 +298,11 @@ variable {K} (v) that of the inverse of the fractional part of `v`. -/ theorem of_s_succ (n : ℕ) : (of v).s.get? (n + 1) = (of (fract v)⁻¹).s.get? n := by - cases' eq_or_ne (fract v) 0 with h h + rcases eq_or_ne (fract v) 0 with h | h · obtain ⟨a, rfl⟩ : ∃ a : ℤ, v = a := ⟨⌊v⌋, eq_of_sub_eq_zero h⟩ rw [fract_intCast, inv_zero, of_s_of_int, ← cast_zero, of_s_of_int, Stream'.Seq.get?_nil, Stream'.Seq.get?_nil] - cases' eq_or_ne ((of (fract v)⁻¹).s.get? n) none with h₁ h₁ + rcases eq_or_ne ((of (fract v)⁻¹).s.get? n) none with h₁ | h₁ · rwa [h₁, ← terminatedAt_iff_s_none, of_terminatedAt_n_iff_succ_nth_intFractPair_stream_eq_none, stream_succ h, ← of_terminatedAt_n_iff_succ_nth_intFractPair_stream_eq_none, terminatedAt_iff_s_none] @@ -340,7 +340,7 @@ of an element `v` of `K` in terms of the convergents of the inverse of its fract -/ theorem convergents'_succ : (of v).convergents' (n + 1) = ⌊v⌋ + 1 / (of (fract v)⁻¹).convergents' n := by - cases' eq_or_ne (fract v) 0 with h h + rcases eq_or_ne (fract v) 0 with h | h · obtain ⟨a, rfl⟩ : ∃ a : ℤ, v = a := ⟨⌊v⌋, eq_of_sub_eq_zero h⟩ rw [convergents'_of_int, fract_intCast, inv_zero, ← cast_zero, convergents'_of_int, cast_zero, div_zero, add_zero, floor_intCast] diff --git a/Mathlib/Algebra/GeomSum.lean b/Mathlib/Algebra/GeomSum.lean index c5ed8501dd2b9..6d6d69b4eb1c5 100644 --- a/Mathlib/Algebra/GeomSum.lean +++ b/Mathlib/Algebra/GeomSum.lean @@ -208,7 +208,7 @@ theorem sub_one_dvd_pow_sub_one [Ring α] (x : α) (n : ℕ) : exact (Commute.one_right x).sub_dvd_pow_sub_pow n theorem nat_sub_dvd_pow_sub_pow (x y n : ℕ) : x - y ∣ x ^ n - y ^ n := by - cases' le_or_lt y x with h h + rcases le_or_lt y x with h | h · have : y ^ n ≤ x ^ n := Nat.pow_le_pow_left h _ exact mod_cast sub_dvd_pow_sub_pow (x : ℤ) (↑y) n · have : x ^ n ≤ y ^ n := Nat.pow_le_pow_left h.le _ diff --git a/Mathlib/Algebra/GroupPower/Lemmas.lean b/Mathlib/Algebra/GroupPower/Lemmas.lean index 9662035c32d90..8c326e4887858 100644 --- a/Mathlib/Algebra/GroupPower/Lemmas.lean +++ b/Mathlib/Algebra/GroupPower/Lemmas.lean @@ -449,7 +449,7 @@ section LinearOrderedAddCommGroup variable [LinearOrderedAddCommGroup α] {a b : α} theorem abs_nsmul (n : ℕ) (a : α) : |n • a| = n • |a| := by - cases' le_total a 0 with hneg hpos + rcases le_total a 0 with hneg | hpos · rw [abs_of_nonpos hneg, ← abs_neg, ← neg_nsmul, abs_of_nonneg] exact nsmul_nonneg (neg_nonneg.mpr hneg) n · rw [abs_of_nonneg hpos, abs_of_nonneg] @@ -743,8 +743,8 @@ theorem pow_bit1_pos_iff : 0 < a ^ bit1 n ↔ 0 < a := theorem strictMono_pow_bit1 (n : ℕ) : StrictMono fun a : R => a ^ bit1 n := by intro a b hab - cases' le_total a 0 with ha ha - · cases' le_or_lt b 0 with hb hb + rcases le_total a 0 with ha | ha + · rcases le_or_lt b 0 with hb | hb · rw [← neg_lt_neg_iff, ← neg_pow_bit1, ← neg_pow_bit1] exact pow_lt_pow_left (neg_lt_neg hab) (neg_nonneg.2 hb) n.bit1_ne_zero · exact (pow_bit1_nonpos_iff.2 ha).trans_lt (pow_bit1_pos_iff.2 hb) diff --git a/Mathlib/Algebra/Homology/LocalCohomology.lean b/Mathlib/Algebra/Homology/LocalCohomology.lean index 196d87baa329b..2f79abd6cd908 100644 --- a/Mathlib/Algebra/Homology/LocalCohomology.lean +++ b/Mathlib/Algebra/Homology/LocalCohomology.lean @@ -250,7 +250,7 @@ instance ideal_powers_initial [hR : IsNoetherian R R] : apply Relation.ReflTransGen.single -- The inclusions `J^n1 ≤ J'` and `J^n2 ≤ J'` always form a triangle, based on -- which exponent is larger. - cases' le_total (unop j1.left) (unop j2.left) with h h + rcases le_total (unop j1.left) (unop j2.left) with h | h right; exact ⟨CostructuredArrow.homMk (homOfLE h).op (AsTrue.get trivial)⟩ left; exact ⟨CostructuredArrow.homMk (homOfLE h).op (AsTrue.get trivial)⟩ #align local_cohomology.ideal_powers_initial localCohomology.ideal_powers_initial diff --git a/Mathlib/Algebra/Lie/Nilpotent.lean b/Mathlib/Algebra/Lie/Nilpotent.lean index e778405f8bd04..8549499ddc4d2 100644 --- a/Mathlib/Algebra/Lie/Nilpotent.lean +++ b/Mathlib/Algebra/Lie/Nilpotent.lean @@ -151,7 +151,7 @@ theorem eventually_iInf_lowerCentralSeries_eq [IsArtinian R M] : obtain ⟨n, hn : ∀ m, n ≤ m → lowerCentralSeries R L M n = lowerCentralSeries R L M m⟩ := WellFounded.monotone_chain_condition.mp h_wf ⟨_, antitone_lowerCentralSeries R L M⟩ refine Filter.eventually_atTop.mpr ⟨n, fun l hl ↦ le_antisymm (iInf_le _ _) (le_iInf fun m ↦ ?_)⟩ - cases' le_or_lt l m with h h + rcases le_or_lt l m with h | h · rw [← hn _ hl, ← hn _ (hl.trans h)] · exact antitone_lowerCentralSeries R L M (le_of_lt h) diff --git a/Mathlib/Algebra/Module/Torsion.lean b/Mathlib/Algebra/Module/Torsion.lean index d9222cfde4e50..e9982ba7de835 100644 --- a/Mathlib/Algebra/Module/Torsion.lean +++ b/Mathlib/Algebra/Module/Torsion.lean @@ -394,7 +394,7 @@ variable (hp : (S : Set ι).Pairwise fun i j => p i ⊔ p j = ⊤) -- Porting note: mem_iSup_finset_iff_exists_sum now requires DecidableEq ι theorem iSup_torsionBySet_ideal_eq_torsionBySet_iInf [DecidableEq ι] : ⨆ i ∈ S, torsionBySet R M (p i) = torsionBySet R M ↑(⨅ i ∈ S, p i) := by - cases' S.eq_empty_or_nonempty with h h + rcases S.eq_empty_or_nonempty with h | h · simp only [h] -- Porting note: converts were not cooperating convert iSup_emptyset (f := fun i => torsionBySet R M (p i)) <;> simp diff --git a/Mathlib/Algebra/Order/Field/Basic.lean b/Mathlib/Algebra/Order/Field/Basic.lean index 078231becfd77..94767a43c7429 100644 --- a/Mathlib/Algebra/Order/Field/Basic.lean +++ b/Mathlib/Algebra/Order/Field/Basic.lean @@ -315,7 +315,7 @@ theorem inv_lt_one_iff_of_pos (h₀ : 0 < a) : a⁻¹ < 1 ↔ 1 < a := #align inv_lt_one_iff_of_pos inv_lt_one_iff_of_pos theorem inv_lt_one_iff : a⁻¹ < 1 ↔ a ≤ 0 ∨ 1 < a := by - cases' le_or_lt a 0 with ha ha + rcases le_or_lt a 0 with ha | ha · simp [ha, (inv_nonpos.2 ha).trans_lt zero_lt_one] · simp only [ha.not_le, false_or_iff, inv_lt_one_iff_of_pos ha] #align inv_lt_one_iff inv_lt_one_iff diff --git a/Mathlib/Algebra/Order/Floor.lean b/Mathlib/Algebra/Order/Floor.lean index 983e25d54d49b..3dbf3c2ac4706 100644 --- a/Mathlib/Algebra/Order/Floor.lean +++ b/Mathlib/Algebra/Order/Floor.lean @@ -466,7 +466,7 @@ theorem floor_sub_nat [Sub α] [OrderedSub α] [ExistsAddOfLE α] (a : α) (n : ⌊a - n⌋₊ = ⌊a⌋₊ - n := by obtain ha | ha := le_total a 0 · rw [floor_of_nonpos ha, floor_of_nonpos (tsub_nonpos_of_le (ha.trans n.cast_nonneg)), zero_tsub] - cases' le_total a n with h h + rcases le_total a n with h | h · rw [floor_of_nonpos (tsub_nonpos_of_le h), eq_comm, tsub_eq_zero_iff_le] exact Nat.cast_le.1 ((Nat.floor_le ha).trans h) · rw [eq_tsub_iff_add_eq_of_le (le_floor h), ← floor_add_nat _, tsub_add_cancel_of_le h] @@ -531,7 +531,7 @@ variable [LinearOrderedSemifield α] [FloorSemiring α] -- TODO: should these lemmas be `simp`? `norm_cast`? theorem floor_div_nat (a : α) (n : ℕ) : ⌊a / n⌋₊ = ⌊a⌋₊ / n := by - cases' le_total a 0 with ha ha + rcases le_total a 0 with ha | ha · rw [floor_of_nonpos, floor_of_nonpos ha] · simp apply div_nonpos_of_nonpos_of_nonneg ha n.cast_nonneg @@ -1349,7 +1349,7 @@ theorem preimage_ceil_singleton (m : ℤ) : (ceil : α → ℤ) ⁻¹' {m} = Ioc #align int.preimage_ceil_singleton Int.preimage_ceil_singleton theorem fract_eq_zero_or_add_one_sub_ceil (a : α) : fract a = 0 ∨ fract a = a + 1 - (⌈a⌉ : α) := by - cases' eq_or_ne (fract a) 0 with ha ha + rcases eq_or_ne (fract a) 0 with ha | ha · exact Or.inl ha right suffices (⌈a⌉ : α) = ⌊a⌋ + 1 by diff --git a/Mathlib/Algebra/Order/Group/Abs.lean b/Mathlib/Algebra/Order/Group/Abs.lean index 99a578fa0f03b..b9979e3cf35ec 100644 --- a/Mathlib/Algebra/Order/Group/Abs.lean +++ b/Mathlib/Algebra/Order/Group/Abs.lean @@ -146,7 +146,7 @@ theorem abs_pos_of_neg (h : a < 0) : 0 < |a| := #align abs_pos_of_neg abs_pos_of_neg theorem neg_abs_le_self (a : α) : -|a| ≤ a := by - cases' le_total 0 a with h h + rcases le_total 0 a with h | h · calc -|a| = -a := congr_arg Neg.neg (abs_of_nonneg h) _ ≤ 0 := neg_nonpos.mpr h @@ -206,7 +206,7 @@ theorem lt_of_abs_lt (h : |a| < b) : a < b := #align lt_of_abs_lt lt_of_abs_lt theorem max_sub_min_eq_abs' (a b : α) : max a b - min a b = |a - b| := by - cases' le_total a b with ab ba + rcases le_total a b with ab | ba · rw [max_eq_right ab, min_eq_left ab, abs_of_nonpos, neg_sub] rwa [sub_nonpos] · rw [max_eq_left ba, min_eq_right ba, abs_of_nonneg] diff --git a/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean b/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean index 1985000eae8b8..3384afbe32afb 100644 --- a/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean +++ b/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean @@ -349,9 +349,9 @@ instance (priority := 100) CanonicallyLinearOrderedCommMonoid.semilatticeSup : S @[to_additive] theorem min_mul_distrib (a b c : α) : min a (b * c) = min a (min a b * min a c) := by - cases' le_total a b with hb hb + rcases le_total a b with hb | hb · simp [hb, le_mul_right] - · cases' le_total a c with hc hc + · rcases le_total a c with hc | hc · simp [hc, le_mul_left] · simp [hb, hc] #align min_mul_distrib min_mul_distrib diff --git a/Mathlib/Algebra/Order/Monoid/MinMax.lean b/Mathlib/Algebra/Order/Monoid/MinMax.lean index 9e7f45fb08a9b..471ad32b95c74 100644 --- a/Mathlib/Algebra/Order/Monoid/MinMax.lean +++ b/Mathlib/Algebra/Order/Monoid/MinMax.lean @@ -23,7 +23,8 @@ variable {α β : Type*} @[to_additive] theorem fn_min_mul_fn_max [LinearOrder α] [CommSemigroup β] (f : α → β) (n m : α) : - f (min n m) * f (max n m) = f n * f m := by cases' le_total n m with h h <;> simp [h, mul_comm] + f (min n m) * f (max n m) = f n * f m := by + rcases le_total n m with h | h <;> simp [h, mul_comm] #align fn_min_mul_fn_max fn_min_mul_fn_max #align fn_min_add_fn_max fn_min_add_fn_max diff --git a/Mathlib/Algebra/Order/Ring/Abs.lean b/Mathlib/Algebra/Order/Ring/Abs.lean index bad88dc014d28..56c757b6b3c26 100644 --- a/Mathlib/Algebra/Order/Ring/Abs.lean +++ b/Mathlib/Algebra/Order/Ring/Abs.lean @@ -32,7 +32,7 @@ theorem abs_two : |(2 : α)| = 2 := theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))] - cases' le_total a 0 with ha ha <;> cases' le_total b 0 with hb hb <;> + rcases le_total a 0 with ha | ha <;> rcases le_total b 0 with hb | hb <;> simp only [abs_of_nonpos, abs_of_nonneg, true_or_iff, or_true_iff, eq_self_iff_true, neg_mul, mul_neg, neg_neg, *] #align abs_mul abs_mul diff --git a/Mathlib/Algebra/Order/Sub/Canonical.lean b/Mathlib/Algebra/Order/Sub/Canonical.lean index 3840aa9483641..e195d76d1368c 100644 --- a/Mathlib/Algebra/Order/Sub/Canonical.lean +++ b/Mathlib/Algebra/Order/Sub/Canonical.lean @@ -428,7 +428,7 @@ theorem tsub_pos_iff_lt : 0 < a - b ↔ b < a := by rw [tsub_pos_iff_not_le, not #align tsub_pos_iff_lt tsub_pos_iff_lt theorem tsub_eq_tsub_min (a b : α) : a - b = a - min a b := by - cases' le_total a b with h h + rcases le_total a b with h | h · rw [min_eq_left h, tsub_self, tsub_eq_zero_of_le h] · rw [min_eq_right h] #align tsub_eq_tsub_min tsub_eq_tsub_min @@ -497,7 +497,7 @@ end Contra theorem tsub_add_eq_max : a - b + b = max a b := by - cases' le_total a b with h h + rcases le_total a b with h | h · rw [max_eq_right h, tsub_eq_zero_of_le h, zero_add] · rw [max_eq_left h, tsub_add_cancel_of_le h] #align tsub_add_eq_max tsub_add_eq_max @@ -506,7 +506,7 @@ theorem add_tsub_eq_max : a + (b - a) = max a b := by rw [add_comm, max_comm, ts #align add_tsub_eq_max add_tsub_eq_max theorem tsub_min : a - min a b = a - b := by - cases' le_total a b with h h + rcases le_total a b with h | h · rw [min_eq_left h, tsub_self, tsub_eq_zero_of_le h] · rw [min_eq_right h] #align tsub_min tsub_min diff --git a/Mathlib/Algebra/Order/ToIntervalMod.lean b/Mathlib/Algebra/Order/ToIntervalMod.lean index d568d1ebef8d4..d5a5aed5b96c2 100644 --- a/Mathlib/Algebra/Order/ToIntervalMod.lean +++ b/Mathlib/Algebra/Order/ToIntervalMod.lean @@ -863,7 +863,7 @@ private theorem toIxxMod_cyclic_left {x₁ x₂ x₃ : α} (h : toIcoMod hp x₁ · obtain ⟨z, hd⟩ : ∃ z : ℤ, x₂ = x₂' + z • p := ((toIcoMod_eq_iff hp).1 rfl).2 rw [hd, toIocMod_add_zsmul', toIcoMod_add_zsmul', add_le_add_iff_right] assumption -- Porting note: was `simpa` - cases' le_or_lt x₃' (x₁ + p) with h₃₁ h₁₃ + rcases le_or_lt x₃' (x₁ + p) with h₃₁ | h₁₃ · suffices hIoc₂₁ : toIocMod hp x₂' x₁ = x₁ + p · exact hIoc₂₁.symm.trans_ge h₃₁ apply (toIocMod_eq_iff hp).2 diff --git a/Mathlib/Algebra/Polynomial/BigOperators.lean b/Mathlib/Algebra/Polynomial/BigOperators.lean index 253fa061b07c3..6cead554cb7a0 100644 --- a/Mathlib/Algebra/Polynomial/BigOperators.lean +++ b/Mathlib/Algebra/Polynomial/BigOperators.lean @@ -99,7 +99,7 @@ theorem coeff_list_prod_of_natDegree_le (l : List S[X]) (n : ℕ) (hl : ∀ p simpa using hl' have hdn : natDegree hd ≤ n := hl _ (List.mem_cons_self _ _) rcases hdn.eq_or_lt with (rfl | hdn') - · cases' h.eq_or_lt with h' h' + · rcases h.eq_or_lt with h' | h' · rw [← h', coeff_mul_degree_add_degree, leadingCoeff, leadingCoeff] · rw [coeff_eq_zero_of_natDegree_lt, coeff_eq_zero_of_natDegree_lt h', mul_zero] exact natDegree_mul_le.trans_lt (add_lt_add_left h' _) diff --git a/Mathlib/Algebra/Tropical/Basic.lean b/Mathlib/Algebra/Tropical/Basic.lean index c595d65b5d981..495b3e58845ad 100644 --- a/Mathlib/Algebra/Tropical/Basic.lean +++ b/Mathlib/Algebra/Tropical/Basic.lean @@ -512,10 +512,10 @@ instance covariant_swap_mul [LE R] [Add R] [CovariantClass R R (Function.swap ( instance covariant_add [LinearOrder R] : CovariantClass (Tropical R) (Tropical R) (· + ·) (· ≤ ·) := ⟨fun x y z h => by - cases' le_total x y with hx hy + rcases le_total x y with hx | hy · rw [add_eq_left hx, add_eq_left (hx.trans h)] · rw [add_eq_right hy] - cases' le_total x z with hx hx + rcases le_total x z with hx | hx · rwa [add_eq_left hx] · rwa [add_eq_right hx]⟩ #align tropical.covariant_add Tropical.covariant_add @@ -543,7 +543,7 @@ instance instDistribTropical [LinearOrder R] [Add R] [CovariantClass R R (· + theorem add_pow [LinearOrder R] [AddMonoid R] [CovariantClass R R (· + ·) (· ≤ ·)] [CovariantClass R R (Function.swap (· + ·)) (· ≤ ·)] (x y : Tropical R) (n : ℕ) : (x + y) ^ n = x ^ n + y ^ n := by - cases' le_total x y with h h + rcases le_total x y with h | h · rw [add_eq_left h, add_eq_left (pow_le_pow_left' h _)] · rw [add_eq_right h, add_eq_right (pow_le_pow_left' h _)] #align tropical.add_pow Tropical.add_pow diff --git a/Mathlib/AlgebraicGeometry/Properties.lean b/Mathlib/AlgebraicGeometry/Properties.lean index 12d814be4a97e..ebebbaabc6e30 100644 --- a/Mathlib/AlgebraicGeometry/Properties.lean +++ b/Mathlib/AlgebraicGeometry/Properties.lean @@ -215,7 +215,7 @@ instance [h : IsIntegral X] : IsDomain (X.presheaf.obj (op ⊤)) := instance (priority := 900) isReducedOfIsIntegral [IsIntegral X] : IsReduced X := by constructor intro U - cases' U.1.eq_empty_or_nonempty with h h + rcases U.1.eq_empty_or_nonempty with h | h · have : U = ⊥ := SetLike.ext' h haveI := CommRingCat.subsingleton_of_isTerminal (X.sheaf.isTerminalOfEqEmpty this) change _root_.IsReduced (X.sheaf.val.obj (op U)) diff --git a/Mathlib/AlgebraicTopology/SimplexCategory.lean b/Mathlib/AlgebraicTopology/SimplexCategory.lean index b513e933a9945..563909dab4b5d 100644 --- a/Mathlib/AlgebraicTopology/SimplexCategory.lean +++ b/Mathlib/AlgebraicTopology/SimplexCategory.lean @@ -642,7 +642,7 @@ theorem eq_σ_comp_of_not_injective {n : ℕ} {Δ' : SimplexCategory} (θ : mk ( by_cases h : x < y · exact ⟨x, y, ⟨h₁, h⟩⟩ · refine' ⟨y, x, ⟨h₁.symm, _⟩⟩ - cases' lt_or_eq_of_le (not_lt.mp h) with h' h' + rcases lt_or_eq_of_le (not_lt.mp h) with h' | h' · exact h' · exfalso exact h₂ h'.symm diff --git a/Mathlib/Analysis/Analytic/Basic.lean b/Mathlib/Analysis/Analytic/Basic.lean index 8c3d0c56a1e1d..2aaf73ecbaa09 100644 --- a/Mathlib/Analysis/Analytic/Basic.lean +++ b/Mathlib/Analysis/Analytic/Basic.lean @@ -928,7 +928,7 @@ theorem HasFPowerSeriesOnBall.sum (h : HasFPowerSeriesOnBall f p x r) {y : E} /-- The sum of a converging power series is continuous in its disk of convergence. -/ protected theorem FormalMultilinearSeries.continuousOn [CompleteSpace F] : ContinuousOn p.sum (EMetric.ball 0 p.radius) := by - cases' (zero_le p.radius).eq_or_lt with h h + rcases (zero_le p.radius).eq_or_lt with h | h · simp [← h, continuousOn_empty] · exact (p.hasFPowerSeriesOnBall h).continuousOn #align formal_multilinear_series.continuous_on FormalMultilinearSeries.continuousOn diff --git a/Mathlib/Analysis/Asymptotics/Asymptotics.lean b/Mathlib/Analysis/Asymptotics/Asymptotics.lean index 25e7ceeafef91..973b31f560aab 100644 --- a/Mathlib/Analysis/Asymptotics/Asymptotics.lean +++ b/Mathlib/Analysis/Asymptotics/Asymptotics.lean @@ -1709,7 +1709,7 @@ theorem IsLittleO.of_pow {f : α → 𝕜} {g : α → R} {n : ℕ} (h : (f ^ n) theorem IsBigOWith.inv_rev {f : α → 𝕜} {g : α → 𝕜'} (h : IsBigOWith c l f g) (h₀ : ∀ᶠ x in l, f x = 0 → g x = 0) : IsBigOWith c l (fun x => (g x)⁻¹) fun x => (f x)⁻¹ := by refine' IsBigOWith.of_bound (h.bound.mp (h₀.mono fun x h₀ hle => _)) - cases' eq_or_ne (f x) 0 with hx hx + rcases eq_or_ne (f x) 0 with hx | hx · simp only [hx, h₀ hx, inv_zero, norm_zero, mul_zero, le_rfl] · have hc : 0 < c := pos_of_mul_pos_left ((norm_pos_iff.2 hx).trans_le hle) (norm_nonneg _) replace hle := inv_le_inv_of_le (norm_pos_iff.2 hx) hle diff --git a/Mathlib/Analysis/BoundedVariation.lean b/Mathlib/Analysis/BoundedVariation.lean index ba0263c323518..432611e0a648c 100644 --- a/Mathlib/Analysis/BoundedVariation.lean +++ b/Mathlib/Analysis/BoundedVariation.lean @@ -107,7 +107,7 @@ theorem sum_le (f : α → E) {s : Set α} (n : ℕ) {u : ℕ → α} (hu : Mono theorem sum_le_of_monotoneOn_Icc (f : α → E) {s : Set α} {m n : ℕ} {u : ℕ → α} (hu : MonotoneOn u (Icc m n)) (us : ∀ i ∈ Icc m n, u i ∈ s) : (∑ i in Finset.Ico m n, edist (f (u (i + 1))) (f (u i))) ≤ eVariationOn f s := by - cases' le_total n m with hnm hmn + rcases le_total n m with hnm | hmn · simp [Finset.Ico_eq_empty_of_le hnm] let π := projIcc m n hmn let v i := u (π i) diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean b/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean index 2e49d2cbe1bf6..5505f02d69c65 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean @@ -184,7 +184,7 @@ theorem injOn_setOf_mem_Icc_setOf_lower_eq (x : ι → ℝ) : exact π.eq_of_mem_of_mem h₁ h₂ hy₁ hy₂ intro i simp only [Set.ext_iff, mem_setOf] at H - cases' (hx₁.1 i).eq_or_lt with hi₁ hi₁ + rcases (hx₁.1 i).eq_or_lt with hi₁ | hi₁ · have hi₂ : J₂.lower i = x i := (H _).1 hi₁ have H₁ : x i < J₁.upper i := by simpa only [hi₁] using J₁.lower_lt_upper i have H₂ : x i < J₂.upper i := by simpa only [hi₂] using J₂.lower_lt_upper i diff --git a/Mathlib/Analysis/Calculus/Darboux.lean b/Mathlib/Analysis/Calculus/Darboux.lean index 4577748ce7317..383ac3f4c5799 100644 --- a/Mathlib/Analysis/Calculus/Darboux.lean +++ b/Mathlib/Analysis/Calculus/Darboux.lean @@ -78,7 +78,7 @@ theorem Set.OrdConnected.image_hasDerivWithinAt {s : Set ℝ} (hs : OrdConnected (hf : ∀ x ∈ s, HasDerivWithinAt f (f' x) s x) : OrdConnected (f' '' s) := by apply ordConnected_of_Ioo rintro _ ⟨a, ha, rfl⟩ _ ⟨b, hb, rfl⟩ - m ⟨hma, hmb⟩ - cases' le_total a b with hab hab + rcases le_total a b with hab | hab · have : Icc a b ⊆ s := hs.out ha hb rcases exists_hasDerivWithinAt_eq_of_gt_of_lt hab (fun x hx => (hf x <| this hx).mono this) hma hmb with @@ -154,4 +154,3 @@ theorem hasDerivWithinAt_forall_lt_or_forall_gt_of_forall_ne {s : Set ℝ} (hs : exact (hs.ordConnected.image_hasDerivWithinAt hf).out (mem_image_of_mem f' ha) (mem_image_of_mem f' hb) ⟨hma, hmb⟩ #align has_deriv_within_at_forall_lt_or_forall_gt_of_forall_ne hasDerivWithinAt_forall_lt_or_forall_gt_of_forall_ne - diff --git a/Mathlib/Analysis/Calculus/Deriv/ZPow.lean b/Mathlib/Analysis/Calculus/Deriv/ZPow.lean index a0fe4d6ba03c6..e5107ef17dafa 100644 --- a/Mathlib/Analysis/Calculus/Deriv/ZPow.lean +++ b/Mathlib/Analysis/Calculus/Deriv/ZPow.lean @@ -124,7 +124,7 @@ theorem iter_deriv_zpow (m : ℤ) (x : 𝕜) (k : ℕ) : theorem iter_deriv_pow (n : ℕ) (x : 𝕜) (k : ℕ) : deriv^[k] (fun x : 𝕜 => x ^ n) x = (∏ i in Finset.range k, ((n : 𝕜) - i)) * x ^ (n - k) := by simp only [← zpow_ofNat, iter_deriv_zpow, Int.cast_ofNat] - cases' le_or_lt k n with hkn hnk + rcases le_or_lt k n with hkn | hnk · rw [Int.ofNat_sub hkn] · have : (∏ i in Finset.range k, (n - i : 𝕜)) = 0 := Finset.prod_eq_zero (Finset.mem_range.2 hnk) (sub_self _) diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean index 7841016f61168..903806a99e403 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean @@ -152,7 +152,7 @@ theorem surjOn_closedBall_of_nonlinearRightInverse (hf : ApproximatesLinearOn f (f'symm : f'.NonlinearRightInverse) {ε : ℝ} {b : E} (ε0 : 0 ≤ ε) (hε : closedBall b ε ⊆ s) : SurjOn f (closedBall b ε) (closedBall (f b) (((f'symm.nnnorm : ℝ)⁻¹ - c) * ε)) := by intro y hy - cases' le_or_lt (f'symm.nnnorm : ℝ)⁻¹ c with hc hc + rcases le_or_lt (f'symm.nnnorm : ℝ)⁻¹ c with hc | hc · refine' ⟨b, by simp [ε0], _⟩ have : dist y (f b) ≤ 0 := (mem_closedBall.1 hy).trans (mul_nonpos_of_nonpos_of_nonneg (by linarith) ε0) diff --git a/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean b/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean index d20b6d31c7354..08fb9d05a9800 100644 --- a/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean +++ b/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean @@ -37,7 +37,7 @@ open scoped BigOperators that are not roots of `p` plus one. -/ theorem card_roots_toFinset_le_card_roots_derivative_diff_roots_succ (p : ℝ[X]) : p.roots.toFinset.card ≤ (p.derivative.roots.toFinset \ p.roots.toFinset).card + 1 := by - cases' eq_or_ne (derivative p) 0 with hp' hp' + rcases eq_or_ne (derivative p) 0 with hp' | hp' · rw [eq_C_of_derivative_eq_zero hp', roots_C, Multiset.toFinset_zero, Finset.card_empty] exact zero_le _ have hp : p ≠ 0 := ne_of_apply_ne derivative (by rwa [derivative_zero]) diff --git a/Mathlib/Analysis/Complex/PhragmenLindelof.lean b/Mathlib/Analysis/Complex/PhragmenLindelof.lean index 7cb39eef528b4..7bae38a3b8ecc 100644 --- a/Mathlib/Analysis/Complex/PhragmenLindelof.lean +++ b/Mathlib/Analysis/Complex/PhragmenLindelof.lean @@ -689,7 +689,7 @@ theorem right_half_plane_of_tendsto_zero_on_real (hd : DiffContOnCl ℂ f {z | 0 have hle : ∀ C', (∀ x : ℝ, 0 ≤ x → ‖f x‖ ≤ C') → ∀ z : ℂ, 0 ≤ z.re → ‖f z‖ ≤ max C C' := fun C' hC' z hz ↦ by rcases hexp with ⟨c, hc, B, hO⟩ - cases' le_total z.im 0 with h h + rcases le_total z.im 0 with h | h · refine quadrant_IV (hd.mono fun _ => And.left) ⟨c, hc, B, ?_⟩ (fun x hx => (hC' x hx).trans <| le_max_right _ _) (fun x _ => (him x).trans (le_max_left _ _)) hz h @@ -714,7 +714,7 @@ theorem right_half_plane_of_tendsto_zero_on_real (hd : DiffContOnCl ℂ f {z | 0 rw [Real.cocompact_eq, inf_sup_right, (disjoint_atBot_principal_Ici (0 : ℝ)).eq_bot, bot_sup_eq] exact (hre.norm.eventually <| ge_mem_nhds hlt).filter_mono inf_le_left - cases' le_or_lt ‖f x₀‖ C with h h + rcases le_or_lt ‖f x₀‖ C with h | h ·-- If `‖f x₀‖ ≤ C`, then `hle` implies the required estimate simpa only [max_eq_left h] using hle _ hmax · -- Otherwise, `‖f z‖ ≤ ‖f x₀‖` for all `z` in the right half-plane due to `hle`. diff --git a/Mathlib/Analysis/Complex/Schwarz.lean b/Mathlib/Analysis/Complex/Schwarz.lean index 6330c797b03ce..5f916b21f9c52 100644 --- a/Mathlib/Analysis/Complex/Schwarz.lean +++ b/Mathlib/Analysis/Complex/Schwarz.lean @@ -94,7 +94,7 @@ theorem norm_dslope_le_div_of_mapsTo_ball (hd : DifferentiableOn ℂ f (ball c R ‖dslope f c z‖ ≤ R₂ / R₁ := by have hR₁ : 0 < R₁ := nonempty_ball.1 ⟨z, hz⟩ have hR₂ : 0 < R₂ := nonempty_ball.1 ⟨f z, h_maps hz⟩ - cases' eq_or_ne (dslope f c z) 0 with hc hc + rcases eq_or_ne (dslope f c z) 0 with hc | hc · rw [hc, norm_zero]; exact div_nonneg hR₂.le hR₁.le rcases exists_dual_vector ℂ _ hc with ⟨g, hg, hgf⟩ have hg' : ‖g‖₊ = 1 := NNReal.eq hg diff --git a/Mathlib/Analysis/Convex/Integral.lean b/Mathlib/Analysis/Convex/Integral.lean index d725941f985da..07f1072851027 100644 --- a/Mathlib/Analysis/Convex/Integral.lean +++ b/Mathlib/Analysis/Convex/Integral.lean @@ -325,13 +325,13 @@ a.e., then either this function is a.e. equal to its average value, or the norm is strictly less than `C`. -/ theorem ae_eq_const_or_norm_average_lt_of_norm_le_const [StrictConvexSpace ℝ E] (h_le : ∀ᵐ x ∂μ, ‖f x‖ ≤ C) : f =ᵐ[μ] const α (⨍ x, f x ∂μ) ∨ ‖⨍ x, f x ∂μ‖ < C := by - cases' le_or_lt C 0 with hC0 hC0 + rcases le_or_lt C 0 with hC0 | hC0 · have : f =ᵐ[μ] 0 := h_le.mono fun x hx => norm_le_zero_iff.1 (hx.trans hC0) simp only [average_congr this, Pi.zero_apply, average_zero] exact Or.inl this by_cases hfi : Integrable f μ; swap · simp [average_eq, integral_undef hfi, hC0, ENNReal.toReal_pos_iff] - cases' (le_top : μ univ ≤ ∞).eq_or_lt with hμt hμt; · simp [average_eq, hμt, hC0] + rcases (le_top : μ univ ≤ ∞).eq_or_lt with hμt | hμt; · simp [average_eq, hμt, hC0] haveI : IsFiniteMeasure μ := ⟨hμt⟩ replace h_le : ∀ᵐ x ∂μ, f x ∈ closedBall (0 : E) C; · simpa only [mem_closedBall_zero_iff] simpa only [interior_closedBall _ hC0.ne', mem_ball_zero_iff] using @@ -345,7 +345,7 @@ strictly less than `(μ univ).toReal * C`. -/ theorem ae_eq_const_or_norm_integral_lt_of_norm_le_const [StrictConvexSpace ℝ E] [IsFiniteMeasure μ] (h_le : ∀ᵐ x ∂μ, ‖f x‖ ≤ C) : f =ᵐ[μ] const α (⨍ x, f x ∂μ) ∨ ‖∫ x, f x ∂μ‖ < (μ univ).toReal * C := by - cases' eq_or_ne μ 0 with h₀ h₀; · left; simp [h₀, EventuallyEq] + rcases eq_or_ne μ 0 with h₀ | h₀; · left; simp [h₀, EventuallyEq] have hμ : 0 < (μ univ).toReal := by simp [ENNReal.toReal_pos_iff, pos_iff_ne_zero, h₀, measure_lt_top] refine' (ae_eq_const_or_norm_average_lt_of_norm_le_const h_le).imp_right fun H => _ diff --git a/Mathlib/Analysis/Convex/Segment.lean b/Mathlib/Analysis/Convex/Segment.lean index 73cdae64cf075..d239ef0cefc71 100644 --- a/Mathlib/Analysis/Convex/Segment.lean +++ b/Mathlib/Analysis/Convex/Segment.lean @@ -489,7 +489,7 @@ section LinearOrderedAddCommMonoid variable [LinearOrderedAddCommMonoid E] [Module 𝕜 E] [OrderedSMul 𝕜 E] {a b : 𝕜} theorem segment_subset_uIcc (x y : E) : [x -[𝕜] y] ⊆ uIcc x y := by - cases' le_total x y with h h + rcases le_total x y with h | h · rw [uIcc_of_le h] exact segment_subset_Icc h · rw [uIcc_of_ge h, segment_symm] @@ -542,7 +542,7 @@ theorem openSegment_eq_Ioo (h : x < y) : openSegment 𝕜 x y = Ioo x y := #align open_segment_eq_Ioo openSegment_eq_Ioo theorem segment_eq_Icc' (x y : 𝕜) : [x -[𝕜] y] = Icc (min x y) (max x y) := by - cases' le_total x y with h h + rcases le_total x y with h | h · rw [segment_eq_Icc h, max_eq_right h, min_eq_left h] · rw [segment_symm, segment_eq_Icc h, max_eq_left h, min_eq_right h] #align segment_eq_Icc' segment_eq_Icc' diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean index 662229221fc00..2cc4fc79a0f39 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean @@ -115,7 +115,7 @@ theorem one_add_mul_self_lt_rpow_one_add {s : ℝ} (hs : -1 ≤ s) (hs' : s ≠ · have : p ≠ 0 := by positivity simpa [zero_rpow this] have hs1 : 0 < 1 + s := by linarith - cases' le_or_lt (1 + p * s) 0 with hs2 hs2 + rcases le_or_lt (1 + p * s) 0 with hs2 | hs2 · exact hs2.trans_lt (rpow_pos_of_pos hs1 _) rw [rpow_def_of_pos hs1, ← exp_log hs2] apply exp_strictMono diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean index 101bc4ca6a098..71d219b7bb727 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean @@ -76,7 +76,7 @@ theorem int_prod_range_nonneg (m : ℤ) (n : ℕ) (hn : Even n) : rw [← two_mul, Nat.succ_eq_add_one, mul_add, mul_one, ← one_add_one_eq_two, ← add_assoc, Finset.prod_range_succ, Finset.prod_range_succ, mul_assoc] refine' mul_nonneg ihn _; generalize (1 + 1) * n = k - cases' le_or_lt m k with hmk hmk + rcases le_or_lt m k with hmk | hmk · have : m ≤ k + 1 := hmk.trans (lt_add_one (k : ℤ)).le convert mul_nonneg_of_nonpos_of_nonpos (sub_nonpos_of_le hmk) _ convert sub_nonpos_of_le this @@ -135,7 +135,7 @@ theorem deriv_sqrt_mul_log' : theorem deriv2_sqrt_mul_log (x : ℝ) : deriv^[2] (fun x => sqrt x * log x) x = -log x / (4 * sqrt x ^ 3) := by simp only [Nat.iterate, deriv_sqrt_mul_log'] - cases' le_or_lt x 0 with hx hx + rcases le_or_lt x 0 with hx | hx · rw [sqrt_eq_zero_of_nonpos hx, zero_pow zero_lt_three, mul_zero, div_zero] refine' HasDerivWithinAt.deriv_eq_zero _ (uniqueDiffOn_Iic 0 x hx) refine' (hasDerivWithinAt_const _ _ 0).congr_of_mem (fun x hx => _) hx diff --git a/Mathlib/Analysis/Convex/StrictConvexSpace.lean b/Mathlib/Analysis/Convex/StrictConvexSpace.lean index 3c9b6ab885409..534f1354d8e76 100644 --- a/Mathlib/Analysis/Convex/StrictConvexSpace.lean +++ b/Mathlib/Analysis/Convex/StrictConvexSpace.lean @@ -80,7 +80,7 @@ variable (𝕜 : Type*) {E : Type*} [NormedLinearOrderedField 𝕜] [NormedAddCo /-- A closed ball in a strictly convex space is strictly convex. -/ theorem strictConvex_closedBall [StrictConvexSpace 𝕜 E] (x : E) (r : ℝ) : StrictConvex 𝕜 (closedBall x r) := by - cases' le_or_lt r 0 with hr hr + rcases le_or_lt r 0 with hr | hr · exact (subsingleton_closedBall x hr).strictConvex rw [← vadd_closedBall_zero] exact (StrictConvexSpace.strictConvex_closedBall r hr).vadd _ diff --git a/Mathlib/Analysis/MeanInequalities.lean b/Mathlib/Analysis/MeanInequalities.lean index 7310ec13f143f..6b91aebbbf25f 100644 --- a/Mathlib/Analysis/MeanInequalities.lean +++ b/Mathlib/Analysis/MeanInequalities.lean @@ -152,7 +152,7 @@ theorem geom_mean_weighted_of_constant (w z : ι → ℝ) (x : ℝ) (hw : ∀ i calc ∏ i in s, z i ^ w i = ∏ i in s, x ^ w i := by refine' prod_congr rfl fun i hi => _ - cases' eq_or_ne (w i) 0 with h₀ h₀ + rcases eq_or_ne (w i) 0 with h₀ | h₀ · rw [h₀, rpow_zero, rpow_zero] · rw [hx i hi h₀] _ = x := by @@ -170,7 +170,7 @@ theorem arith_mean_weighted_of_constant (w z : ι → ℝ) (x : ℝ) (hw' : ∑ calc ∑ i in s, w i * z i = ∑ i in s, w i * x := by refine' sum_congr rfl fun i hi => _ - cases' eq_or_ne (w i) 0 with hwi hwi + rcases eq_or_ne (w i) 0 with hwi | hwi · rw [hwi, zero_mul, zero_mul] · rw [hx i hi hwi] _ = x := by rw [← sum_mul, hw', one_mul] diff --git a/Mathlib/Analysis/Normed/Group/AddCircle.lean b/Mathlib/Analysis/Normed/Group/AddCircle.lean index 886689a865a7a..45271d0a2477e 100644 --- a/Mathlib/Analysis/Normed/Group/AddCircle.lean +++ b/Mathlib/Analysis/Normed/Group/AddCircle.lean @@ -199,7 +199,7 @@ theorem coe_real_preimage_closedBall_eq_iUnion (x ε : ℝ) : theorem coe_real_preimage_closedBall_inter_eq {x ε : ℝ} (s : Set ℝ) (hs : s ⊆ closedBall x (|p| / 2)) : (↑) ⁻¹' closedBall (x : AddCircle p) ε ∩ s = if ε < |p| / 2 then closedBall x ε ∩ s else s := by - cases' le_or_lt (|p| / 2) ε with hε hε + rcases le_or_lt (|p| / 2) ε with hε | hε · rcases eq_or_ne p 0 with (rfl | hp) · simp only [abs_zero, zero_div] at hε simp only [not_lt.mpr hε, coe_real_preimage_closedBall_period_zero, abs_zero, zero_div, diff --git a/Mathlib/Analysis/Normed/Group/Basic.lean b/Mathlib/Analysis/Normed/Group/Basic.lean index da7618a5bac7e..89b92050366a9 100644 --- a/Mathlib/Analysis/Normed/Group/Basic.lean +++ b/Mathlib/Analysis/Normed/Group/Basic.lean @@ -1213,7 +1213,7 @@ theorem Filter.Tendsto.op_one_isBoundedUnder_le' {f : α → E} {g : α → F} { rcases exists_pos_mul_lt ε₀ (A * C) with ⟨δ, δ₀, hδ⟩ filter_upwards [hf δ δ₀, hC] with i hf hg refine' (h_op _ _).trans_lt _ - cases' le_total A 0 with hA hA + rcases le_total A 0 with hA | hA · exact (mul_nonpos_of_nonpos_of_nonneg (mul_nonpos_of_nonpos_of_nonneg hA <| norm_nonneg' _) <| norm_nonneg' _).trans_lt ε₀ calc diff --git a/Mathlib/Analysis/NormedSpace/AddTorsor.lean b/Mathlib/Analysis/NormedSpace/AddTorsor.lean index 2ce38ffeb10d8..5bf830a9136bd 100644 --- a/Mathlib/Analysis/NormedSpace/AddTorsor.lean +++ b/Mathlib/Analysis/NormedSpace/AddTorsor.lean @@ -255,7 +255,7 @@ variable (𝕜) theorem eventually_homothety_mem_of_mem_interior (x : Q) {s : Set Q} {y : Q} (hy : y ∈ interior s) : ∀ᶠ δ in 𝓝 (1 : 𝕜), homothety x δ y ∈ s := by rw [(NormedAddCommGroup.nhds_basis_norm_lt (1 : 𝕜)).eventually_iff] - cases' eq_or_ne y x with h h + rcases eq_or_ne y x with h | h · use 1 simp [h.symm, interior_subset hy] have hxy : 0 < ‖y -ᵥ x‖ := by rwa [norm_pos_iff, vsub_ne_zero] diff --git a/Mathlib/Analysis/NormedSpace/RieszLemma.lean b/Mathlib/Analysis/NormedSpace/RieszLemma.lean index 564a0d5dac40c..17d6fecdc1444 100644 --- a/Mathlib/Analysis/NormedSpace/RieszLemma.lean +++ b/Mathlib/Analysis/NormedSpace/RieszLemma.lean @@ -109,7 +109,7 @@ theorem riesz_lemma_of_norm_lt {c : 𝕜} (hc : 1 < ‖c‖) {R : ℝ} (hR : ‖ theorem Metric.closedBall_infDist_compl_subset_closure {x : F} {s : Set F} (hx : x ∈ s) : closedBall x (infDist x sᶜ) ⊆ closure s := by - cases' eq_or_ne (infDist x sᶜ) 0 with h₀ h₀ + rcases eq_or_ne (infDist x sᶜ) 0 with h₀ | h₀ · rw [h₀, closedBall_zero'] exact closure_mono (singleton_subset_iff.2 hx) · rw [← closure_ball x h₀] diff --git a/Mathlib/Analysis/ODE/PicardLindelof.lean b/Mathlib/Analysis/ODE/PicardLindelof.lean index 3916ef0f0ec84..e89de73ef5015 100644 --- a/Mathlib/Analysis/ODE/PicardLindelof.lean +++ b/Mathlib/Analysis/ODE/PicardLindelof.lean @@ -126,7 +126,7 @@ theorem tDist_nonneg : 0 ≤ v.tDist := theorem dist_t₀_le (t : Icc v.tMin v.tMax) : dist t v.t₀ ≤ v.tDist := by rw [Subtype.dist_eq, Real.dist_eq] - cases' le_total t v.t₀ with ht ht + rcases le_total t v.t₀ with ht | ht · rw [abs_of_nonpos (sub_nonpos.2 <| Subtype.coe_le_coe.2 ht), neg_sub] exact (sub_le_sub_left t.2.1 _).trans (le_max_right _ _) · rw [abs_of_nonneg (sub_nonneg.2 <| Subtype.coe_le_coe.2 ht)] diff --git a/Mathlib/Analysis/PSeries.lean b/Mathlib/Analysis/PSeries.lean index 3739a9197021f..71aaee2926c4b 100644 --- a/Mathlib/Analysis/PSeries.lean +++ b/Mathlib/Analysis/PSeries.lean @@ -161,7 +161,7 @@ if and only if `1 < p`. -/ @[simp] theorem Real.summable_nat_rpow_inv {p : ℝ} : Summable (fun n => ((n : ℝ) ^ p)⁻¹ : ℕ → ℝ) ↔ 1 < p := by - cases' le_or_lt 0 p with hp hp + rcases le_or_lt 0 p with hp | hp /- Cauchy condensation test applies only to antitone sequences, so we consider the cases `0 ≤ p` and `p < 0` separately. -/ · rw [← summable_condensed_iff_of_nonneg] diff --git a/Mathlib/Analysis/SpecialFunctions/CompareExp.lean b/Mathlib/Analysis/SpecialFunctions/CompareExp.lean index 7e6bae15b2529..09a89fb93a389 100644 --- a/Mathlib/Analysis/SpecialFunctions/CompareExp.lean +++ b/Mathlib/Analysis/SpecialFunctions/CompareExp.lean @@ -144,7 +144,7 @@ theorem isLittleO_log_abs_re (hl : IsExpCmpFilter l) : (fun z => Real.log (abs z filter_upwards [isLittleO_iff_nat_mul_le'.1 hl.isLittleO_log_re_re n, hl.abs_im_pow_eventuallyLE_exp_re n, hl.tendsto_re.eventually_gt_atTop 1] with z hre him h₁ - cases' le_total |z.im| z.re with hle hle + rcases le_total |z.im| z.re with hle | hle · rwa [max_eq_left hle] · have H : 1 < |z.im| := h₁.trans_le hle norm_cast at * diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean index 5f325e53e83ac..6a8f900b4f81e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean @@ -332,10 +332,10 @@ theorem arg_inv (x : ℂ) : arg x⁻¹ = if arg x = π then π else -arg x := by #align complex.arg_inv Complex.arg_inv theorem arg_le_pi_div_two_iff {z : ℂ} : arg z ≤ π / 2 ↔ 0 ≤ re z ∨ im z < 0 := by - cases' le_or_lt 0 (re z) with hre hre + rcases le_or_lt 0 (re z) with hre | hre · simp only [hre, arg_of_re_nonneg hre, Real.arcsin_le_pi_div_two, true_or_iff] simp only [hre.not_le, false_or_iff] - cases' le_or_lt 0 (im z) with him him + rcases le_or_lt 0 (im z) with him | him · simp only [him.not_lt] rw [iff_false_iff, not_le, arg_of_re_neg_of_im_nonneg hre him, ← sub_lt_iff_lt_add, half_sub, Real.neg_pi_div_two_lt_arcsin, neg_im, neg_div, neg_lt_neg_iff, div_lt_one, ← @@ -347,10 +347,10 @@ theorem arg_le_pi_div_two_iff {z : ℂ} : arg z ≤ π / 2 ↔ 0 ≤ re z ∨ im #align complex.arg_le_pi_div_two_iff Complex.arg_le_pi_div_two_iff theorem neg_pi_div_two_le_arg_iff {z : ℂ} : -(π / 2) ≤ arg z ↔ 0 ≤ re z ∨ 0 ≤ im z := by - cases' le_or_lt 0 (re z) with hre hre + rcases le_or_lt 0 (re z) with hre | hre · simp only [hre, arg_of_re_nonneg hre, Real.neg_pi_div_two_le_arcsin, true_or_iff] simp only [hre.not_le, false_or_iff] - cases' le_or_lt 0 (im z) with him him + rcases le_or_lt 0 (im z) with him | him · simp only [him] rw [iff_true_iff, arg_of_re_neg_of_im_nonneg hre him] exact (Real.neg_pi_div_two_le_arcsin _).trans (le_add_of_nonneg_right Real.pi_pos.le) diff --git a/Mathlib/Analysis/SpecialFunctions/Integrals.lean b/Mathlib/Analysis/SpecialFunctions/Integrals.lean index ce8ad9de3f0fa..7df44514485bb 100644 --- a/Mathlib/Analysis/SpecialFunctions/Integrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/Integrals.lean @@ -412,7 +412,7 @@ theorem integral_pow : ∫ x in a..b, x ^ n = (b ^ (n + 1) - a ^ (n + 1)) / (n + /-- Integral of `|x - a| ^ n` over `Ι a b`. This integral appears in the proof of the Picard-Lindelöf/Cauchy-Lipschitz theorem. -/ theorem integral_pow_abs_sub_uIoc : ∫ x in Ι a b, |x - a| ^ n = |b - a| ^ (n + 1) / (n + 1) := by - cases' le_or_lt a b with hab hab + rcases le_or_lt a b with hab | hab · calc ∫ x in Ι a b, |x - a| ^ n = ∫ x in a..b, |x - a| ^ n := by rw [uIoc_of_le hab, ← integral_of_le hab] diff --git a/Mathlib/Analysis/SpecialFunctions/Polynomials.lean b/Mathlib/Analysis/SpecialFunctions/Polynomials.lean index d29dda5eb8260..7fbf55ba3d570 100644 --- a/Mathlib/Analysis/SpecialFunctions/Polynomials.lean +++ b/Mathlib/Analysis/SpecialFunctions/Polynomials.lean @@ -83,7 +83,7 @@ theorem tendsto_atBot_of_leadingCoeff_nonpos (hdeg : 0 < P.degree) (hnps : P.lea theorem abs_tendsto_atTop (hdeg : 0 < P.degree) : Tendsto (fun x => abs <| eval x P) atTop atTop := by - cases' le_total 0 P.leadingCoeff with hP hP + rcases le_total 0 P.leadingCoeff with hP | hP · exact tendsto_abs_atTop_atTop.comp (P.tendsto_atTop_of_leadingCoeff_nonneg hdeg hP) · exact tendsto_abs_atBot_atTop.comp (P.tendsto_atBot_of_leadingCoeff_nonpos hdeg hP) #align polynomial.abs_tendsto_at_top Polynomial.abs_tendsto_atTop diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean index 58b55feae704e..a5323ca6ac8ca 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean @@ -166,7 +166,7 @@ theorem abs_rpow_of_nonneg {x y : ℝ} (hx_nonneg : 0 ≤ x) : |x ^ y| = |x| ^ y #align real.abs_rpow_of_nonneg Real.abs_rpow_of_nonneg theorem abs_rpow_le_abs_rpow (x y : ℝ) : |x ^ y| ≤ |x| ^ y := by - cases' le_or_lt 0 x with hx hx + rcases le_or_lt 0 x with hx | hx · rw [abs_rpow_of_nonneg hx] · rw [abs_of_neg hx, rpow_def_of_neg hx, rpow_def_of_pos (neg_pos.2 hx), log_neg_eq_log, abs_mul, abs_of_pos (exp_pos _)] @@ -297,7 +297,7 @@ theorem abs_cpow_of_ne_zero {z : ℂ} (hz : z ≠ 0) (w : ℂ) : theorem abs_cpow_of_imp {z w : ℂ} (h : z = 0 → w.re = 0 → w = 0) : abs (z ^ w) = abs z ^ w.re / Real.exp (arg z * im w) := by rcases ne_or_eq z 0 with (hz | rfl) <;> [exact abs_cpow_of_ne_zero hz w; rw [map_zero]] - cases' eq_or_ne w.re 0 with hw hw + rcases eq_or_ne w.re 0 with hw | hw · simp [hw, h rfl hw] · rw [Real.zero_rpow hw, zero_div, zero_cpow, map_zero] exact ne_of_apply_ne re hw diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean index eedb24944e24c..fad79d5c6a50c 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean @@ -72,7 +72,7 @@ theorem continuousOn_tan_Ioo : ContinuousOn tan (Ioo (-(π / 2)) (π / 2)) := by simp only [and_imp, mem_Ioo, mem_setOf_eq, Ne.def] rw [cos_eq_zero_iff] rintro hx_gt hx_lt ⟨r, hxr_eq⟩ - cases' le_or_lt 0 r with h h + rcases le_or_lt 0 r with h | h · rw [lt_iff_not_ge] at hx_lt refine' hx_lt _ rw [hxr_eq, ← one_mul (π / 2), mul_div_assoc, ge_iff_le, mul_le_mul_right (half_pos pi_pos)] diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Inverse.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Inverse.lean index a13666b448a01..25b38a59ca951 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Inverse.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Inverse.lean @@ -133,9 +133,9 @@ theorem arcsin_of_le_neg_one {x : ℝ} (hx : x ≤ -1) : arcsin x = -(π / 2) := @[simp] theorem arcsin_neg (x : ℝ) : arcsin (-x) = -arcsin x := by - cases' le_total x (-1) with hx₁ hx₁ + rcases le_total x (-1) with hx₁ | hx₁ · rw [arcsin_of_le_neg_one hx₁, neg_neg, arcsin_of_one_le (le_neg.2 hx₁)] - cases' le_total 1 x with hx₂ hx₂ + rcases le_total 1 x with hx₂ | hx₂ · rw [arcsin_of_one_le hx₂, arcsin_of_le_neg_one (neg_le_neg hx₂)] refine' arcsin_eq_of_sin_eq _ _ · rw [sin_neg, sin_arcsin hx₁ hx₂] @@ -149,7 +149,7 @@ theorem arcsin_le_iff_le_sin {x y : ℝ} (hx : x ∈ Icc (-1 : ℝ) 1) (hy : y theorem arcsin_le_iff_le_sin' {x y : ℝ} (hy : y ∈ Ico (-(π / 2)) (π / 2)) : arcsin x ≤ y ↔ x ≤ sin y := by - cases' le_total x (-1) with hx₁ hx₁ + rcases le_total x (-1) with hx₁ | hx₁ · simp [arcsin_of_le_neg_one hx₁, hy.1, hx₁.trans (neg_one_le_sin _)] cases' lt_or_le 1 x with hx₂ hx₂ · simp [arcsin_of_one_le hx₂.le, hy.2.not_le, (sin_le_one y).trans_lt hx₂] diff --git a/Mathlib/Combinatorics/Hindman.lean b/Mathlib/Combinatorics/Hindman.lean index 9ec4467ed2092..1301cd870999a 100644 --- a/Mathlib/Combinatorics/Hindman.lean +++ b/Mathlib/Combinatorics/Hindman.lean @@ -286,7 +286,7 @@ theorem FP.finset_prod {M} [CommMonoid M] (a : Stream' M) (s : Finset ℕ) (hs : refine' FP_drop_subset_FP _ (s.min' hs) _ induction' s using Finset.strongInduction with s ih rw [← Finset.mul_prod_erase _ _ (s.min'_mem hs), ← Stream'.head_drop] - cases' (s.erase (s.min' hs)).eq_empty_or_nonempty with h h + rcases (s.erase (s.min' hs)).eq_empty_or_nonempty with h | h · rw [h, Finset.prod_empty, mul_one] exact FP.head _ · apply FP.cons diff --git a/Mathlib/Computability/TuringMachine.lean b/Mathlib/Computability/TuringMachine.lean index dc62e3f4ede3e..ec92328d785de 100644 --- a/Mathlib/Computability/TuringMachine.lean +++ b/Mathlib/Computability/TuringMachine.lean @@ -133,10 +133,10 @@ theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} : BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by rintro (h₁ | h₁) (h₂ | h₂) · exact Or.inl (h₁.trans h₂) - · cases' le_total l₁.length l₃.length with h h + · rcases le_total l₁.length l₃.length with h | h · exact Or.inl (h₁.above_of_le h₂ h) · exact Or.inr (h₂.above_of_le h₁ h) - · cases' le_total l₁.length l₃.length with h h + · rcases le_total l₁.length l₃.length with h | h · exact Or.inl (h₁.below_of_le h₂ h) · exact Or.inr (h₂.below_of_le h₁ h) · exact Or.inr (h₂.trans h₁) @@ -284,7 +284,7 @@ def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by cases' lt_or_le n _ with h h · rw [List.getI_append _ _ _ h] rw [List.getI_eq_default _ h] - cases' le_or_lt _ n with h₂ h₂ + rcases le_or_lt _ n with h₂ | h₂ · rw [List.getI_eq_default _ h₂] rw [List.getI_eq_get _ h₂, List.get_append_right' h, List.get_replicate] #align turing.list_blank.nth Turing.ListBlank.nth diff --git a/Mathlib/Control/LawfulFix.lean b/Mathlib/Control/LawfulFix.lean index 55b55060ef16e..067baedb3e31f 100644 --- a/Mathlib/Control/LawfulFix.lean +++ b/Mathlib/Control/LawfulFix.lean @@ -83,7 +83,7 @@ theorem mem_iff (a : α) (b : β a) : b ∈ Part.fix f a ↔ ∃ i, b ∈ approx cases' hh with i hh revert h₁; generalize succ (Nat.find h₀) = j; intro h₁ wlog case : i ≤ j - · cases' le_total i j with H H <;> [skip; symm] <;> apply_assumption <;> assumption + · rcases le_total i j with H | H <;> [skip; symm] <;> apply_assumption <;> assumption replace hh := approx_mono f case _ _ hh apply Part.mem_unique h₁ hh · simp only [fix_def' (⇑f) h₀, not_exists, false_iff_iff, not_mem_none] diff --git a/Mathlib/Data/Fin/Basic.lean b/Mathlib/Data/Fin/Basic.lean index 794cd85e5db8d..a1d02bc80f803 100644 --- a/Mathlib/Data/Fin/Basic.lean +++ b/Mathlib/Data/Fin/Basic.lean @@ -1272,7 +1272,7 @@ theorem coe_sub_one {n} (a : Fin (n + 1)) : ↑(a - 1) = if a = 0 then n else a theorem coe_sub_iff_le {n : ℕ} {a b : Fin n} : (↑(a - b) : ℕ) = a - b ↔ b ≤ a := by cases n; · exact @finZeroElim (fun _ => _) a rw [le_iff_val_le_val, Fin.coe_sub, ← add_tsub_assoc_of_le b.is_lt.le a] - cases' le_or_lt (b : ℕ) a with h h + rcases le_or_lt (b : ℕ) a with h | h · simp [← tsub_add_eq_add_tsub h, val_fin_le.mp h, Nat.mod_eq_of_lt ((Nat.sub_le _ _).trans_lt a.is_lt)] · rw [Nat.mod_eq_of_lt, tsub_eq_zero_of_le h.le, tsub_eq_zero_iff_le, ← not_iff_not] @@ -1284,7 +1284,7 @@ theorem coe_sub_iff_lt {n : ℕ} {a b : Fin n} : (↑(a - b) : ℕ) = n + a - b cases' n with n · exact @finZeroElim (fun _ => _) a rw [lt_iff_val_lt_val, Fin.coe_sub, add_comm] - cases' le_or_lt (b : ℕ) a with h h + rcases le_or_lt (b : ℕ) a with h | h · refine iff_of_false ?_ (not_lt_of_le h) simpa [add_tsub_assoc_of_le h] using ((Nat.mod_lt _ (Nat.succ_pos _)).trans_le le_self_add).ne diff --git a/Mathlib/Data/Finset/PiInduction.lean b/Mathlib/Data/Finset/PiInduction.lean index 1bca90a6b84e6..94bf98d382ed1 100644 --- a/Mathlib/Data/Finset/PiInduction.lean +++ b/Mathlib/Data/Finset/PiInduction.lean @@ -43,7 +43,7 @@ theorem induction_on_pi_of_choice (r : ∀ i, α i → Finset (α i) → Prop) p f := by cases nonempty_fintype ι induction' hs : univ.sigma f using Finset.strongInductionOn with s ihs generalizing f; subst s - cases' eq_empty_or_nonempty (univ.sigma f) with he hne + rcases eq_empty_or_nonempty (univ.sigma f) with he | hne · convert h0 using 1 simpa [funext_iff] using he · rcases sigma_nonempty.1 hne with ⟨i, -, hi⟩ diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean index f7bf0c5bd810b..385a252311344 100644 --- a/Mathlib/Data/Finset/Powerset.lean +++ b/Mathlib/Data/Finset/Powerset.lean @@ -317,15 +317,13 @@ theorem powersetCard_sup [DecidableEq α] (u : Finset α) (n : ℕ) (hn : n < u. rintro x ⟨h, -⟩ exact h · rw [sup_eq_biUnion, le_iff_subset, subset_iff] - cases' (Nat.succ_le_of_lt hn).eq_or_lt with h' h' - · simp [h'] - · intro x hx - simp only [mem_biUnion, exists_prop, id.def] - obtain ⟨t, ht⟩ : ∃ t, t ∈ powersetCard n (u.erase x) := powersetCard_nonempty - (le_trans (Nat.le_sub_one_of_lt hn) pred_card_le_card_erase) - · refine' ⟨insert x t, _, mem_insert_self _ _⟩ - rw [← insert_erase hx, powersetCard_succ_insert (not_mem_erase _ _)] - exact mem_union_right _ (mem_image_of_mem _ ht) + intro x hx + simp only [mem_biUnion, exists_prop, id.def] + obtain ⟨t, ht⟩ : ∃ t, t ∈ powersetCard n (u.erase x) := powersetCard_nonempty + (le_trans (Nat.le_sub_one_of_lt hn) pred_card_le_card_erase) + · refine' ⟨insert x t, _, mem_insert_self _ _⟩ + rw [← insert_erase hx, powersetCard_succ_insert (not_mem_erase _ _)] + exact mem_union_right _ (mem_image_of_mem _ ht) #align finset.powerset_len_sup Finset.powersetCard_sup @[simp] diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index 69e9fecfd4d40..cbc253aef9e2e 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -1138,7 +1138,7 @@ theorem exists_superset_card_eq [Infinite α] (s : Finset α) (n : ℕ) (hn : s. ∃ t : Finset α, s ⊆ t ∧ t.card = n := by induction' n with n IH generalizing s · exact ⟨s, subset_refl _, Nat.eq_zero_of_le_zero hn⟩ - · cases' hn.eq_or_lt with hn' hn' + · rcases hn.eq_or_lt with hn' | hn' · exact ⟨s, subset_refl _, hn'⟩ obtain ⟨t, hs, ht⟩ := IH _ (Nat.le_of_lt_succ hn') obtain ⟨x, hx⟩ := exists_not_mem_finset t diff --git a/Mathlib/Data/Int/Log.lean b/Mathlib/Data/Int/Log.lean index 1aeb3bde17372..34f44a280392f 100644 --- a/Mathlib/Data/Int/Log.lean +++ b/Mathlib/Data/Int/Log.lean @@ -79,7 +79,7 @@ theorem log_natCast (b : ℕ) (n : ℕ) : log b (n : R) = Nat.log b n := by #align int.log_nat_cast Int.log_natCast theorem log_of_left_le_one {b : ℕ} (hb : b ≤ 1) (r : R) : log b r = 0 := by - cases' le_total 1 r with h h + rcases le_total 1 r with h | h · rw [log_of_one_le_right _ h, Nat.log_of_left_le_one hb, Int.ofNat_zero] · rw [log_of_right_le_one _ h, Nat.clog_of_left_le_one hb, Int.ofNat_zero, neg_zero] #align int.log_of_left_le_one Int.log_of_left_le_one @@ -91,7 +91,7 @@ theorem log_of_right_le_zero (b : ℕ) {r : R} (hr : r ≤ 0) : log b r = 0 := b #align int.log_of_right_le_zero Int.log_of_right_le_zero theorem zpow_log_le_self {b : ℕ} {r : R} (hb : 1 < b) (hr : 0 < r) : (b : R) ^ log b r ≤ r := by - cases' le_total 1 r with hr1 hr1 + rcases le_total 1 r with hr1 | hr1 · rw [log_of_one_le_right _ hr1] rw [zpow_ofNat, ← Nat.cast_pow, ← Nat.le_floor_iff hr.le] exact Nat.pow_log_le_self b (Nat.floor_pos.mpr hr1).ne' @@ -100,10 +100,10 @@ theorem zpow_log_le_self {b : ℕ} {r : R} (hb : 1 < b) (hr : 0 < r) : (b : R) ^ #align int.zpow_log_le_self Int.zpow_log_le_self theorem lt_zpow_succ_log_self {b : ℕ} (hb : 1 < b) (r : R) : r < (b : R) ^ (log b r + 1) := by - cases' le_or_lt r 0 with hr hr + rcases le_or_lt r 0 with hr | hr · rw [log_of_right_le_zero _ hr, zero_add, zpow_one] exact hr.trans_lt (zero_lt_one.trans_le <| mod_cast hb.le) - cases' le_or_lt 1 r with hr1 hr1 + rcases le_or_lt 1 r with hr1 | hr1 · rw [log_of_one_le_right _ hr1] rw [Int.ofNat_add_one_out, zpow_ofNat, ← Nat.cast_pow] apply Nat.lt_of_floor_lt @@ -141,9 +141,7 @@ theorem log_zpow {b : ℕ} (hb : 1 < b) (z : ℤ) : log b ((b : R) ^ z : R) = z @[mono] theorem log_mono_right {b : ℕ} {r₁ r₂ : R} (h₀ : 0 < r₁) (h : r₁ ≤ r₂) : log b r₁ ≤ log b r₂ := by - cases' le_or_lt b 1 with hb hb - · rw [log_of_left_le_one hb, log_of_left_le_one hb] - cases' le_total r₁ 1 with h₁ h₁ <;> cases' le_total r₂ 1 with h₂ h₂ + rcases le_total r₁ 1 with h₁ | h₁ <;> rcases le_total r₂ 1 with h₂ | h₂ · rw [log_of_right_le_one _ h₁, log_of_right_le_one _ h₂, neg_le_neg_iff, Int.ofNat_le] exact Nat.clog_mono_right _ (Nat.ceil_mono <| inv_le_inv_of_le h₀ h) · rw [log_of_right_le_one _ h₁, log_of_one_le_right _ h₂] @@ -200,7 +198,7 @@ theorem clog_of_right_le_one (b : ℕ) {r : R} (hr : r ≤ 1) : clog b r = -Nat. theorem clog_of_right_le_zero (b : ℕ) {r : R} (hr : r ≤ 0) : clog b r = 0 := by rw [clog, if_neg (hr.trans_lt zero_lt_one).not_le, neg_eq_zero, Int.coe_nat_eq_zero, Nat.log_eq_zero_iff] - cases' le_or_lt b 1 with hb hb + rcases le_or_lt b 1 with hb | hb · exact Or.inr hb · refine' Or.inl (lt_of_le_of_lt _ hb) exact Nat.floor_le_one_of_le_one ((inv_nonpos.2 hr).trans zero_le_one) @@ -239,7 +237,7 @@ theorem clog_of_left_le_one {b : ℕ} (hb : b ≤ 1) (r : R) : clog b r = 0 := b #align int.clog_of_left_le_one Int.clog_of_left_le_one theorem self_le_zpow_clog {b : ℕ} (hb : 1 < b) (r : R) : r ≤ (b : R) ^ clog b r := by - cases' le_or_lt r 0 with hr hr + rcases le_or_lt r 0 with hr | hr · rw [clog_of_right_le_zero _ hr, zpow_zero] exact hr.trans zero_le_one rw [← neg_log_inv_eq_clog, zpow_neg, le_inv hr (zpow_pos_of_pos _ _)] diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index 46f67f53d9fc1..c06f864687508 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -1609,7 +1609,7 @@ theorem insertNth_length_self (l : List α) (x : α) : insertNth l.length x l = theorem length_le_length_insertNth (l : List α) (x : α) (n : ℕ) : l.length ≤ (insertNth n x l).length := by - cases' le_or_lt n l.length with hn hn + rcases le_or_lt n l.length with hn | hn · rw [length_insertNth _ _ hn] exact (Nat.lt_succ_self _).le · rw [insertNth_of_length_lt _ _ _ hn] @@ -1617,7 +1617,7 @@ theorem length_le_length_insertNth (l : List α) (x : α) (n : ℕ) : theorem length_insertNth_le_succ (l : List α) (x : α) (n : ℕ) : (insertNth n x l).length ≤ l.length + 1 := by - cases' le_or_lt n l.length with hn hn + rcases le_or_lt n l.length with hn | hn · rw [length_insertNth _ _ hn] · rw [insertNth_of_length_lt _ _ _ hn] exact (Nat.lt_succ_self _).le diff --git a/Mathlib/Data/List/Intervals.lean b/Mathlib/Data/List/Intervals.lean index cbafe43247693..33687deb3482e 100644 --- a/Mathlib/Data/List/Intervals.lean +++ b/Mathlib/Data/List/Intervals.lean @@ -61,7 +61,7 @@ theorem nodup (n m : ℕ) : Nodup (Ico n m) := by @[simp] theorem mem {n m l : ℕ} : l ∈ Ico n m ↔ n ≤ l ∧ l < m := by suffices n ≤ l ∧ l < n + (m - n) ↔ n ≤ l ∧ l < m by simp [Ico, this] - cases' le_total n m with hnm hmn + rcases le_total n m with hnm | hmn · rw [add_tsub_cancel_of_le hnm] · rw [tsub_eq_zero_iff_le.mpr hmn, add_zero] exact @@ -167,7 +167,7 @@ theorem filter_lt_of_le_bot {n m l : ℕ} (hln : l ≤ n) : ((Ico n m).filter fu theorem filter_lt_of_ge {n m l : ℕ} (hlm : l ≤ m) : ((Ico n m).filter fun x => x < l) = Ico n l := by - cases' le_total n l with hnl hln + rcases le_total n l with hnl | hln · rw [← append_consecutive hnl hlm, filter_append, filter_lt_of_top_le (le_refl l), filter_lt_of_le_bot (le_refl l), append_nil] · rw [eq_nil_of_le hln, filter_lt_of_le_bot hln] @@ -176,7 +176,7 @@ theorem filter_lt_of_ge {n m l : ℕ} (hlm : l ≤ m) : @[simp] theorem filter_lt (n m l : ℕ) : ((Ico n m).filter fun x => x < l) = Ico n (min m l) := by - cases' le_total m l with hml hlm + rcases le_total m l with hml | hlm · rw [min_eq_left hml, filter_lt_of_top_le hml] · rw [min_eq_right hlm, filter_lt_of_ge hlm] #align list.Ico.filter_lt List.Ico.filter_lt @@ -196,7 +196,7 @@ theorem filter_le_of_top_le {n m l : ℕ} (hml : m ≤ l) : ((Ico n m).filter fu theorem filter_le_of_le {n m l : ℕ} (hnl : n ≤ l) : ((Ico n m).filter fun x => l ≤ x) = Ico l m := by - cases' le_total l m with hlm hml + rcases le_total l m with hlm | hml · rw [← append_consecutive hnl hlm, filter_append, filter_le_of_top_le (le_refl l), filter_le_of_le_bot (le_refl l), nil_append] · rw [eq_nil_of_le hml, filter_le_of_top_le hml] @@ -204,7 +204,7 @@ theorem filter_le_of_le {n m l : ℕ} (hnl : n ≤ l) : @[simp] theorem filter_le (n m l : ℕ) : ((Ico n m).filter fun x => l ≤ x) = Ico (max n l) m := by - cases' le_total n l with hnl hln + rcases le_total n l with hnl | hln · rw [max_eq_right hnl, filter_le_of_le hnl] · rw [max_eq_left hln, filter_le_of_le_bot hln] #align list.Ico.filter_le List.Ico.filter_le diff --git a/Mathlib/Data/List/Rotate.lean b/Mathlib/Data/List/Rotate.lean index c2a0598d6f44f..57eb4489f6762 100644 --- a/Mathlib/Data/List/Rotate.lean +++ b/Mathlib/Data/List/Rotate.lean @@ -143,7 +143,7 @@ theorem rotate_eq_drop_append_take {l : List α} {n : ℕ} : theorem rotate_eq_drop_append_take_mod {l : List α} {n : ℕ} : l.rotate n = l.drop (n % l.length) ++ l.take (n % l.length) := by - cases' l.length.zero_le.eq_or_lt with hl hl + rcases l.length.zero_le.eq_or_lt with hl | hl · simp [eq_nil_of_length_eq_zero hl.symm] rw [← rotate_eq_drop_append_take (n.mod_lt hl).le, rotate_mod] #align list.rotate_eq_drop_append_take_mod List.rotate_eq_drop_append_take_mod @@ -336,9 +336,9 @@ theorem rotate_eq_rotate {l l' : List α} {n : ℕ} : l.rotate n = l'.rotate n theorem rotate_eq_iff {l l' : List α} {n : ℕ} : l.rotate n = l' ↔ l = l'.rotate (l'.length - n % l'.length) := by rw [← @rotate_eq_rotate _ l _ n, rotate_rotate, ← rotate_mod l', add_mod] - cases' l'.length.zero_le.eq_or_lt with hl hl + rcases l'.length.zero_le.eq_or_lt with hl | hl · rw [eq_nil_of_length_eq_zero hl.symm, rotate_nil, rotate_eq_nil_iff] - · cases' (Nat.zero_le (n % l'.length)).eq_or_lt with hn hn + · rcases (Nat.zero_le (n % l'.length)).eq_or_lt with hn | hn · simp [← hn] · rw [mod_eq_of_lt (tsub_lt_self hl hn), tsub_add_cancel_of_le, mod_self, rotate_zero] exact (Nat.mod_lt _ hl).le @@ -395,7 +395,7 @@ theorem Nodup.rotate_eq_self_iff {l : List α} (hl : l.Nodup) {n : ℕ} : l.rotate n = l ↔ n % l.length = 0 ∨ l = [] := by constructor · intro h - cases' l.length.zero_le.eq_or_lt with hl' hl' + rcases l.length.zero_le.eq_or_lt with hl' | hl' · simp [← length_eq_zero, ← hl'] left rw [nodup_iff_nthLe_inj] at hl diff --git a/Mathlib/Data/Nat/Cast/Order.lean b/Mathlib/Data/Nat/Cast/Order.lean index e56710e3f007b..1155e85b79a2f 100644 --- a/Mathlib/Data/Nat/Cast/Order.lean +++ b/Mathlib/Data/Nat/Cast/Order.lean @@ -121,7 +121,7 @@ for `ℕ∞` and `ℝ≥0∞`, so we use type-specific lemmas for these types. - @[simp, norm_cast] theorem cast_tsub [CanonicallyOrderedCommSemiring α] [Sub α] [OrderedSub α] [ContravariantClass α α (· + ·) (· ≤ ·)] (m n : ℕ) : ↑(m - n) = (m - n : α) := by - cases' le_total m n with h h + rcases le_total m n with h | h · rw [Nat.sub_eq_zero_of_le h, cast_zero, tsub_eq_zero_of_le] exact mono_cast h · rcases le_iff_exists_add'.mp h with ⟨m, rfl⟩ diff --git a/Mathlib/Data/Nat/Choose/Basic.lean b/Mathlib/Data/Nat/Choose/Basic.lean index 5adc92bb73d49..a5e9b5806199d 100644 --- a/Mathlib/Data/Nat/Choose/Basic.lean +++ b/Mathlib/Data/Nat/Choose/Basic.lean @@ -127,7 +127,7 @@ theorem choose_mul_factorial_mul_factorial : ∀ {n k}, k ≤ n → choose n k * | 0, _, hk => by simp [Nat.eq_zero_of_le_zero hk] | n + 1, 0, _ => by simp | n + 1, succ k, hk => by - cases' lt_or_eq_of_le hk with hk₁ hk₁ + rcases lt_or_eq_of_le hk with hk₁ | hk₁ · have h : choose n k * k.succ ! * (n - k)! = (k + 1) * n ! := by rw [← choose_mul_factorial_mul_factorial (le_of_succ_le_succ hk)] simp [factorial_succ, mul_comm, mul_left_comm, mul_assoc] @@ -303,7 +303,7 @@ private theorem choose_le_middle_of_le_half_left {n r : ℕ} (hr : r ≤ n / 2) /-- `choose n r` is maximised when `r` is `n/2`. -/ theorem choose_le_middle (r n : ℕ) : choose n r ≤ choose n (n / 2) := by cases' le_or_gt r n with b b - · cases' le_or_lt r (n / 2) with a h + · rcases le_or_lt r (n / 2) with a | h · apply choose_le_middle_of_le_half_left a · rw [← choose_symm b] apply choose_le_middle_of_le_half_left diff --git a/Mathlib/Data/Nat/Digits.lean b/Mathlib/Data/Nat/Digits.lean index 03d416d0156de..9152ca7f2aaa1 100644 --- a/Mathlib/Data/Nat/Digits.lean +++ b/Mathlib/Data/Nat/Digits.lean @@ -448,7 +448,7 @@ theorem digits_len_le_digits_len_succ (b n : ℕ) : (digits b n).length ≤ (digits b (n + 1)).length := by rcases Decidable.eq_or_ne n 0 with (rfl | hn) · simp - cases' le_or_lt b 1 with hb hb + rcases le_or_lt b 1 with hb | hb · interval_cases b <;> simp_arith [digits_zero_succ', hn] simpa [digits_len, hb, hn] using log_mono_right (le_succ _) #align nat.digits_len_le_digits_len_succ Nat.digits_len_le_digits_len_succ diff --git a/Mathlib/Data/Nat/Fib/Basic.lean b/Mathlib/Data/Nat/Fib/Basic.lean index 0fe6adaa8a22c..905e749542abf 100644 --- a/Mathlib/Data/Nat/Fib/Basic.lean +++ b/Mathlib/Data/Nat/Fib/Basic.lean @@ -267,7 +267,7 @@ theorem fast_fib_eq (n : ℕ) : fastFib n = fib n := by rw [fastFib, fast_fib_au #align nat.fast_fib_eq Nat.fast_fib_eq theorem gcd_fib_add_self (m n : ℕ) : gcd (fib m) (fib (n + m)) = gcd (fib m) (fib n) := by - cases' Nat.eq_zero_or_pos n with h h + rcases Nat.eq_zero_or_pos n with h | h · rw [h] simp replace h := Nat.succ_pred_eq_of_pos h; rw [← h, succ_eq_add_one] diff --git a/Mathlib/Data/Nat/GCD/Basic.lean b/Mathlib/Data/Nat/GCD/Basic.lean index 7a7cbdac3ce08..f479a85070d46 100644 --- a/Mathlib/Data/Nat/GCD/Basic.lean +++ b/Mathlib/Data/Nat/GCD/Basic.lean @@ -308,7 +308,7 @@ theorem dvd_mul {x m n : ℕ} : x ∣ m * n ↔ ∃ y z, y ∣ m ∧ z ∣ n ∧ theorem pow_dvd_pow_iff {a b n : ℕ} (n0 : 0 < n) : a ^ n ∣ b ^ n ↔ a ∣ b := by refine' ⟨fun h => _, fun h => pow_dvd_pow_of_dvd h _⟩ - cases' Nat.eq_zero_or_pos (gcd a b) with g0 g0 + rcases Nat.eq_zero_or_pos (gcd a b) with g0 | g0 · simp [eq_zero_of_gcd_eq_zero_right g0] rcases exists_coprime' g0 with ⟨g, a', b', g0', co, rfl, rfl⟩ rw [mul_pow, mul_pow] at h diff --git a/Mathlib/Data/Nat/Log.lean b/Mathlib/Data/Nat/Log.lean index b247618d89f9c..d3fb023e114d6 100644 --- a/Mathlib/Data/Nat/Log.lean +++ b/Mathlib/Data/Nat/Log.lean @@ -179,7 +179,7 @@ theorem pow_log_le_add_one (b : ℕ) : ∀ x, b ^ log b x ≤ x + 1 theorem log_monotone {b : ℕ} : Monotone (log b) := by refine' monotone_nat_of_le_succ fun n => _ - cases' le_or_lt b 1 with hb hb + rcases le_or_lt b 1 with hb | hb · rw [log_of_left_le_one hb] exact zero_le _ · exact le_log_of_pow_le hb (pow_log_le_add_one _ _) @@ -205,7 +205,7 @@ theorem log_antitone_left {n : ℕ} : AntitoneOn (fun b => log b n) (Set.Ioi 1) @[simp] theorem log_div_base (b n : ℕ) : log b (n / b) = log b n - 1 := by - cases' le_or_lt b 1 with hb hb + rcases le_or_lt b 1 with hb | hb · rw [log_of_left_le_one hb, log_of_left_le_one hb, Nat.zero_sub] cases' lt_or_le n b with h h · rw [div_eq_of_lt h, log_of_lt h, log_zero_right] @@ -214,7 +214,7 @@ theorem log_div_base (b n : ℕ) : log b (n / b) = log b n - 1 := by @[simp] theorem log_div_mul_self (b n : ℕ) : log b (n / b * b) = log b n := by - cases' le_or_lt b 1 with hb hb + rcases le_or_lt b 1 with hb | hb · rw [log_of_left_le_one hb, log_of_left_le_one hb] cases' lt_or_le n b with h h · rw [div_eq_of_lt h, zero_mul, log_zero_right, log_of_lt h] @@ -328,7 +328,7 @@ theorem le_pow_clog {b : ℕ} (hb : 1 < b) (x : ℕ) : x ≤ b ^ clog b x := @[mono] theorem clog_mono_right (b : ℕ) {n m : ℕ} (h : n ≤ m) : clog b n ≤ clog b m := by - cases' le_or_lt b 1 with hb hb + rcases le_or_lt b 1 with hb | hb · rw [clog_of_left_le_one hb] exact zero_le _ · rw [← le_pow_iff_clog_le hb] diff --git a/Mathlib/Data/Nat/Order/Basic.lean b/Mathlib/Data/Nat/Order/Basic.lean index bc4d65d56fde4..3d62c7d35d091 100644 --- a/Mathlib/Data/Nat/Order/Basic.lean +++ b/Mathlib/Data/Nat/Order/Basic.lean @@ -124,12 +124,12 @@ theorem max_eq_zero_iff : max m n = 0 ↔ m = 0 ∧ n = 0 := max_eq_bot theorem add_eq_max_iff : m + n = max m n ↔ m = 0 ∨ n = 0 := by rw [← min_eq_zero_iff] - cases' le_total m n with H H <;> simp [H] + rcases le_total m n with H | H <;> simp [H] #align nat.add_eq_max_iff Nat.add_eq_max_iff theorem add_eq_min_iff : m + n = min m n ↔ m = 0 ∧ n = 0 := by rw [← max_eq_zero_iff] - cases' le_total m n with H H <;> simp [H] + rcases le_total m n with H | H <;> simp [H] #align nat.add_eq_min_iff Nat.add_eq_min_iff theorem one_le_of_lt (h : n < m) : 1 ≤ m := @@ -244,11 +244,11 @@ theorem lt_of_lt_pred (h : m < n - 1) : m < n := #align nat.lt_of_lt_pred Nat.lt_of_lt_pred theorem le_or_le_of_add_eq_add_pred (h : k + l = m + n - 1) : m ≤ k ∨ n ≤ l := by - cases' le_or_lt m k with h' h' <;> [left; right] + rcases le_or_lt m k with h' | h' <;> [left; right] · exact h' · replace h' := add_lt_add_right h' l rw [h] at h' - cases' n.eq_zero_or_pos with hn hn + rcases n.eq_zero_or_pos with hn | hn · rw [hn] exact zero_le l rw [n.add_sub_assoc (Nat.succ_le_of_lt hn), add_lt_add_iff_left] at h' diff --git a/Mathlib/Data/Nat/Order/Lemmas.lean b/Mathlib/Data/Nat/Order/Lemmas.lean index 252ea0b800df8..0d35bb17bec18 100644 --- a/Mathlib/Data/Nat/Order/Lemmas.lean +++ b/Mathlib/Data/Nat/Order/Lemmas.lean @@ -115,7 +115,7 @@ protected theorem dvd_add_self_right {m n : ℕ} : m ∣ n + m ↔ m ∣ n := -- TODO: update `Nat.dvd_sub` in core theorem dvd_sub' {k m n : ℕ} (h₁ : k ∣ m) (h₂ : k ∣ n) : k ∣ m - n := by - cases' le_total n m with H H + rcases le_total n m with H | H · exact dvd_sub H h₁ h₂ · rw [tsub_eq_zero_iff_le.mpr H] exact dvd_zero k diff --git a/Mathlib/Data/Nat/Prime.lean b/Mathlib/Data/Nat/Prime.lean index bc3d5c3f5537d..52562e5efe8af 100644 --- a/Mathlib/Data/Nat/Prime.lean +++ b/Mathlib/Data/Nat/Prime.lean @@ -136,7 +136,7 @@ theorem prime_def_le_sqrt {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m, 2 ≤ m → have : ∀ {m k : ℕ}, m ≤ k → 1 < m → p ≠ m * k := fun {m k} mk m1 e => a m m1 (le_sqrt.2 (e.symm ▸ Nat.mul_le_mul_left m mk)) ⟨k, e⟩ fun m m2 l ⟨k, e⟩ => by - cases' le_total m k with mk km + rcases le_total m k with mk | km · exact this mk m2 e · rw [mul_comm] at e refine' this km (lt_of_mul_lt_mul_right _ (zero_le m)) e @@ -296,7 +296,7 @@ theorem minFacAux_has_prop {n : ℕ} (n2 : 2 ≤ n) : · refine' have := minFac_lemma n k h minFacAux_has_prop n2 (k + 2) (i + 1) (by simp [e, left_distrib]) fun m m2 d => _ - cases' Nat.eq_or_lt_of_le (a m m2 d) with me ml + rcases Nat.eq_or_lt_of_le (a m m2 d) with me | ml · subst me contradiction apply (Nat.eq_or_lt_of_le ml).resolve_left diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index e324c6530e488..4ed58411296da 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -184,7 +184,7 @@ theorem minSqFacAux_has_prop {n : ℕ} (k) (n0 : 0 < n) (i) (e : k = 2 * i + 3) lt_of_le_of_lt (Nat.sub_le_sub_right (Nat.sqrt_le_sqrt hn') _) (Nat.minFac_lemma n k h) @minSqFacAux_has_prop n' (k + 2) (pos_of_dvd_of_pos nd' n0) (i + 1) (by simp [e, left_distrib]) fun m m2 d => _ - cases' Nat.eq_or_lt_of_le (ih m m2 (dvd_trans d nd')) with me ml + rcases Nat.eq_or_lt_of_le (ih m m2 (dvd_trans d nd')) with me | ml · subst me contradiction apply (Nat.eq_or_lt_of_le ml).resolve_left @@ -208,7 +208,7 @@ termination_by _ => n.sqrt + 2 - k theorem minSqFac_has_prop (n : ℕ) : MinSqFacProp n (minSqFac n) := by dsimp only [minSqFac]; split_ifs with d2 d4 · exact ⟨prime_two, (dvd_div_iff d2).1 d4, fun p pp _ => pp.two_le⟩ - · cases' Nat.eq_zero_or_pos n with n0 n0 + · rcases Nat.eq_zero_or_pos n with n0 | n0 · subst n0 cases d4 (by decide) refine' minSqFacProp_div _ prime_two d2 (mt (dvd_div_iff d2).2 d4) _ @@ -216,7 +216,7 @@ theorem minSqFac_has_prop (n : ℕ) : MinSqFacProp n (minSqFac n) := by refine' fun p pp dp => succ_le_of_lt (lt_of_le_of_ne pp.two_le _) rintro rfl contradiction - · cases' Nat.eq_zero_or_pos n with n0 n0 + · rcases Nat.eq_zero_or_pos n with n0 | n0 · subst n0 cases d2 (by decide) refine' minSqFacAux_has_prop _ n0 0 rfl _ @@ -522,7 +522,7 @@ theorem squarefreeHelper_3 (n n' k k' c : ℕ) (e : k + 1 = k') (hn' : bit1 n' * theorem squarefreeHelper_4 (n k k' : ℕ) (e : bit1 k * bit1 k = k') (hd : bit1 n < k') : SquarefreeHelper n k := by - cases' Nat.eq_zero_or_pos n with h h + rcases Nat.eq_zero_or_pos n with h | h · subst n exact fun _ _ => squarefree_one subst e diff --git a/Mathlib/Data/Ordmap/Ordset.lean b/Mathlib/Data/Ordmap/Ordset.lean index 95eff9627d254..9dd526315267e 100644 --- a/Mathlib/Data/Ordmap/Ordset.lean +++ b/Mathlib/Data/Ordmap/Ordset.lean @@ -1173,7 +1173,7 @@ theorem Valid'.node4L {l} {x : α} {m} {y : α} {r o₁ o₂} (hl : Valid' o₁ · rw [hm.2.size_eq, Nat.succ_inj', add_eq_zero_iff] at m1 rw [l0, m1.1, m1.2]; revert r0; rcases size r with (_ | _ | _) <;> [decide; decide; (intro r0; unfold BalancedSz delta; linarith)] - · cases' Nat.eq_zero_or_pos (size r) with r0 r0 + · rcases Nat.eq_zero_or_pos (size r) with r0 | r0 · rw [r0] at mr₂; cases not_le_of_lt Hm mr₂ rw [hm.2.size_eq] at lr₁ lr₂ mr₁ mr₂ by_cases mm : size ml + size mr ≤ 1 @@ -1193,7 +1193,7 @@ theorem Valid'.node4L {l} {x : α} {m} {y : α} {r o₁ o₂} (hl : Valid' o₁ · rcases mm with (_ | ⟨⟨⟩⟩); decide · rw [Nat.succ_add] at mm; rcases mm with (_ | ⟨⟨⟩⟩) rcases hm.3.1.resolve_left mm with ⟨mm₁, mm₂⟩ - cases' Nat.eq_zero_or_pos (size ml) with ml0 ml0 + rcases Nat.eq_zero_or_pos (size ml) with ml0 | ml0 · rw [ml0, mul_zero, le_zero_iff] at mm₂ rw [ml0, mm₂] at mm; cases mm (by decide) have : 2 * size l ≤ size ml + size mr + 1 := by @@ -1252,10 +1252,10 @@ theorem Valid'.rotateL {l} {x : α} {r o₁ o₂} (hl : Valid' o₁ l x) (hr : V (mul_lt_mul_left (by decide)).1 (lt_of_le_of_lt (Nat.zero_le _) h : ratio * 0 < _) suffices BalancedSz (size l) (size rl) ∧ BalancedSz (size l + size rl + 1) (size rr) by exact hl.node3L hr.left hr.right this.1 this.2 - cases' Nat.eq_zero_or_pos (size l) with l0 l0 + rcases Nat.eq_zero_or_pos (size l) with l0 | l0 · rw [l0]; replace H3 := H3_0 l0 have := hr.3.1 - cases' Nat.eq_zero_or_pos (size rl) with rl0 rl0 + rcases Nat.eq_zero_or_pos (size rl) with rl0 | rl0 · rw [rl0] at this ⊢ rw [le_antisymm (balancedSz_zero.1 this.symm) rr0] decide @@ -1272,16 +1272,16 @@ theorem Valid'.rotateL {l} {x : α} {r o₁ o₂} (hl : Valid' o₁ l x) (hr : V · exact le_trans hb₂ (Nat.mul_le_mul_left _ <| le_trans (Nat.le_add_left _ _) (Nat.le_add_right _ _)) - · cases' Nat.eq_zero_or_pos (size rl) with rl0 rl0 + · rcases Nat.eq_zero_or_pos (size rl) with rl0 | rl0 · rw [rl0, not_lt, le_zero_iff, Nat.mul_eq_zero] at h replace h := h.resolve_left (by decide) erw [rl0, h, le_zero_iff, Nat.mul_eq_zero] at H2 rw [hr.2.size_eq, rl0, h, H2.resolve_left (by decide)] at H1 cases H1 (by decide) refine' hl.node4L hr.left hr.right rl0 _ - cases' Nat.eq_zero_or_pos (size l) with l0 l0 + rcases Nat.eq_zero_or_pos (size l) with l0 | l0 · replace H3 := H3_0 l0 - cases' Nat.eq_zero_or_pos (size rr) with rr0 rr0 + rcases Nat.eq_zero_or_pos (size rr) with rr0 | rr0 · have := hr.3.1 rw [rr0] at this exact Or.inl ⟨l0, le_antisymm (balancedSz_zero.1 this) rl0, rr0.symm ▸ zero_le_one⟩ @@ -1315,7 +1315,7 @@ theorem Valid'.balance'_lemma {α l l' r r'} (H1 : BalancedSz l' r') (H2 : Nat.dist (@size α l) l' ≤ 1 ∧ size r = r' ∨ Nat.dist (size r) r' ≤ 1 ∧ size l = l') : 2 * @size α r ≤ 9 * size l + 5 ∨ size r ≤ 3 := by suffices @size α r ≤ 3 * (size l + 1) by - cases' Nat.eq_zero_or_pos (size l) with l0 l0 + rcases Nat.eq_zero_or_pos (size l) with l0 | l0 · apply Or.inr; rwa [l0] at this change 1 ≤ _ at l0; apply Or.inl; linarith rcases H2 with (⟨hl, rfl⟩ | ⟨hr, rfl⟩) <;> rcases H1 with (h | ⟨_, h₂⟩) @@ -1350,9 +1350,9 @@ theorem Valid'.balanceL_aux {l} {x : α} {r o₁ o₂} (hl : Valid' o₁ l x) (h (H₃ : 2 * @size α l ≤ 9 * size r + 5 ∨ size l ≤ 3) : Valid' o₁ (@balanceL α l x r) o₂ := by rw [balanceL_eq_balance hl.2 hr.2 H₁ H₂, balance_eq_balance' hl.3 hr.3 hl.2 hr.2] refine' hl.balance'_aux hr (Or.inl _) H₃ - cases' Nat.eq_zero_or_pos (size r) with r0 r0 + rcases Nat.eq_zero_or_pos (size r) with r0 | r0 · rw [r0]; exact Nat.zero_le _ - cases' Nat.eq_zero_or_pos (size l) with l0 l0 + rcases Nat.eq_zero_or_pos (size l) with l0 | l0 · rw [l0]; exact le_trans (Nat.mul_le_mul_left _ (H₁ l0)) (by decide) replace H₂ : _ ≤ 3 * _ := H₂ l0 r0; linarith #align ordnode.valid'.balance_l_aux Ordnode.Valid'.balanceL_aux diff --git a/Mathlib/Data/Pi/Lex.lean b/Mathlib/Data/Pi/Lex.lean index 356eba10ea3da..6db9d11a8ec5e 100644 --- a/Mathlib/Data/Pi/Lex.lean +++ b/Mathlib/Data/Pi/Lex.lean @@ -74,7 +74,7 @@ theorem lex_lt_of_lt [∀ i, PartialOrder (β i)] {r} (hwf : WellFounded r) {x y theorem isTrichotomous_lex [∀ i, IsTrichotomous (β i) s] (wf : WellFounded r) : IsTrichotomous (∀ i, β i) (Pi.Lex r @s) := { trichotomous := fun a b => by - cases' eq_or_ne a b with hab hab + rcases eq_or_ne a b with hab | hab · exact Or.inr (Or.inl hab) · rw [Function.ne_iff] at hab let i := wf.min _ hab diff --git a/Mathlib/Data/Polynomial/Derivative.lean b/Mathlib/Data/Polynomial/Derivative.lean index 024614a29847f..1607e96ec8487 100644 --- a/Mathlib/Data/Polynomial/Derivative.lean +++ b/Mathlib/Data/Polynomial/Derivative.lean @@ -206,7 +206,7 @@ theorem degree_derivative_le {p : R[X]} : p.derivative.degree ≤ p.degree := theorem natDegree_derivative_lt {p : R[X]} (hp : p.natDegree ≠ 0) : p.derivative.natDegree < p.natDegree := by - cases' eq_or_ne (derivative p) 0 with hp' hp' + rcases eq_or_ne (derivative p) 0 with hp' | hp' · rw [hp', Polynomial.natDegree_zero] exact hp.bot_lt · rw [natDegree_lt_natDegree_iff hp'] diff --git a/Mathlib/Data/Polynomial/Expand.lean b/Mathlib/Data/Polynomial/Expand.lean index 08e5fe00fa7b3..e49abfdba91c5 100644 --- a/Mathlib/Data/Polynomial/Expand.lean +++ b/Mathlib/Data/Polynomial/Expand.lean @@ -149,7 +149,7 @@ set_option linter.uppercaseLean3 false in #align polynomial.expand_eq_C Polynomial.expand_eq_C theorem natDegree_expand (p : ℕ) (f : R[X]) : (expand R p f).natDegree = f.natDegree * p := by - cases' p.eq_zero_or_pos with hp hp + rcases p.eq_zero_or_pos with hp | hp · rw [hp, coe_expand, pow_zero, mul_zero, ← C_1, eval₂_hom, natDegree_C] by_cases hf : f = 0 · rw [hf, AlgHom.map_zero, natDegree_zero, zero_mul] diff --git a/Mathlib/Data/Rat/NNRat.lean b/Mathlib/Data/Rat/NNRat.lean index ff84ceb139201..4bd8ad292500d 100644 --- a/Mathlib/Data/Rat/NNRat.lean +++ b/Mathlib/Data/Rat/NNRat.lean @@ -407,7 +407,7 @@ theorem lt_toNNRat_iff_coe_lt {q : ℚ≥0} : q < toNNRat p ↔ ↑q < p := #noalign rat.to_nnrat_bit1 theorem toNNRat_mul (hp : 0 ≤ p) : toNNRat (p * q) = toNNRat p * toNNRat q := by - cases' le_total 0 q with hq hq + rcases le_total 0 q with hq | hq · ext <;> simp [toNNRat, hp, hq, max_eq_left, mul_nonneg] · have hpq := mul_nonpos_of_nonneg_of_nonpos hp hq rw [toNNRat_eq_zero.2 hq, toNNRat_eq_zero.2 hpq, mul_zero] diff --git a/Mathlib/Data/Rat/Order.lean b/Mathlib/Data/Rat/Order.lean index c818c84d65440..e3444fa75338f 100644 --- a/Mathlib/Data/Rat/Order.lean +++ b/Mathlib/Data/Rat/Order.lean @@ -296,7 +296,7 @@ theorem lt_one_iff_num_lt_denom {q : ℚ} : q < 1 ↔ q.num < q.den := by simp [ #align rat.lt_one_iff_num_lt_denom Rat.lt_one_iff_num_lt_denom theorem abs_def (q : ℚ) : |q| = q.num.natAbs /. q.den := by - cases' le_total q 0 with hq hq + rcases le_total q 0 with hq | hq · rw [abs_of_nonpos hq] rw [← @num_den q, ← divInt_zero_one, Rat.le_def (Int.coe_nat_pos.2 q.pos) zero_lt_one, mul_one, zero_mul] at hq diff --git a/Mathlib/Data/Real/ENNReal.lean b/Mathlib/Data/Real/ENNReal.lean index 47f14748d308c..bee679539acb4 100644 --- a/Mathlib/Data/Real/ENNReal.lean +++ b/Mathlib/Data/Real/ENNReal.lean @@ -1240,7 +1240,7 @@ theorem sub_right_inj {a b c : ℝ≥0∞} (ha : a ≠ ∞) (hb : b ≤ a) (hc : #align ennreal.sub_right_inj ENNReal.sub_right_inj theorem sub_mul (h : 0 < b → b < a → c ≠ ∞) : (a - b) * c = a * c - b * c := by - cases' le_or_lt a b with hab hab; · simp [hab, mul_right_mono hab] + rcases le_or_lt a b with hab | hab; · simp [hab, mul_right_mono hab] rcases eq_or_lt_of_le (zero_le b) with (rfl | hb); · simp exact (cancel_of_ne <| mul_ne_top hab.ne_top (h hb hab)).tsub_mul #align ennreal.sub_mul ENNReal.sub_mul diff --git a/Mathlib/Data/Real/NNReal.lean b/Mathlib/Data/Real/NNReal.lean index 09cd022406298..2d1bcf775a878 100644 --- a/Mathlib/Data/Real/NNReal.lean +++ b/Mathlib/Data/Real/NNReal.lean @@ -988,7 +988,7 @@ theorem div_lt_one_of_lt {a b : ℝ≥0} (h : a < b) : a / b < 1 := by #align nnreal.div_lt_one_of_lt NNReal.div_lt_one_of_lt theorem _root_.Real.toNNReal_inv {x : ℝ} : Real.toNNReal x⁻¹ = (Real.toNNReal x)⁻¹ := by - cases' le_total 0 x with hx hx + rcases le_total 0 x with hx | hx · nth_rw 1 [← Real.coe_toNNReal x hx] rw [← NNReal.coe_inv, Real.toNNReal_coe] · rw [toNNReal_eq_zero.mpr hx, inv_zero, toNNReal_eq_zero.mpr (inv_nonpos.mpr hx)] @@ -1135,7 +1135,7 @@ theorem image_coe_nnreal_real (h : t.OrdConnected) : ((↑) '' t : Set ℝ).OrdC -- porting note: todo: does it generalize to a `GaloisInsertion`? theorem image_real_toNNReal (h : s.OrdConnected) : (Real.toNNReal '' s).OrdConnected := by refine' ⟨ball_image_iff.2 fun x hx => ball_image_iff.2 fun y hy z hz => _⟩ - cases' le_total y 0 with hy₀ hy₀ + rcases le_total y 0 with hy₀ | hy₀ · rw [mem_Icc, Real.toNNReal_of_nonpos hy₀, nonpos_iff_eq_zero] at hz exact ⟨y, hy, (toNNReal_of_nonpos hy₀).trans hz.2.symm⟩ · lift y to ℝ≥0 using hy₀ diff --git a/Mathlib/Data/Real/Sqrt.lean b/Mathlib/Data/Real/Sqrt.lean index ca73aab94a253..d4db77e39a29c 100644 --- a/Mathlib/Data/Real/Sqrt.lean +++ b/Mathlib/Data/Real/Sqrt.lean @@ -208,7 +208,7 @@ theorem sqrt_mul_self (h : 0 ≤ x) : sqrt (x * x) = x := theorem sqrt_eq_cases : sqrt x = y ↔ y * y = x ∧ 0 ≤ y ∨ x < 0 ∧ y = 0 := by constructor · rintro rfl - cases' le_or_lt 0 x with hle hlt + rcases le_or_lt 0 x with hle | hlt · exact Or.inl ⟨mul_self_sqrt hle, sqrt_nonneg x⟩ · exact Or.inr ⟨hlt, sqrt_eq_zero_of_nonpos hlt.le⟩ · rintro (⟨rfl, hy⟩ | ⟨hx, rfl⟩) @@ -417,7 +417,7 @@ theorem sqrt_div' (x) {y : ℝ} (hy : 0 ≤ y) : sqrt (x / y) = sqrt x / sqrt y @[simp] theorem div_sqrt : x / sqrt x = sqrt x := by - cases' le_or_lt x 0 with h h + rcases le_or_lt x 0 with h | h · rw [sqrt_eq_zero'.mpr h, div_zero] · rw [div_eq_iff (sqrt_ne_zero'.mpr h), mul_self_sqrt h.le] #align real.div_sqrt Real.div_sqrt diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index 9484aa9de1cf5..70a84f80d331f 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -1634,7 +1634,7 @@ theorem Finite.exists_maximal_wrt [PartialOrder β] (f : α → β) (s : Set α) induction s, h using Set.Finite.dinduction_on with | H0 => exact absurd hs not_nonempty_empty | @H1 a s his _ ih => - cases' s.eq_empty_or_nonempty with h h + rcases s.eq_empty_or_nonempty with h | h · use a simp [h] rcases ih h with ⟨b, hb, ih⟩ diff --git a/Mathlib/Data/Set/Intervals/Basic.lean b/Mathlib/Data/Set/Intervals/Basic.lean index 39e39cac17983..bab3be2e4805d 100644 --- a/Mathlib/Data/Set/Intervals/Basic.lean +++ b/Mathlib/Data/Set/Intervals/Basic.lean @@ -1271,7 +1271,7 @@ theorem Ioo_union_Ioi' (h₁ : c < b) : Ioo a b ∪ Ioi c = Ioi (min a c) := by #align set.Ioo_union_Ioi' Set.Ioo_union_Ioi' theorem Ioo_union_Ioi (h : c < max a b) : Ioo a b ∪ Ioi c = Ioi (min a c) := by - cases' le_total a b with hab hab <;> simp [hab] at h + rcases le_total a b with hab | hab <;> simp [hab] at h · exact Ioo_union_Ioi' h · rw [min_comm] simp [*, min_eq_left_of_lt] @@ -1305,7 +1305,7 @@ theorem Ico_union_Ici' (h₁ : c ≤ b) : Ico a b ∪ Ici c = Ici (min a c) := b #align set.Ico_union_Ici' Set.Ico_union_Ici' theorem Ico_union_Ici (h : c ≤ max a b) : Ico a b ∪ Ici c = Ici (min a c) := by - cases' le_total a b with hab hab <;> simp [hab] at h + rcases le_total a b with hab | hab <;> simp [hab] at h · exact Ico_union_Ici' h · simp [*] #align set.Ico_union_Ici Set.Ico_union_Ici @@ -1329,7 +1329,7 @@ theorem Ioc_union_Ioi' (h₁ : c ≤ b) : Ioc a b ∪ Ioi c = Ioi (min a c) := b #align set.Ioc_union_Ioi' Set.Ioc_union_Ioi' theorem Ioc_union_Ioi (h : c ≤ max a b) : Ioc a b ∪ Ioi c = Ioi (min a c) := by - cases' le_total a b with hab hab <;> simp [hab] at h + rcases le_total a b with hab | hab <;> simp [hab] at h · exact Ioc_union_Ioi' h · simp [*] #align set.Ioc_union_Ioi Set.Ioc_union_Ioi @@ -1372,7 +1372,7 @@ theorem Icc_union_Ici' (h₁ : c ≤ b) : Icc a b ∪ Ici c = Ici (min a c) := b #align set.Icc_union_Ici' Set.Icc_union_Ici' theorem Icc_union_Ici (h : c ≤ max a b) : Icc a b ∪ Ici c = Ici (min a c) := by - cases' le_or_lt a b with hab hab <;> simp [hab] at h + rcases le_or_lt a b with hab | hab <;> simp [hab] at h · exact Icc_union_Ici' h · cases' h with h h · simp [*] @@ -1413,7 +1413,7 @@ theorem Iio_union_Ico' (h₁ : c ≤ b) : Iio b ∪ Ico c d = Iio (max b d) := b #align set.Iio_union_Ico' Set.Iio_union_Ico' theorem Iio_union_Ico (h : min c d ≤ b) : Iio b ∪ Ico c d = Iio (max b d) := by - cases' le_total c d with hcd hcd <;> simp [hcd] at h + rcases le_total c d with hcd | hcd <;> simp [hcd] at h · exact Iio_union_Ico' h · simp [*] #align set.Iio_union_Ico Set.Iio_union_Ico @@ -1438,7 +1438,7 @@ theorem Iic_union_Ioc' (h₁ : c < b) : Iic b ∪ Ioc c d = Iic (max b d) := by #align set.Iic_union_Ioc' Set.Iic_union_Ioc' theorem Iic_union_Ioc (h : min c d < b) : Iic b ∪ Ioc c d = Iic (max b d) := by - cases' le_total c d with hcd hcd <;> simp [hcd] at h + rcases le_total c d with hcd | hcd <;> simp [hcd] at h · exact Iic_union_Ioc' h · rw [max_comm] simp [*, max_eq_right_of_lt h] @@ -1464,7 +1464,7 @@ theorem Iio_union_Ioo' (h₁ : c < b) : Iio b ∪ Ioo c d = Iio (max b d) := by #align set.Iio_union_Ioo' Set.Iio_union_Ioo' theorem Iio_union_Ioo (h : min c d < b) : Iio b ∪ Ioo c d = Iio (max b d) := by - cases' le_total c d with hcd hcd <;> simp [hcd] at h + rcases le_total c d with hcd | hcd <;> simp [hcd] at h · exact Iio_union_Ioo' h · rw [max_comm] simp [*, max_eq_right_of_lt h] @@ -1490,7 +1490,7 @@ theorem Iic_union_Icc' (h₁ : c ≤ b) : Iic b ∪ Icc c d = Iic (max b d) := b #align set.Iic_union_Icc' Set.Iic_union_Icc' theorem Iic_union_Icc (h : min c d ≤ b) : Iic b ∪ Icc c d = Iic (max b d) := by - cases' le_or_lt c d with hcd hcd <;> simp [hcd] at h + rcases le_or_lt c d with hcd | hcd <;> simp [hcd] at h · exact Iic_union_Icc' h · cases' h with h h · have hdb : d ≤ b := hcd.le.trans h @@ -1547,7 +1547,7 @@ theorem Ico_union_Ico' (h₁ : c ≤ b) (h₂ : a ≤ d) : Ico a b ∪ Ico c d = theorem Ico_union_Ico (h₁ : min a b ≤ max c d) (h₂ : min c d ≤ max a b) : Ico a b ∪ Ico c d = Ico (min a c) (max b d) := by - cases' le_total a b with hab hab <;> cases' le_total c d with hcd hcd <;> simp [hab, hcd] at h₁ h₂ + rcases le_total a b with hab | hab <;> rcases le_total c d with hcd | hcd <;> simp [*] at h₁ h₂ · exact Ico_union_Ico' h₂ h₁ all_goals simp [*] #align set.Ico_union_Ico Set.Ico_union_Ico @@ -1635,7 +1635,7 @@ theorem Ioc_union_Ioc' (h₁ : c ≤ b) (h₂ : a ≤ d) : Ioc a b ∪ Ioc c d = theorem Ioc_union_Ioc (h₁ : min a b ≤ max c d) (h₂ : min c d ≤ max a b) : Ioc a b ∪ Ioc c d = Ioc (min a c) (max b d) := by - cases' le_total a b with hab hab <;> cases' le_total c d with hcd hcd <;> simp [hab, hcd] at h₁ h₂ + rcases le_total a b with hab | hab <;> rcases le_total c d with hcd | hcd <;> simp [*] at h₁ h₂ · exact Ioc_union_Ioc' h₂ h₁ all_goals simp [*] #align set.Ioc_union_Ioc Set.Ioc_union_Ioc @@ -1694,7 +1694,7 @@ Otherwise for `b < a = d < c` the l.h.s. is `∅` and the r.h.s. is `{a}`. -/ theorem Icc_union_Icc (h₁ : min a b < max c d) (h₂ : min c d < max a b) : Icc a b ∪ Icc c d = Icc (min a c) (max b d) := by - cases' le_or_lt a b with hab hab <;> cases' le_or_lt c d with hcd hcd <;> + rcases le_or_lt a b with hab | hab <;> rcases le_or_lt c d with hcd | hcd <;> simp only [min_eq_left, min_eq_right, max_eq_left, max_eq_right, min_eq_left_of_lt, min_eq_right_of_lt, max_eq_left_of_lt, max_eq_right_of_lt, hab, hcd] at h₁ h₂ · exact Icc_union_Icc' h₂.le h₁.le @@ -1726,7 +1726,7 @@ theorem Ioo_union_Ioo' (h₁ : c < b) (h₂ : a < d) : Ioo a b ∪ Ioo c d = Ioo theorem Ioo_union_Ioo (h₁ : min a b < max c d) (h₂ : min c d < max a b) : Ioo a b ∪ Ioo c d = Ioo (min a c) (max b d) := by - cases' le_total a b with hab hab <;> cases' le_total c d with hcd hcd <;> + rcases le_total a b with hab | hab <;> rcases le_total c d with hcd | hcd <;> simp only [min_eq_left, min_eq_right, max_eq_left, max_eq_right, hab, hcd] at h₁ h₂ · exact Ioo_union_Ioo' h₂ h₁ all_goals diff --git a/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean b/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean index 0bee1b87f3725..d7e846c791f3b 100644 --- a/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean +++ b/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean @@ -203,7 +203,7 @@ theorem disjoint_ordT5Nhd : Disjoint (ordT5Nhd s t) (ordT5Nhd t s) := by rcases mem_iUnion₂.1 hx₂ with ⟨b, hbt, hb⟩ clear hx₂ rw [mem_ordConnectedComponent, subset_inter_iff] at ha hb - cases' le_total a b with hab hab + rcases le_total a b with hab | hab on_goal 2 => swap_var a ↔ b, s ↔ t, ha ↔ hb, has ↔ hbt all_goals -- porting note: wlog not implemented yet, the following replaces the three previous lines @@ -216,9 +216,9 @@ theorem disjoint_ordT5Nhd : Disjoint (ordT5Nhd s t) (ordT5Nhd t s) := by [[a, b]] ⊆ [[a, x]] ∪ [[x, b]] := uIcc_subset_uIcc_union_uIcc _ ⊆ (ordSeparatingSet s t).ordConnectedSectionᶜ := union_subset ha' hb' clear ha' hb' - cases' le_total x a with hxa hax + rcases le_total x a with hxa | hax · exact hb (Icc_subset_uIcc' ⟨hxa, hab⟩) has - cases' le_total b x with hbx hxb + rcases le_total b x with hbx | hxb · exact ha (Icc_subset_uIcc ⟨hab, hbx⟩) hbt have h' : x ∈ ordSeparatingSet s t := ⟨mem_iUnion₂.2 ⟨a, has, ha⟩, mem_iUnion₂.2 ⟨b, hbt, hb⟩⟩ -- porting note: lift not implemented yet diff --git a/Mathlib/Data/Set/Intervals/ProjIcc.lean b/Mathlib/Data/Set/Intervals/ProjIcc.lean index 28ad38efd218c..aac89cb9582cd 100644 --- a/Mathlib/Data/Set/Intervals/ProjIcc.lean +++ b/Mathlib/Data/Set/Intervals/ProjIcc.lean @@ -302,7 +302,7 @@ theorem IccExtend_eq_self (f : α → β) (ha : ∀ x < a, f x = f a) (hb : ∀ ext x cases' lt_or_le x a with hxa hax · simp [IccExtend_of_le_left _ _ hxa.le, ha x hxa] - · cases' le_or_lt x b with hxb hbx + · rcases le_or_lt x b with hxb | hbx · lift x to Icc a b using ⟨hax, hxb⟩ rw [IccExtend_val, comp_apply] · simp [IccExtend_of_right_le _ _ hbx.le, hb x hbx] diff --git a/Mathlib/Data/Set/Intervals/UnorderedInterval.lean b/Mathlib/Data/Set/Intervals/UnorderedInterval.lean index 23e6724a4a0fb..eefdc07cef471 100644 --- a/Mathlib/Data/Set/Intervals/UnorderedInterval.lean +++ b/Mathlib/Data/Set/Intervals/UnorderedInterval.lean @@ -248,9 +248,7 @@ lemma uIcc_subset_uIcc_iff_le : /-- A sort of triangle inequality. -/ lemma uIcc_subset_uIcc_union_uIcc : [[a, c]] ⊆ [[a, b]] ∪ [[b, c]] := fun x => by simp only [mem_uIcc, mem_union] - cases' le_total a c with h1 h1 <;> - cases' le_total x b with h2 h2 <;> - tauto + rcases le_total x b with h2 | h2 <;> tauto #align set.uIcc_subset_uIcc_union_uIcc Set.uIcc_subset_uIcc_union_uIcc lemma monotone_or_antitone_iff_uIcc : diff --git a/Mathlib/Data/Set/Prod.lean b/Mathlib/Data/Set/Prod.lean index 6d0a7a5afbfb3..bb4dc9ab2c3af 100644 --- a/Mathlib/Data/Set/Prod.lean +++ b/Mathlib/Data/Set/Prod.lean @@ -411,7 +411,7 @@ theorem prod_diff_prod : s ×ˢ t \ s₁ ×ˢ t₁ = s ×ˢ (t \ t₁) ∪ (s \ /-- A product set is included in a product set if and only factors are included, or a factor of the first set is empty. -/ theorem prod_subset_prod_iff : s ×ˢ t ⊆ s₁ ×ˢ t₁ ↔ s ⊆ s₁ ∧ t ⊆ t₁ ∨ s = ∅ ∨ t = ∅ := by - cases' (s ×ˢ t).eq_empty_or_nonempty with h h + rcases (s ×ˢ t).eq_empty_or_nonempty with h | h · simp [h, prod_eq_empty_iff.1 h] have st : s.Nonempty ∧ t.Nonempty := by rwa [prod_nonempty_iff] at h refine' ⟨fun H => Or.inl ⟨_, _⟩, _⟩ @@ -439,7 +439,7 @@ theorem prod_eq_prod_iff_of_nonempty (h : (s ×ˢ t).Nonempty) : theorem prod_eq_prod_iff : s ×ˢ t = s₁ ×ˢ t₁ ↔ s = s₁ ∧ t = t₁ ∨ (s = ∅ ∨ t = ∅) ∧ (s₁ = ∅ ∨ t₁ = ∅) := by symm - cases' eq_empty_or_nonempty (s ×ˢ t) with h h + rcases eq_empty_or_nonempty (s ×ˢ t) with h | h · simp_rw [h, @eq_comm _ ∅, prod_eq_empty_iff, prod_eq_empty_iff.mp h, true_and_iff, or_iff_right_iff_imp] rintro ⟨rfl, rfl⟩ diff --git a/Mathlib/Dynamics/Ergodic/AddCircle.lean b/Mathlib/Dynamics/Ergodic/AddCircle.lean index 458b24bf56fe5..0ef7ce731fc63 100644 --- a/Mathlib/Dynamics/Ergodic/AddCircle.lean +++ b/Mathlib/Dynamics/Ergodic/AddCircle.lean @@ -58,7 +58,7 @@ theorem ae_empty_or_univ_of_forall_vadd_ae_eq_self {s : Set <| AddCircle T} have hT₀ : 0 < T := hT.out have hT₁ : ENNReal.ofReal T ≠ 0 := by simpa rw [ae_eq_empty, ae_eq_univ_iff_measure_eq hs, AddCircle.measure_univ] - cases' eq_or_ne (μ s) 0 with h h; · exact Or.inl h + rcases eq_or_ne (μ s) 0 with h | h; · exact Or.inl h right obtain ⟨d, -, hd⟩ : ∃ d, d ∈ s ∧ ∀ {ι'} {l : Filter ι'} (w : ι' → AddCircle T) (δ : ι' → ℝ), Tendsto δ l (𝓝[>] 0) → (∀ᶠ j in l, d ∈ closedBall (w j) (1 * δ j)) → diff --git a/Mathlib/Dynamics/PeriodicPts.lean b/Mathlib/Dynamics/PeriodicPts.lean index 4eb3262c6e6a6..169b40878b7b4 100644 --- a/Mathlib/Dynamics/PeriodicPts.lean +++ b/Mathlib/Dynamics/PeriodicPts.lean @@ -114,7 +114,7 @@ theorem right_of_add (hn : IsPeriodicPt f (n + m) x) (hm : IsPeriodicPt f n x) : protected theorem sub (hm : IsPeriodicPt f m x) (hn : IsPeriodicPt f n x) : IsPeriodicPt f (m - n) x := by - cases' le_total n m with h h + rcases le_total n m with h | h · refine' left_of_add _ hn rwa [tsub_add_cancel_of_le h] · rw [tsub_eq_zero_iff_le.mpr h] diff --git a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean index 69dee05f8dff5..9f307115bfc88 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean @@ -97,7 +97,7 @@ theorem exists_eq_mul_self [IsAlgClosed k] (x : k) : ∃ z, x = z * z := by theorem roots_eq_zero_iff [IsAlgClosed k] {p : k[X]} : p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by refine' ⟨fun h => _, fun hp => by rw [hp, roots_C]⟩ - cases' le_or_lt (degree p) 0 with hd hd + rcases le_or_lt (degree p) 0 with hd | hd · exact eq_C_of_degree_le_zero hd · obtain ⟨z, hz⟩ := IsAlgClosed.exists_root p hd.ne' rw [← mem_roots (ne_zero_of_degree_gt hd), h] at hz diff --git a/Mathlib/FieldTheory/IsSepClosed.lean b/Mathlib/FieldTheory/IsSepClosed.lean index 019d590cff649..9faecc88e75f6 100644 --- a/Mathlib/FieldTheory/IsSepClosed.lean +++ b/Mathlib/FieldTheory/IsSepClosed.lean @@ -112,7 +112,7 @@ theorem exists_eq_mul_self [IsSepClosed k] (x : k) [h2 : NeZero (2 : k)] : ∃ z theorem roots_eq_zero_iff [IsSepClosed k] {p : k[X]} (hsep : p.Separable) : p.roots = 0 ↔ p = Polynomial.C (p.coeff 0) := by refine' ⟨fun h => _, fun hp => by rw [hp, roots_C]⟩ - cases' le_or_lt (degree p) 0 with hd hd + rcases le_or_lt (degree p) 0 with hd | hd · exact eq_C_of_degree_le_zero hd · obtain ⟨z, hz⟩ := IsSepClosed.exists_root p hd.ne' hsep rw [← mem_roots (ne_zero_of_degree_gt hd), h] at hz diff --git a/Mathlib/FieldTheory/Minpoly/Basic.lean b/Mathlib/FieldTheory/Minpoly/Basic.lean index c66386a8854a3..3059999be3d97 100644 --- a/Mathlib/FieldTheory/Minpoly/Basic.lean +++ b/Mathlib/FieldTheory/Minpoly/Basic.lean @@ -166,7 +166,7 @@ theorem subsingleton [Subsingleton B] : minpoly A x = 1 := by nontriviality A have := minpoly.min A x monic_one (Subsingleton.elim _ _) rw [degree_one] at this - cases' le_or_lt (minpoly A x).degree 0 with h h + rcases le_or_lt (minpoly A x).degree 0 with h | h · rwa [(monic ⟨1, monic_one, by simp [eq_iff_true_of_subsingleton]⟩ : (minpoly A x).Monic).degree_le_zero_iff_eq_one] at h · exact (this.not_lt h).elim diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index 1a4ea83cb43ee..6c1db29068cd2 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -287,7 +287,7 @@ def idGroupoid (H : Type u) [TopologicalSpace H] : StructureGroupoid H where simpa only [e.toPartialEquiv.image_source_eq_target.symm, mfld_simps] using E id_mem' := mem_union_left _ rfl locality' e he := by - cases' e.source.eq_empty_or_nonempty with h h + rcases e.source.eq_empty_or_nonempty with h | h · right exact h · left diff --git a/Mathlib/GroupTheory/Perm/List.lean b/Mathlib/GroupTheory/Perm/List.lean index 9d58a13543226..eb1e953ba72aa 100644 --- a/Mathlib/GroupTheory/Perm/List.lean +++ b/Mathlib/GroupTheory/Perm/List.lean @@ -249,7 +249,7 @@ theorem support_formPerm_of_nodup' (l : List α) (h : Nodup l) (h' : ∀ x : α, intro H rw [nodup_iff_nthLe_inj] at h specialize h _ _ _ _ H - cases' (Nat.succ_le_of_lt hn).eq_or_lt with hn' hn' + rcases (Nat.succ_le_of_lt hn).eq_or_lt with hn' | hn' · simp only [← hn', Nat.mod_self] at h refine' not_exists.mpr h' _ rw [← length_eq_one] @@ -311,7 +311,7 @@ theorem formPerm_reverse (l : List α) (h : Nodup l) : formPerm l.reverse = (for nthLe_reverse' _ _ _ h2, formPerm_apply_nthLe _ h] congr rw [length_reverse] at * - cases' lt_or_eq_of_le (Nat.succ_le_of_lt hk) with h h + rcases lt_or_eq_of_le (Nat.succ_le_of_lt hk) with h | h · rw [Nat.mod_eq_of_lt h, ← Nat.sub_add_comm, Nat.succ_sub_succ_eq_sub, Nat.mod_eq_of_lt h1] exact (Nat.le_sub_iff_add_le (length_pos_of_mem hx)).2 (Nat.succ_le_of_lt h) @@ -382,7 +382,7 @@ theorem formPerm_apply_mem_eq_self_iff (hl : Nodup l) (x : α) (hx : x ∈ l) : cases hn : l.length · exact absurd k.zero_le (hk.trans_le hn.le).not_le · rw [hn] at hk - cases' (Nat.le_of_lt_succ hk).eq_or_lt with hk' hk' + rcases (Nat.le_of_lt_succ hk).eq_or_lt with hk' | hk' · simp [← hk', Nat.succ_le_succ_iff, eq_comm] · simpa [Nat.mod_eq_of_lt (Nat.succ_lt_succ hk'), Nat.succ_lt_succ_iff] using k.zero_le.trans_lt hk' diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean index 14db18950ee72..46ac77e1d746e 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean @@ -817,7 +817,7 @@ theorem affineSpan_eq_top_iff_vectorSpan_eq_top_of_nonempty {s : Set P} (hs : s. /-- For a non-trivial space, the affine span of a set is `⊤` iff its vector span is `⊤`. -/ theorem affineSpan_eq_top_iff_vectorSpan_eq_top_of_nontrivial {s : Set P} [Nontrivial P] : affineSpan k s = ⊤ ↔ vectorSpan k s = ⊤ := by - cases' s.eq_empty_or_nonempty with hs hs + rcases s.eq_empty_or_nonempty with hs | hs · simp [hs, subsingleton_iff_bot_eq_top, AddTorsor.subsingleton_iff V P, not_subsingleton] · rw [affineSpan_eq_top_iff_vectorSpan_eq_top_of_nonempty k V P hs] #align affine_subspace.affine_span_eq_top_iff_vector_span_eq_top_of_nontrivial AffineSubspace.affineSpan_eq_top_iff_vectorSpan_eq_top_of_nontrivial diff --git a/Mathlib/LinearAlgebra/AffineSpace/Basis.lean b/Mathlib/LinearAlgebra/AffineSpace/Basis.lean index ee627e932e529..02e237d8f270b 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Basis.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Basis.lean @@ -180,7 +180,7 @@ theorem coord_apply_ne (h : i ≠ j) : b.coord i (b j) = 0 := by #align affine_basis.coord_apply_ne AffineBasis.coord_apply_ne theorem coord_apply [DecidableEq ι] (i j : ι) : b.coord i (b j) = if i = j then 1 else 0 := by - cases' eq_or_ne i j with h h <;> simp [h] + rcases eq_or_ne i j with h | h <;> simp [h] #align affine_basis.coord_apply AffineBasis.coord_apply @[simp] diff --git a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean index fe55de73cdca5..1321c9dbb7924 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean @@ -102,7 +102,7 @@ theorem weightedVSubOfPoint_eq_of_weights_eq (p : ι → P) (j : ι) (w₁ w₂ simp only [Finset.weightedVSubOfPoint_apply] congr ext i - cases' eq_or_ne i j with h h + rcases eq_or_ne i j with h | h · simp [h] · simp [hw i h] #align finset.weighted_vsub_of_point_eq_of_weights_eq Finset.weightedVSubOfPoint_eq_of_weights_eq diff --git a/Mathlib/LinearAlgebra/Basis.lean b/Mathlib/LinearAlgebra/Basis.lean index 8cbbd25f04307..7587b3e25a41b 100644 --- a/Mathlib/LinearAlgebra/Basis.lean +++ b/Mathlib/LinearAlgebra/Basis.lean @@ -1162,7 +1162,7 @@ theorem mk_coord_apply_ne {i j : ι} (h : j ≠ i) : (Basis.mk hli hsp).coord i `j`th element of the basis. -/ theorem mk_coord_apply [DecidableEq ι] {i j : ι} : (Basis.mk hli hsp).coord i (v j) = if j = i then 1 else 0 := by - cases' eq_or_ne j i with h h + rcases eq_or_ne j i with h | h · simp only [h, if_true, eq_self_iff_true, mk_coord_apply_eq i] · simp only [h, if_false, mk_coord_apply_ne h] #align basis.mk_coord_apply Basis.mk_coord_apply diff --git a/Mathlib/LinearAlgebra/LinearPMap.lean b/Mathlib/LinearAlgebra/LinearPMap.lean index 84af0760eb5d2..9d789d8a6ced8 100644 --- a/Mathlib/LinearAlgebra/LinearPMap.lean +++ b/Mathlib/LinearAlgebra/LinearPMap.lean @@ -605,7 +605,7 @@ end private theorem sSup_aux (c : Set (E →ₗ.[R] F)) (hc : DirectedOn (· ≤ ·) c) : ∃ f : ↥(sSup (domain '' c)) →ₗ[R] F, (⟨_, f⟩ : E →ₗ.[R] F) ∈ upperBounds c := by - cases' c.eq_empty_or_nonempty with ceq cne + rcases c.eq_empty_or_nonempty with ceq | cne · subst c simp have hdir : DirectedOn (· ≤ ·) (domain '' c) := diff --git a/Mathlib/LinearAlgebra/Matrix/Adjugate.lean b/Mathlib/LinearAlgebra/Matrix/Adjugate.lean index 0a5a4f347537d..a22097c3e9828 100644 --- a/Mathlib/LinearAlgebra/Matrix/Adjugate.lean +++ b/Mathlib/LinearAlgebra/Matrix/Adjugate.lean @@ -372,7 +372,7 @@ theorem _root_.AlgHom.map_adjugate {R A B : Type*} [CommSemiring R] [CommRing A] theorem det_adjugate (A : Matrix n n α) : (adjugate A).det = A.det ^ (Fintype.card n - 1) := by -- get rid of the `- 1` - cases' (Fintype.card n).eq_zero_or_pos with h_card h_card + rcases (Fintype.card n).eq_zero_or_pos with h_card | h_card · haveI : IsEmpty n := Fintype.card_eq_zero_iff.mp h_card rw [h_card, Nat.zero_sub, pow_zero, adjugate_subsingleton, det_one] replace h_card := tsub_add_cancel_of_le h_card.nat_succ_le diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean index 764e2d8721a22..e9a77c9c386dc 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean @@ -363,7 +363,7 @@ lemma reverse_charpoly (M : Matrix n n R) : eval 0 M.charpolyRev = 1 := by rw [charpolyRev, ← coe_evalRingHom, RingHom.map_det, ← det_one (R := R) (n := n)] have : (1 - (X : R[X]) • M.map C).map (eval 0) = 1 := by - ext i j; cases' eq_or_ne i j with hij hij <;> simp [hij] + ext i j; rcases eq_or_ne i j with hij | hij <;> simp [hij] congr @[simp] lemma coeff_charpolyRev_eq_neg_trace (M : Matrix n n R) : diff --git a/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean b/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean index bf8da90e6373c..cad38b1541dac 100644 --- a/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean +++ b/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean @@ -553,7 +553,7 @@ variable (A) theorem inv_zero : (0 : Matrix n n α)⁻¹ = 0 := by cases' subsingleton_or_nontrivial α with ht ht · simp [eq_iff_true_of_subsingleton] - cases' (Fintype.card n).zero_le.eq_or_lt with hc hc + rcases (Fintype.card n).zero_le.eq_or_lt with hc | hc · rw [eq_comm, Fintype.card_eq_zero_iff] at hc haveI := hc ext i diff --git a/Mathlib/LinearAlgebra/Matrix/Polynomial.lean b/Mathlib/LinearAlgebra/Matrix/Polynomial.lean index 94750ff201f43..fc58bca832d29 100644 --- a/Mathlib/LinearAlgebra/Matrix/Polynomial.lean +++ b/Mathlib/LinearAlgebra/Matrix/Polynomial.lean @@ -92,7 +92,7 @@ theorem leadingCoeff_det_X_one_add_C (A : Matrix n n α) : · simp [eq_iff_true_of_subsingleton] rw [← @det_one n, ← coeff_det_X_add_C_card _ A, leadingCoeff] simp only [Matrix.map_one, C_eq_zero, RingHom.map_one] - cases' (natDegree_det_X_add_C_le 1 A).eq_or_lt with h h + rcases (natDegree_det_X_add_C_le 1 A).eq_or_lt with h | h · simp only [RingHom.map_one, Matrix.map_one, C_eq_zero] at h rw [h] · -- contradiction. we have a hypothesis that the degree is less than |n| diff --git a/Mathlib/LinearAlgebra/Matrix/ZPow.lean b/Mathlib/LinearAlgebra/Matrix/ZPow.lean index 680cb6df6ce60..a013a52cfbef9 100644 --- a/Mathlib/LinearAlgebra/Matrix/ZPow.lean +++ b/Mathlib/LinearAlgebra/Matrix/ZPow.lean @@ -242,7 +242,7 @@ theorem Commute.zpow_zpow_self (A : M) (m n : ℤ) : Commute (A ^ m) (A ^ n) := set_option linter.deprecated false in theorem zpow_bit0 (A : M) (n : ℤ) : A ^ bit0 n = A ^ n * A ^ n := by - cases' le_total 0 n with nonneg nonpos + rcases le_total 0 n with nonneg | nonpos · exact zpow_add_of_nonneg nonneg nonneg · exact zpow_add_of_nonpos nonpos nonpos #align matrix.zpow_bit0 Matrix.zpow_bit0 diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index 1859d0aabf727..1d0e05cec9e24 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -385,7 +385,7 @@ theorem measurable_of_isClosed {f : δ → γ} (hf : ∀ s, IsClosed s → Measu theorem measurable_of_isClosed' {f : δ → γ} (hf : ∀ s, IsClosed s → s.Nonempty → s ≠ univ → MeasurableSet (f ⁻¹' s)) : Measurable f := by apply measurable_of_isClosed; intro s hs - cases' eq_empty_or_nonempty s with h1 h1 + rcases eq_empty_or_nonempty s with h1 | h1 · simp [h1] by_cases h2 : s = univ · simp [h2] diff --git a/Mathlib/MeasureTheory/Constructions/Pi.lean b/Mathlib/MeasureTheory/Constructions/Pi.lean index 6e6367e19080c..f516a4398ddd0 100644 --- a/Mathlib/MeasureTheory/Constructions/Pi.lean +++ b/Mathlib/MeasureTheory/Constructions/Pi.lean @@ -164,7 +164,7 @@ theorem piPremeasure_pi {s : ∀ i, Set (α i)} (hs : (pi univ s).Nonempty) : theorem piPremeasure_pi' {s : ∀ i, Set (α i)} : piPremeasure m (pi univ s) = ∏ i, m i (s i) := by cases isEmpty_or_nonempty ι · simp [piPremeasure] - cases' (pi univ s).eq_empty_or_nonempty with h h + rcases (pi univ s).eq_empty_or_nonempty with h | h · rcases univ_pi_eq_empty_iff.mp h with ⟨i, hi⟩ have : ∃ i, m i (s i) = 0 := ⟨i, by simp [hi]⟩ simpa [h, Finset.card_univ, zero_pow (Fintype.card_pos_iff.mpr ‹_›), @eq_comm _ (0 : ℝ≥0∞), @@ -194,7 +194,7 @@ protected def pi (m : ∀ i, OuterMeasure (α i)) : OuterMeasure (∀ i, α i) : theorem pi_pi_le (m : ∀ i, OuterMeasure (α i)) (s : ∀ i, Set (α i)) : OuterMeasure.pi m (pi univ s) ≤ ∏ i, m i (s i) := by - cases' (pi univ s).eq_empty_or_nonempty with h h; simp [h] + rcases (pi univ s).eq_empty_or_nonempty with h | h; simp [h] exact (boundedBy_le _).trans_eq (piPremeasure_pi h) #align measure_theory.outer_measure.pi_pi_le MeasureTheory.OuterMeasure.pi_pi_le diff --git a/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean b/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean index 1b31646146c92..d4f45067213c0 100644 --- a/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean +++ b/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean @@ -168,7 +168,7 @@ theorem blimsup_cthickening_ae_le_of_eventually_mul_le (p : ℕ → Prop) {s : rw [mul_max_of_nonneg _ _ hM.le, mul_zero] exact max_le_max (le_refl 0) hi simp_rw [← cthickening_max_zero (r₁ _), ← cthickening_max_zero (r₂ _)] - cases' le_or_lt 1 M with hM' hM' + rcases le_or_lt 1 M with hM' | hM' · apply HasSubset.Subset.eventuallyLE change _ ≤ _ refine' mono_blimsup' (hMr.mono fun i hi _ => cthickening_mono _ (s i)) diff --git a/Mathlib/MeasureTheory/Function/Floor.lean b/Mathlib/MeasureTheory/Function/Floor.lean index 286f833e65eb3..88a1d03ca7991 100644 --- a/Mathlib/MeasureTheory/Function/Floor.lean +++ b/Mathlib/MeasureTheory/Function/Floor.lean @@ -71,7 +71,7 @@ variable {α R : Type*} [MeasurableSpace α] [LinearOrderedSemiring R] [FloorSem theorem Nat.measurable_floor : Measurable (Nat.floor : R → ℕ) := measurable_to_countable fun n => by - cases' eq_or_ne ⌊n⌋₊ 0 with h h <;> simp_all [h, Nat.preimage_floor_of_ne_zero, -floor_eq_zero] + rcases eq_or_ne ⌊n⌋₊ 0 with h | h <;> simp [h, Nat.preimage_floor_of_ne_zero, -floor_eq_zero] #align nat.measurable_floor Nat.measurable_floor @[measurability] @@ -81,7 +81,7 @@ theorem Measurable.nat_floor (hf : Measurable f) : Measurable fun x => ⌊f x⌋ theorem Nat.measurable_ceil : Measurable (Nat.ceil : R → ℕ) := measurable_to_countable fun n => by - cases' eq_or_ne ⌈n⌉₊ 0 with h h <;> simp_all [h, Nat.preimage_ceil_of_ne_zero, -ceil_eq_zero] + rcases eq_or_ne ⌈n⌉₊ 0 with h | h <;> simp_all [h, Nat.preimage_ceil_of_ne_zero, -ceil_eq_zero] #align nat.measurable_ceil Nat.measurable_ceil @[measurability] diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm.lean b/Mathlib/MeasureTheory/Function/LpSeminorm.lean index d24786a3e186c..6a9a54643d89d 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm.lean @@ -187,7 +187,7 @@ theorem snorm'_zero (hp0_lt : 0 < q) : snorm' (0 : α → F) q μ = 0 := by simp @[simp] theorem snorm'_zero' (hq0_ne : q ≠ 0) (hμ : μ ≠ 0) : snorm' (0 : α → F) q μ = 0 := by - cases' le_or_lt 0 q with hq0 hq_neg + rcases le_or_lt 0 q with hq0 | hq_neg · exact snorm'_zero (lt_of_le_of_ne hq0 hq0_ne.symm) · simp [snorm', ENNReal.rpow_eq_zero_iff, hμ, hq_neg] #align measure_theory.snorm'_zero' MeasureTheory.snorm'_zero' @@ -1135,7 +1135,7 @@ theorem snorm_le_snorm_of_exponent_le {p q : ℝ≥0∞} (hpq : p ≤ q) [IsProb theorem snorm'_lt_top_of_snorm'_lt_top_of_exponent_le {p q : ℝ} [IsFiniteMeasure μ] {f : α → E} (hf : AEStronglyMeasurable f μ) (hfq_lt_top : snorm' f q μ < ∞) (hp_nonneg : 0 ≤ p) (hpq : p ≤ q) : snorm' f p μ < ∞ := by - cases' le_or_lt p 0 with hp_nonpos hp_pos + rcases le_or_lt p 0 with hp_nonpos | hp_pos · rw [le_antisymm hp_nonpos hp_nonneg] simp have hq_pos : 0 < q := lt_of_lt_of_le hp_pos hpq diff --git a/Mathlib/MeasureTheory/Function/LpSpace.lean b/Mathlib/MeasureTheory/Function/LpSpace.lean index e6d0c7dda26d5..660d0f2916f7c 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace.lean @@ -374,7 +374,7 @@ theorem nnnorm_le_mul_nnnorm_of_ae_le_mul {c : ℝ≥0} {f : Lp E p μ} {g : Lp theorem norm_le_mul_norm_of_ae_le_mul {c : ℝ} {f : Lp E p μ} {g : Lp F p μ} (h : ∀ᵐ x ∂μ, ‖f x‖ ≤ c * ‖g x‖) : ‖f‖ ≤ c * ‖g‖ := by - cases' le_or_lt 0 c with hc hc + rcases le_or_lt 0 c with hc | hc · lift c to ℝ≥0 using hc exact NNReal.coe_le_coe.mpr (nnnorm_le_mul_nnnorm_of_ae_le_mul h) · simp only [norm_def] diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean index 7dcb794bcdbd9..767033402dcb6 100644 --- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean +++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean @@ -244,7 +244,7 @@ theorem norm_approxBounded_le {β} {f : α → β} [SeminormedAddCommGroup β] [ by_cases h0 : ‖hf.approx n x‖ = 0 · simp only [h0, _root_.div_zero, min_eq_right, zero_le_one, norm_zero, mul_zero] exact hc - cases' le_total ‖hf.approx n x‖ c with h h + rcases le_total ‖hf.approx n x‖ c with h | h · rw [min_eq_left _] · simpa only [norm_one, one_mul] using h · rwa [one_le_div (lt_of_le_of_ne (norm_nonneg _) (Ne.symm h0))] diff --git a/Mathlib/MeasureTheory/Group/AddCircle.lean b/Mathlib/MeasureTheory/Group/AddCircle.lean index 6f2dd41d25695..42071dca59e81 100644 --- a/Mathlib/MeasureTheory/Group/AddCircle.lean +++ b/Mathlib/MeasureTheory/Group/AddCircle.lean @@ -32,7 +32,7 @@ namespace AddCircle variable {T : ℝ} [hT : Fact (0 < T)] theorem closedBall_ae_eq_ball {x : AddCircle T} {ε : ℝ} : closedBall x ε =ᵐ[volume] ball x ε := by - cases' le_or_lt ε 0 with hε hε + rcases le_or_lt ε 0 with hε | hε · rw [ball_eq_empty.mpr hε, ae_eq_empty, volume_closedBall, min_eq_right (by linarith [hT.out] : 2 * ε ≤ T), ENNReal.ofReal_eq_zero] exact mul_nonpos_of_nonneg_of_nonpos zero_le_two hε diff --git a/Mathlib/MeasureTheory/Integral/Average.lean b/Mathlib/MeasureTheory/Integral/Average.lean index 707385eba14de..0ab88a92a7ce6 100644 --- a/Mathlib/MeasureTheory/Integral/Average.lean +++ b/Mathlib/MeasureTheory/Integral/Average.lean @@ -99,7 +99,7 @@ theorem laverage_eq_lintegral [IsProbabilityMeasure μ] (f : α → ℝ≥0∞) @[simp] theorem measure_mul_laverage [IsFiniteMeasure μ] (f : α → ℝ≥0∞) : μ univ * ⨍⁻ x, f x ∂μ = ∫⁻ x, f x ∂μ := by - cases' eq_or_ne μ 0 with hμ hμ + rcases eq_or_ne μ 0 with hμ | hμ · rw [hμ, lintegral_zero_measure, laverage_zero_measure, mul_zero] · rw [laverage_eq, ENNReal.mul_div_cancel' (measure_univ_ne_zero.2 hμ) (measure_ne_top _ _)] #align measure_theory.measure_mul_laverage MeasureTheory.measure_mul_laverage @@ -289,7 +289,7 @@ theorem average_eq_integral [IsProbabilityMeasure μ] (f : α → E) : ⨍ x, f @[simp] theorem measure_smul_average [IsFiniteMeasure μ] (f : α → E) : (μ univ).toReal • ⨍ x, f x ∂μ = ∫ x, f x ∂μ := by - cases' eq_or_ne μ 0 with hμ hμ + rcases eq_or_ne μ 0 with hμ | hμ · rw [hμ, integral_zero_measure, average_zero_measure, smul_zero] · rw [average_eq, smul_inv_smul₀] refine' (ENNReal.toReal_pos _ <| measure_ne_top _ _).ne' diff --git a/Mathlib/MeasureTheory/Integral/CircleIntegral.lean b/Mathlib/MeasureTheory/Integral/CircleIntegral.lean index a009b1a5ce5a5..84c2fba843097 100644 --- a/Mathlib/MeasureTheory/Integral/CircleIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/CircleIntegral.lean @@ -565,7 +565,7 @@ theorem le_radius_cauchyPowerSeries (f : ℂ → E) (c : ℂ) (R : ℝ≥0) : refine' (mul_le_mul_of_nonneg_right (norm_cauchyPowerSeries_le _ _ _ _) (pow_nonneg R.coe_nonneg _)).trans _ rw [_root_.abs_of_nonneg R.coe_nonneg] - cases' eq_or_ne (R ^ n : ℝ) 0 with hR hR + rcases eq_or_ne (R ^ n : ℝ) 0 with hR | hR · rw_mod_cast [hR, mul_zero] exact mul_nonneg (inv_nonneg.2 Real.two_pi_pos.le) (intervalIntegral.integral_nonneg Real.two_pi_pos.le fun _ _ => norm_nonneg _) diff --git a/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean b/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean index b4d52eb14ae5f..735bce0dda645 100644 --- a/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean +++ b/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean @@ -419,7 +419,7 @@ theorem integral_eq_of_has_deriv_within_at_off_countable (f f' : ℝ → E) {a b (hs : s.Countable) (Hc : ContinuousOn f [[a, b]]) (Hd : ∀ x ∈ Ioo (min a b) (max a b) \ s, HasDerivAt f (f' x) x) (Hi : IntervalIntegrable f' volume a b) : ∫ x in a..b, f' x = f b - f a := by - cases' le_total a b with hab hab + rcases le_total a b with hab | hab · simp only [uIcc_of_le hab, min_eq_left hab, max_eq_right hab] at * exact integral_eq_of_hasDerivWithinAt_off_countable_of_le f f' hab hs Hc Hd Hi · simp only [uIcc_of_ge hab, min_eq_right hab, max_eq_left hab] at * diff --git a/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean index edff5f8d486e1..f2ffc0559bbf4 100644 --- a/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean +++ b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean @@ -1187,7 +1187,7 @@ theorem integral_eq_sub_of_hasDeriv_right_of_le (hab : a ≤ b) (hcont : Continu theorem integral_eq_sub_of_hasDeriv_right (hcont : ContinuousOn f (uIcc a b)) (hderiv : ∀ x ∈ Ioo (min a b) (max a b), HasDerivWithinAt f (f' x) (Ioi x) x) (hint : IntervalIntegrable f' volume a b) : ∫ y in a..b, f' y = f b - f a := by - cases' le_total a b with hab hab + rcases le_total a b with hab | hab · simp only [uIcc_of_le, min_eq_left, max_eq_right, hab] at hcont hderiv hint apply integral_eq_sub_of_hasDeriv_right_of_le hab hcont hderiv hint · simp only [uIcc_of_ge, min_eq_right, max_eq_left, hab] at hcont hderiv @@ -1322,7 +1322,7 @@ interval version. -/ theorem intervalIntegrable_deriv_of_nonneg (hcont : ContinuousOn g (uIcc a b)) (hderiv : ∀ x ∈ Ioo (min a b) (max a b), HasDerivAt g (g' x) x) (hpos : ∀ x ∈ Ioo (min a b) (max a b), 0 ≤ g' x) : IntervalIntegrable g' volume a b := by - cases' le_total a b with hab hab + rcases le_total a b with hab | hab · simp only [uIcc_of_le, min_eq_left, max_eq_right, hab, IntervalIntegrable, hab, Ioc_eq_empty_of_le, integrableOn_empty, and_true_iff] at hcont hderiv hpos ⊢ exact integrableOn_deriv_of_nonneg hcont hderiv hpos diff --git a/Mathlib/MeasureTheory/Integral/IntervalAverage.lean b/Mathlib/MeasureTheory/Integral/IntervalAverage.lean index 5b62fdb5c14d1..798e811cc2f19 100644 --- a/Mathlib/MeasureTheory/Integral/IntervalAverage.lean +++ b/Mathlib/MeasureTheory/Integral/IntervalAverage.lean @@ -42,7 +42,7 @@ theorem interval_average_symm (f : ℝ → E) (a b : ℝ) : (⨍ x in a..b, f x) theorem interval_average_eq (f : ℝ → E) (a b : ℝ) : (⨍ x in a..b, f x) = (b - a)⁻¹ • ∫ x in a..b, f x := by - cases' le_or_lt a b with h h + rcases le_or_lt a b with h | h · rw [setAverage_eq, uIoc_of_le h, Real.volume_Ioc, intervalIntegral.integral_of_le h, ENNReal.toReal_ofReal (sub_nonneg.2 h)] · rw [setAverage_eq, uIoc_of_lt h, Real.volume_Ioc, intervalIntegral.integral_of_ge h.le, diff --git a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean index cbfc79abcb452..f67d7438900c9 100644 --- a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean @@ -884,7 +884,7 @@ variable {a b c d : ℝ} {f g : ℝ → E} {μ : Measure ℝ} /-- If two functions are equal in the relevant interval, their interval integrals are also equal. -/ theorem integral_congr {a b : ℝ} (h : EqOn f g [[a, b]]) : ∫ x in a..b, f x ∂μ = ∫ x in a..b, g x ∂μ := by - cases' le_total a b with hab hab <;> + rcases le_total a b with hab | hab <;> simpa [hab, integral_of_le, integral_of_ge] using set_integral_congr measurableSet_Ioc (h.mono Ioc_subset_Icc_self) #align interval_integral.integral_congr intervalIntegral.integral_congr @@ -981,7 +981,7 @@ theorem integral_const_of_cdf [IsFiniteMeasure μ] (c : E) : theorem integral_eq_integral_of_support_subset {a b} (h : support f ⊆ Ioc a b) : ∫ x in a..b, f x ∂μ = ∫ x, f x ∂μ := by - cases' le_total a b with hab hab + rcases le_total a b with hab | hab · rw [integral_of_le hab, ← integral_indicator measurableSet_Ioc, indicator_eq_self.2 h] · rw [Ioc_eq_empty hab.not_lt, subset_empty_iff, support_eq_empty_iff] at h simp [h] @@ -1272,7 +1272,7 @@ theorem integral_eq_zero_iff_of_le_of_nonneg_ae (hab : a ≤ b) (hf : 0 ≤ᵐ[ theorem integral_eq_zero_iff_of_nonneg_ae (hf : 0 ≤ᵐ[μ.restrict (Ioc a b ∪ Ioc b a)] f) (hfi : IntervalIntegrable f μ a b) : ∫ x in a..b, f x ∂μ = 0 ↔ f =ᵐ[μ.restrict (Ioc a b ∪ Ioc b a)] 0 := by - cases' le_total a b with hab hab <;> + rcases le_total a b with hab | hab <;> simp only [Ioc_eq_empty hab.not_lt, empty_union, union_empty] at hf ⊢ · exact integral_eq_zero_iff_of_le_of_nonneg_ae hab hf hfi · rw [integral_symm, neg_eq_zero, integral_eq_zero_iff_of_le_of_nonneg_ae hab hf hfi.symm] diff --git a/Mathlib/MeasureTheory/Integral/Lebesgue.lean b/Mathlib/MeasureTheory/Integral/Lebesgue.lean index 4a2d20e9efe90..930cb66d02577 100644 --- a/Mathlib/MeasureTheory/Integral/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Integral/Lebesgue.lean @@ -175,7 +175,7 @@ variable (μ) integral. -/ theorem exists_measurable_le_lintegral_eq (f : α → ℝ≥0∞) : ∃ g : α → ℝ≥0∞, Measurable g ∧ g ≤ f ∧ ∫⁻ a, f a ∂μ = ∫⁻ a, g a ∂μ := by - cases' eq_or_ne (∫⁻ a, f a ∂μ) 0 with h₀ h₀ + rcases eq_or_ne (∫⁻ a, f a ∂μ) 0 with h₀ | h₀ · exact ⟨0, measurable_zero, zero_le f, h₀.trans lintegral_zero.symm⟩ rcases exists_seq_strictMono_tendsto' h₀.bot_lt with ⟨L, _, hLf, hL_tendsto⟩ have : ∀ n, ∃ g : α → ℝ≥0∞, Measurable g ∧ g ≤ f ∧ L n < ∫⁻ a, g a ∂μ := by diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean index b26484b265459..693bd732c56d4 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean @@ -799,7 +799,7 @@ theorem measurableSet_prod_of_nonempty {s : Set α} {t : Set β} (h : (s ×ˢ t) theorem measurableSet_prod {s : Set α} {t : Set β} : MeasurableSet (s ×ˢ t) ↔ MeasurableSet s ∧ MeasurableSet t ∨ s = ∅ ∨ t = ∅ := by - cases' (s ×ˢ t).eq_empty_or_nonempty with h h + rcases (s ×ˢ t).eq_empty_or_nonempty with h | h · simp [h, prod_eq_empty_iff.mp h] · simp [← not_nonempty_iff_eq_empty, prod_nonempty_iff.mp h, measurableSet_prod_of_nonempty h] #align measurable_set_prod measurableSet_prod @@ -1001,7 +1001,7 @@ theorem measurableSet_pi_of_nonempty {s : Set δ} {t : ∀ i, Set (π i)} (hs : theorem measurableSet_pi {s : Set δ} {t : ∀ i, Set (π i)} (hs : s.Countable) : MeasurableSet (pi s t) ↔ (∀ i ∈ s, MeasurableSet (t i)) ∨ pi s t = ∅ := by - cases' (pi s t).eq_empty_or_nonempty with h h + rcases (pi s t).eq_empty_or_nonempty with h | h · simp [h] · simp [measurableSet_pi_of_nonempty hs, h, ← not_nonempty_iff_eq_empty] #align measurable_set_pi measurableSet_pi diff --git a/Mathlib/MeasureTheory/Measure/Content.lean b/Mathlib/MeasureTheory/Measure/Content.lean index 284607820a407..c261ca165a967 100644 --- a/Mathlib/MeasureTheory/Measure/Content.lean +++ b/Mathlib/MeasureTheory/Measure/Content.lean @@ -157,7 +157,7 @@ theorem innerContent_mono ⦃U V : Set G⦄ (hU : IsOpen U) (hV : IsOpen V) (h2 theorem innerContent_exists_compact {U : Opens G} (hU : μ.innerContent U ≠ ∞) {ε : ℝ≥0} (hε : ε ≠ 0) : ∃ K : Compacts G, (K : Set G) ⊆ U ∧ μ.innerContent U ≤ μ K + ε := by have h'ε := ENNReal.coe_ne_zero.2 hε - cases' le_or_lt (μ.innerContent U) ε with h h + rcases le_or_lt (μ.innerContent U) ε with h | h · exact ⟨⊥, empty_subset _, le_add_left h⟩ have h₂ := ENNReal.sub_lt_self hU h.ne_bot h'ε conv at h₂ => rhs; rw [innerContent] diff --git a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean index 7e76cfb3bbd71..df3842c6384b2 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean @@ -146,7 +146,7 @@ theorem parallelepiped_single [DecidableEq ι] (a : ι → ℝ) : · rintro ⟨t, ht, rfl⟩ i specialize ht i simp_rw [smul_eq_mul, Pi.mul_apply] - cases' le_total (a i) 0 with hai hai + rcases le_total (a i) 0 with hai | hai · rw [sup_eq_left.mpr hai, inf_eq_right.mpr hai] exact ⟨le_mul_of_le_one_left hai ht.2, mul_nonpos_of_nonneg_of_nonpos ht.1 hai⟩ · rw [sup_eq_right.mpr hai, inf_eq_left.mpr hai] @@ -154,14 +154,14 @@ theorem parallelepiped_single [DecidableEq ι] (a : ι → ℝ) : · intro h refine' ⟨fun i => x i / a i, fun i => _, funext fun i => _⟩ · specialize h i - cases' le_total (a i) 0 with hai hai + rcases le_total (a i) 0 with hai | hai · rw [sup_eq_left.mpr hai, inf_eq_right.mpr hai] at h exact ⟨div_nonneg_of_nonpos h.2 hai, div_le_one_of_ge h.1 hai⟩ · rw [sup_eq_right.mpr hai, inf_eq_left.mpr hai] at h exact ⟨div_nonneg h.1 hai, div_le_one_of_le h.2 hai⟩ · specialize h i simp only [smul_eq_mul, Pi.mul_apply] - cases' eq_or_ne (a i) 0 with hai hai + rcases eq_or_ne (a i) 0 with hai | hai · rw [hai, inf_idem, sup_idem, ← le_antisymm_iff] at h rw [hai, ← h, zero_div, zero_mul] · rw [div_mul_cancel _ hai] diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index 44c3e38c25fa5..3bcad6db9513c 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -1077,7 +1077,7 @@ theorem _root_.MeasureTheory.OuterMeasure.toMeasure_top [MeasurableSpace α] : (⊤ : OuterMeasure α).toMeasure (by rw [OuterMeasure.top_caratheodory]; exact le_top) = (⊤ : Measure α) := top_unique fun s hs => by - cases' s.eq_empty_or_nonempty with h h <;> + rcases s.eq_empty_or_nonempty with h | h <;> simp [h, toMeasure_apply ⊤ _ hs, OuterMeasure.top_apply] #align measure_theory.outer_measure.to_measure_top MeasureTheory.OuterMeasure.toMeasure_top diff --git a/Mathlib/MeasureTheory/Measure/OuterMeasure.lean b/Mathlib/MeasureTheory/Measure/OuterMeasure.lean index b301365a0201a..c1964dc75cf8e 100644 --- a/Mathlib/MeasureTheory/Measure/OuterMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/OuterMeasure.lean @@ -200,7 +200,7 @@ theorem iUnion_nat_of_monotone_of_tsum_ne_top (m : OuterMeasure α) {s : ℕ → have : ∃i, x ∈ s i := by exists i rcases Nat.findX this with ⟨j, hj, hlt⟩ clear hx i - cases' le_or_lt j n with hjn hnj + rcases le_or_lt j n with hjn | hnj · exact Or.inl (h' hjn hj) have : j - (n + 1) + n + 1 = j := by rw [add_assoc, tsub_add_cancel_of_le hnj.nat_succ_le] refine' Or.inr (mem_iUnion.2 ⟨j - (n + 1), _, hlt _ _⟩) @@ -840,7 +840,7 @@ theorem boundedBy_eq_ofFunction (m_empty : m ∅ = 0) (s : Set α) : boundedBy m s = OuterMeasure.ofFunction m m_empty s := by have : (fun s : Set α => ⨆ _ : s.Nonempty, m s) = m := by ext1 t - cases' t.eq_empty_or_nonempty with h h <;> simp [h, Set.not_nonempty_empty, m_empty] + rcases t.eq_empty_or_nonempty with h | h <;> simp [h, Set.not_nonempty_empty, m_empty] simp [boundedBy, this] #align measure_theory.outer_measure.bounded_by_eq_of_function MeasureTheory.OuterMeasure.boundedBy_eq_ofFunction @@ -862,14 +862,14 @@ theorem boundedBy_eq_self (m : OuterMeasure α) : boundedBy m = m := theorem le_boundedBy {μ : OuterMeasure α} : μ ≤ boundedBy m ↔ ∀ s, μ s ≤ m s := by rw [boundedBy , le_ofFunction, forall_congr']; intro s - cases' s.eq_empty_or_nonempty with h h <;> simp [h, Set.not_nonempty_empty] + rcases s.eq_empty_or_nonempty with h | h <;> simp [h, Set.not_nonempty_empty] #align measure_theory.outer_measure.le_bounded_by MeasureTheory.OuterMeasure.le_boundedBy theorem le_boundedBy' {μ : OuterMeasure α} : μ ≤ boundedBy m ↔ ∀ s : Set α, s.Nonempty → μ s ≤ m s := by rw [le_boundedBy, forall_congr'] intro s - cases' s.eq_empty_or_nonempty with h h <;> simp [h] + rcases s.eq_empty_or_nonempty with h | h <;> simp [h] #align measure_theory.outer_measure.le_bounded_by' MeasureTheory.OuterMeasure.le_boundedBy' @[simp] @@ -1077,7 +1077,7 @@ theorem ofFunction_caratheodory {m : Set α → ℝ≥0∞} {s : Set α} {h₀ : theorem boundedBy_caratheodory {m : Set α → ℝ≥0∞} {s : Set α} (hs : ∀ t, m (t ∩ s) + m (t \ s) ≤ m t) : MeasurableSet[(boundedBy m).caratheodory] s := by apply ofFunction_caratheodory; intro t - cases' t.eq_empty_or_nonempty with h h + rcases t.eq_empty_or_nonempty with h | h · simp [h, Set.not_nonempty_empty] · convert le_trans _ (hs t) · simp [h] diff --git a/Mathlib/MeasureTheory/Measure/Regular.lean b/Mathlib/MeasureTheory/Measure/Regular.lean index b10ae518d1f1a..f425a92eedefc 100644 --- a/Mathlib/MeasureTheory/Measure/Regular.lean +++ b/Mathlib/MeasureTheory/Measure/Regular.lean @@ -221,7 +221,7 @@ theorem measure_eq_iSup (H : InnerRegularWRT μ p q) (hU : q U) : theorem exists_subset_lt_add (H : InnerRegularWRT μ p q) (h0 : p ∅) (hU : q U) (hμU : μ U ≠ ∞) (hε : ε ≠ 0) : ∃ K, K ⊆ U ∧ p K ∧ μ U < μ K + ε := by - cases' eq_or_ne (μ U) 0 with h₀ h₀ + rcases eq_or_ne (μ U) 0 with h₀ | h₀ · 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⟩ diff --git a/Mathlib/MeasureTheory/Measure/Restrict.lean b/Mathlib/MeasureTheory/Measure/Restrict.lean index 8b4146a28fd87..79e243edbdd94 100644 --- a/Mathlib/MeasureTheory/Measure/Restrict.lean +++ b/Mathlib/MeasureTheory/Measure/Restrict.lean @@ -494,7 +494,7 @@ theorem ext_of_generateFrom_of_cover_subset {S T : Set (Set α)} (h_gen : ‹_ (h_inter : IsPiSystem S) (h_sub : T ⊆ S) (hc : T.Countable) (hU : ⋃₀ T = univ) (htop : ∀ s ∈ T, μ s ≠ ∞) (h_eq : ∀ s ∈ S, μ s = ν s) : μ = ν := by refine' ext_of_generateFrom_of_cover h_gen hc h_inter hU htop _ fun t ht => h_eq t (h_sub ht) - intro t ht s hs; cases' (s ∩ t).eq_empty_or_nonempty with H H + intro t ht s hs; rcases (s ∩ t).eq_empty_or_nonempty with H | H · simp only [H, measure_empty] · exact h_eq _ (h_inter _ hs _ (h_sub ht) H) #align measure_theory.measure.ext_of_generate_from_of_cover_subset MeasureTheory.Measure.ext_of_generateFrom_of_cover_subset diff --git a/Mathlib/MeasureTheory/Measure/Stieltjes.lean b/Mathlib/MeasureTheory/Measure/Stieltjes.lean index 7b235e52ad43b..a509618dc0689 100644 --- a/Mathlib/MeasureTheory/Measure/Stieltjes.lean +++ b/Mathlib/MeasureTheory/Measure/Stieltjes.lean @@ -160,7 +160,7 @@ theorem length_Ioc (a b : ℝ) : f.length (Ioc a b) = ofReal (f b - f a) := by refine' le_antisymm (iInf_le_of_le a <| iInf₂_le b Subset.rfl) (le_iInf fun a' => le_iInf fun b' => le_iInf fun h => ENNReal.coe_le_coe.2 _) - cases' le_or_lt b a with ab ab + rcases le_or_lt b a with ab | ab · rw [Real.toNNReal_of_nonpos (sub_nonpos.2 (f.mono ab))] apply zero_le cases' (Ioc_subset_Ioc_iff ab).1 h with h₁ h₂ @@ -202,7 +202,7 @@ theorem length_subadditive_Icc_Ioo {a b : ℝ} {c d : ℕ → ℝ} (ss : Icc a b exact this hf.toFinset _ (by simpa only [e] ) clear ss b refine' fun s => Finset.strongInductionOn s fun s IH b cv => _ - cases' le_total b a with ab ab + rcases le_total b a with ab | ab · rw [ENNReal.ofReal_eq_zero.2 (sub_nonpos.2 (f.mono ab))] exact zero_le _ have := cv ⟨ab, le_rfl⟩ @@ -291,7 +291,7 @@ theorem measurableSet_Ioi {c : ℝ} : MeasurableSet[f.outer.caratheodory] (Ioi c le_trans (add_le_add (f.length_mono <| inter_subset_inter_left _ h) (f.length_mono <| diff_subset_diff_left h)) _ - cases' le_total a c with hac hac <;> cases' le_total b c with hbc hbc + rcases le_total a c with hac | hac <;> rcases le_total b c with hbc | hbc · simp only [Ioc_inter_Ioi, f.length_Ioc, hac, _root_.sup_eq_max, hbc, le_refl, Ioc_eq_empty, max_eq_right, min_eq_left, Ioc_diff_Ioi, f.length_empty, zero_add, not_lt] · simp only [hac, hbc, Ioc_inter_Ioi, Ioc_diff_Ioi, f.length_Ioc, min_eq_right, diff --git a/Mathlib/ModelTheory/FinitelyGenerated.lean b/Mathlib/ModelTheory/FinitelyGenerated.lean index 00481cef85d53..3d529a976350f 100644 --- a/Mathlib/ModelTheory/FinitelyGenerated.lean +++ b/Mathlib/ModelTheory/FinitelyGenerated.lean @@ -118,7 +118,7 @@ theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} : rw [cg_def] constructor · rintro ⟨S, Scount, hS⟩ - cases' eq_empty_or_nonempty (N : Set M) with h h + rcases eq_empty_or_nonempty (N : Set M) with h | h · exact Or.intro_left _ h obtain ⟨f, h'⟩ := (Scount.union (Set.countable_singleton h.some)).exists_eq_range diff --git a/Mathlib/NumberTheory/Dioph.lean b/Mathlib/NumberTheory/Dioph.lean index 74b7ef18f145f..955adcf842ad2 100644 --- a/Mathlib/NumberTheory/Dioph.lean +++ b/Mathlib/NumberTheory/Dioph.lean @@ -659,7 +659,7 @@ theorem sub_dioph : DiophFn fun v => f v - g v := · rw [ae, add_tsub_cancel_right] · rw [x0, tsub_eq_zero_iff_le.mpr yz], by rintro rfl - cases' le_total y z with yz zy + rcases 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⟩ #align dioph.sub_dioph Dioph.sub_dioph diff --git a/Mathlib/NumberTheory/DiophantineApproximation.lean b/Mathlib/NumberTheory/DiophantineApproximation.lean index 6e421ac4f473f..b0d912b7c417a 100644 --- a/Mathlib/NumberTheory/DiophantineApproximation.lean +++ b/Mathlib/NumberTheory/DiophantineApproximation.lean @@ -545,7 +545,7 @@ theorem exists_rat_eq_convergent' {v : ℕ} (h' : ContfracLegendre.Ass ξ u v) : exact False.elim (lt_irrefl _ <| (abs_nonneg ξ).trans_lt h) · rw [Nat.cast_one, div_one] obtain ⟨_, h₁, h₂⟩ := h - cases' le_or_lt (u : ℝ) ξ with ht ht + rcases le_or_lt (u : ℝ) ξ with ht | ht · use 0 rw [convergent_zero, Rat.coe_int_inj, eq_comm, floor_eq_iff] convert And.intro ht (sub_lt_iff_lt_add'.mp (abs_lt.mp h₂).2) <;> norm_num @@ -553,7 +553,7 @@ theorem exists_rat_eq_convergent' {v : ℕ} (h' : ContfracLegendre.Ass ξ u v) : have hξ₁ : ⌊ξ⌋ = u - 1 := by rw [floor_eq_iff, cast_sub, cast_one, sub_add_cancel] exact ⟨(((sub_lt_sub_iff_left _).mpr one_half_lt_one).trans h₁).le, ht⟩ - cases' eq_or_ne ξ ⌊ξ⌋ with Hξ Hξ + rcases eq_or_ne ξ ⌊ξ⌋ with Hξ | Hξ · rw [Hξ, hξ₁, cast_sub, cast_one, ← sub_eq_add_neg, sub_lt_sub_iff_left] at h₁ exact False.elim (lt_irrefl _ <| h₁.trans one_half_lt_one) · have hξ₂ : ⌊(fract ξ)⁻¹⌋ = 1 := by diff --git a/Mathlib/NumberTheory/LegendreSymbol/Basic.lean b/Mathlib/NumberTheory/LegendreSymbol/Basic.lean index fe740c8c7086f..18ca71944909a 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/Basic.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/Basic.lean @@ -112,7 +112,7 @@ namespace legendreSym /-- We have the congruence `legendreSym p a ≡ a ^ (p / 2) mod p`. -/ theorem eq_pow (a : ℤ) : (legendreSym p a : ZMod p) = (a : ZMod p) ^ (p / 2) := by - cases' eq_or_ne (ringChar (ZMod p)) 2 with hc hc + rcases eq_or_ne (ringChar (ZMod p)) 2 with hc | hc · by_cases ha : (a : ZMod p) = 0 · rw [legendreSym, ha, quadraticChar_zero, zero_pow (Nat.div_pos (@Fact.out p.Prime).two_le (succ_pos 1))] diff --git a/Mathlib/NumberTheory/LegendreSymbol/GaussSum.lean b/Mathlib/NumberTheory/LegendreSymbol/GaussSum.lean index 59cbd04d59fc9..5b0c5da32cb98 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/GaussSum.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/GaussSum.lean @@ -96,7 +96,7 @@ variable {R : Type u} [Field R] [Fintype R] {R' : Type v} [CommRing R'] [IsDomai -- Is this useful enough in other contexts to be public? private theorem gaussSum_mul_aux {χ : MulChar R R'} (hχ : IsNontrivial χ) (ψ : AddChar R R') (b : R) : ∑ a, χ (a * b⁻¹) * ψ (a - b) = ∑ c, χ c * ψ (b * (c - 1)) := by - cases' eq_or_ne b 0 with hb hb + rcases eq_or_ne b 0 with hb | hb · -- case `b = 0` simp only [hb, inv_zero, mul_zero, MulChar.map_zero, zero_mul, Finset.sum_const_zero, map_zero_one, mul_one] diff --git a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean index 6f3f7f408fb70..a0193c29a16f0 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean @@ -180,7 +180,7 @@ protected theorem ne_zero {a : ℤ} {b : ℕ} (h : a.gcd b = 1) : J(a | b) ≠ 0 /-- The symbol `J(a | b)` vanishes if and only if `b ≠ 0` and `a` and `b` are not coprime. -/ theorem eq_zero_iff {a : ℤ} {b : ℕ} : J(a | b) = 0 ↔ b ≠ 0 ∧ a.gcd b ≠ 1 := ⟨fun h => by - cases' eq_or_ne b 0 with hb hb + rcases eq_or_ne b 0 with hb | hb · rw [hb, zero_right] at h; cases h exact ⟨hb, mt jacobiSym.ne_zero <| Classical.not_not.2 h⟩, fun ⟨hb, h⟩ => by rw [← neZero_iff] at hb; exact eq_zero_iff_not_coprime.2 h⟩ diff --git a/Mathlib/NumberTheory/LegendreSymbol/QuadraticReciprocity.lean b/Mathlib/NumberTheory/LegendreSymbol/QuadraticReciprocity.lean index 7f6f58054006a..f7175a02418b5 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/QuadraticReciprocity.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/QuadraticReciprocity.lean @@ -137,7 +137,7 @@ theorem quadratic_reciprocity (hp : p ≠ 2) (hq : q ≠ 2) (hpq : p ≠ q) : `(q / p) = (-1)^((p-1)(q-1)/4) * (p / q)`. -/ theorem quadratic_reciprocity' (hp : p ≠ 2) (hq : q ≠ 2) : legendreSym q p = (-1) ^ (p / 2 * (q / 2)) * legendreSym p q := by - cases' eq_or_ne p q with h h + rcases eq_or_ne p q with h | h · subst p rw [(eq_zero_iff q q).mpr (mod_cast nat_cast_self q), mul_zero] · have qr := congr_arg (· * legendreSym p q) (quadratic_reciprocity hp hq h) @@ -172,7 +172,7 @@ open legendreSym `p` is a square mod `q`. -/ theorem exists_sq_eq_prime_iff_of_mod_four_eq_one (hp1 : p % 4 = 1) (hq1 : q ≠ 2) : IsSquare (q : ZMod p) ↔ IsSquare (p : ZMod q) := by - cases' eq_or_ne p q with h h + rcases eq_or_ne p q with h | h · subst p; rfl · rw [← eq_one_iff' p (prime_ne_zero p q h), ← eq_one_iff' q (prime_ne_zero q p h.symm), quadratic_reciprocity_one_mod_four hp1 hq1] diff --git a/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean b/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean index a80c8959bdb93..b9873374f6f3b 100644 --- a/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean +++ b/Mathlib/NumberTheory/Liouville/LiouvilleWith.lean @@ -360,7 +360,7 @@ theorem frequently_exists_num (hx : Liouville x) (n : ℕ) : rcases (this.and (eventually_ge_atTop n)).exists with ⟨m, hm, hnm⟩ rcases hx m with ⟨a, b, hb, hne, hlt⟩ lift b to ℕ using zero_le_one.trans hb.le; norm_cast at hb; push_cast at hne hlt - cases' le_or_lt N b with h h + rcases le_or_lt N b with h | h · refine' (hN b h a hne).not_lt (hlt.trans_le _) gcongr exact_mod_cast hb.le diff --git a/Mathlib/NumberTheory/Pell.lean b/Mathlib/NumberTheory/Pell.lean index 8cd4d4e8bbc30..aa5e779fbb3f7 100644 --- a/Mathlib/NumberTheory/Pell.lean +++ b/Mathlib/NumberTheory/Pell.lean @@ -267,7 +267,7 @@ theorem x_mul_pos {a b : Solution₁ d} (ha : 0 < a.x) (hb : 0 < b.x) : 0 < (a * rw [← abs_of_pos ha, ← abs_of_pos hb, ← abs_mul, ← sq_lt_sq, mul_pow a.x, a.prop_x, b.prop_x, ← sub_pos] ring_nf - cases' le_or_lt 0 d with h h + rcases le_or_lt 0 d with h | h · positivity · rw [(eq_zero_of_d_neg h a).resolve_left ha.ne', (eq_zero_of_d_neg h b).resolve_left hb.ne'] -- Porting note: was @@ -552,7 +552,7 @@ theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) : · simp only [zpow_zero, y_one, le_refl] · exact (y_zpow_pos h.x_pos h.2.1 hn).le refine' strictMono_int_of_lt_succ fun n => _ - cases' le_or_lt 0 n with hn hn + rcases le_or_lt 0 n with hn | hn · exact H n hn · let m : ℤ := -n - 1 have hm : n = -m - 1 := by simp only [neg_sub, sub_neg_eq_add, add_tsub_cancel_left] @@ -664,7 +664,7 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So -- Porting note: added clear hax induction' ax using Nat.strong_induction_on with x ih generalizing a - cases' hay.eq_or_lt with hy hy + rcases hay.eq_or_lt with hy | hy · -- case 1: `a = 1` refine' ⟨0, _⟩ simp only [pow_zero] diff --git a/Mathlib/NumberTheory/PellMatiyasevic.lean b/Mathlib/NumberTheory/PellMatiyasevic.lean index 61f8b6204c7d1..3f6f612f68240 100644 --- a/Mathlib/NumberTheory/PellMatiyasevic.lean +++ b/Mathlib/NumberTheory/PellMatiyasevic.lean @@ -696,7 +696,7 @@ theorem eq_of_xn_modEq_lem3 {i n} (npos : 0 < n) : show 2 * n - (n + 1) = n - 1 by rw [two_mul, tsub_add_eq_tsub_tsub, add_tsub_cancel_right]] refine' lt_sub_left_of_add_lt (Int.ofNat_lt_ofNat_of_lt _) - cases' lt_or_eq_of_le <| Nat.le_of_succ_le_succ ij with lin ein + rcases lt_or_eq_of_le <| Nat.le_of_succ_le_succ ij with lin | ein · rw [Nat.mod_eq_of_lt (strictMono_x _ lin)] have ll : xn a1 (n - 1) + xn a1 (n - 1) ≤ xn a1 n := by rw [← two_mul, mul_comm, @@ -708,7 +708,7 @@ theorem eq_of_xn_modEq_lem3 {i n} (npos : 0 < n) : apply Nat.le_of_succ_le_succ rw [npm] exact lin - cases' lt_or_eq_of_le il with ill ile + rcases lt_or_eq_of_le il with ill | ile · exact lt_of_lt_of_le (Nat.add_lt_add_left (strictMono_x a1 ill) _) ll · rw [ile] apply lt_of_le_of_ne ll diff --git a/Mathlib/NumberTheory/PythagoreanTriples.lean b/Mathlib/NumberTheory/PythagoreanTriples.lean index e909fe28d2c6a..2c1577443bb03 100644 --- a/Mathlib/NumberTheory/PythagoreanTriples.lean +++ b/Mathlib/NumberTheory/PythagoreanTriples.lean @@ -638,7 +638,7 @@ theorem coprime_classification' {x y z : ℤ} (h : PythagoreanTriple x y z) Int.gcd m n = 1 ∧ (m % 2 = 0 ∧ n % 2 = 1 ∨ m % 2 = 1 ∧ n % 2 = 0) ∧ 0 ≤ m := by obtain ⟨m, n, ht1, ht2, ht3, ht4⟩ := PythagoreanTriple.coprime_classification.mp (And.intro h h_coprime) - cases' le_or_lt 0 m with hm hm + rcases le_or_lt 0 m with hm | hm · use m, n cases' ht1 with h_odd h_even · apply And.intro h_odd.1 diff --git a/Mathlib/Order/Atoms.lean b/Mathlib/Order/Atoms.lean index 8d367401a0053..2110a42e4bbaf 100644 --- a/Mathlib/Order/Atoms.lean +++ b/Mathlib/Order/Atoms.lean @@ -437,7 +437,7 @@ variable [IsAtomistic α] instance (priority := 100) : IsAtomic α := ⟨fun b => by rcases eq_sSup_atoms b with ⟨s, rfl, hs⟩ - cases' s.eq_empty_or_nonempty with h h + rcases s.eq_empty_or_nonempty with h | h · simp [h] · exact Or.intro_right _ ⟨h.some, hs _ h.choose_spec, le_sSup h.choose_spec⟩⟩ @@ -483,7 +483,7 @@ variable [IsCoatomistic α] instance (priority := 100) : IsCoatomic α := ⟨fun b => by rcases eq_sInf_coatoms b with ⟨s, rfl, hs⟩ - cases' s.eq_empty_or_nonempty with h h + rcases s.eq_empty_or_nonempty with h | h · simp [h] · exact Or.intro_right _ ⟨h.some, hs _ h.choose_spec, sInf_le h.choose_spec⟩⟩ diff --git a/Mathlib/Order/Bounds/Basic.lean b/Mathlib/Order/Bounds/Basic.lean index 1f4e082b79042..540c92239ca5c 100644 --- a/Mathlib/Order/Bounds/Basic.lean +++ b/Mathlib/Order/Bounds/Basic.lean @@ -458,14 +458,14 @@ theorem IsGLB.union [SemilatticeInf γ] {a₁ a₂ : γ} {s t : Set γ} (hs : Is then `min a b` is the least element of `s ∪ t`. -/ theorem IsLeast.union [LinearOrder γ] {a b : γ} {s t : Set γ} (ha : IsLeast s a) (hb : IsLeast t b) : IsLeast (s ∪ t) (min a b) := - ⟨by cases' le_total a b with h h <;> simp [h, ha.1, hb.1], (ha.isGLB.union hb.isGLB).1⟩ + ⟨by rcases le_total a b with h | h <;> simp [h, ha.1, hb.1], (ha.isGLB.union hb.isGLB).1⟩ #align is_least.union IsLeast.union /-- If `a` is the greatest element of `s` and `b` is the greatest element of `t`, then `max a b` is the greatest element of `s ∪ t`. -/ theorem IsGreatest.union [LinearOrder γ] {a b : γ} {s t : Set γ} (ha : IsGreatest s a) (hb : IsGreatest t b) : IsGreatest (s ∪ t) (max a b) := - ⟨by cases' le_total a b with h h <;> simp [h, ha.1, hb.1], (ha.isLUB.union hb.isLUB).1⟩ + ⟨by rcases le_total a b with h | h <;> simp [h, ha.1, hb.1], (ha.isLUB.union hb.isLUB).1⟩ #align is_greatest.union IsGreatest.union theorem IsLUB.inter_Ici_of_mem [LinearOrder γ] {s : Set γ} {a b : γ} (ha : IsLUB s a) (hb : b ∈ s) : diff --git a/Mathlib/Order/Circular.lean b/Mathlib/Order/Circular.lean index 8599dc8812675..8bb926b9a9657 100644 --- a/Mathlib/Order/Circular.lean +++ b/Mathlib/Order/Circular.lean @@ -457,8 +457,8 @@ See note [reducible non-instances]. -/ def LinearOrder.toCircularOrder (α : Type*) [LinearOrder α] : CircularOrder α := { PartialOrder.toCircularPartialOrder α with btw_total := fun a b c => by - cases' le_total a b with hab hba <;> cases' le_total b c with hbc hcb <;> - cases' le_total c a with hca hac + rcases le_total a b with hab | hba <;> rcases le_total b c with hbc | hcb <;> + rcases le_total c a with hca | hac · exact Or.inl (Or.inl ⟨hab, hbc⟩) · exact Or.inl (Or.inl ⟨hab, hbc⟩) · exact Or.inl (Or.inr <| Or.inr ⟨hca, hab⟩) diff --git a/Mathlib/Order/CompactlyGenerated.lean b/Mathlib/Order/CompactlyGenerated.lean index 650c3f76658c6..75cbde5ba46f1 100644 --- a/Mathlib/Order/CompactlyGenerated.lean +++ b/Mathlib/Order/CompactlyGenerated.lean @@ -216,7 +216,7 @@ theorem WellFounded.isSupFiniteCompact (h : WellFounded ((· > ·) : α → α theorem IsSupFiniteCompact.isSupClosedCompact (h : IsSupFiniteCompact α) : IsSupClosedCompact α := by intro s hne hsc; obtain ⟨t, ht₁, ht₂⟩ := h s; clear h - cases' t.eq_empty_or_nonempty with h h + rcases t.eq_empty_or_nonempty with h | h · subst h rw [Finset.sup_empty] at ht₂ rw [ht₂] diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean index 7099a9f589035..1b0284e324f88 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean @@ -1313,7 +1313,7 @@ theorem isLUB_sSup' {β : Type*} [ConditionallyCompleteLattice β] {s : Set (Wit -- Porting note: in mathlib3 `dsimp only [sSup]` was not needed, we used `show IsLUB ∅ (ite _ _ _)` theorem isLUB_sSup (s : Set (WithTop α)) : IsLUB s (sSup s) := by - cases' s.eq_empty_or_nonempty with hs hs + rcases s.eq_empty_or_nonempty with hs | hs · rw [hs] dsimp only [sSup] show IsLUB ∅ _ @@ -1648,7 +1648,7 @@ noncomputable instance WithTop.WithBot.completeLattice {α : Type*} { instInfSet, instSupSet, boundedOrder, lattice with le_sSup := fun S a haS => (WithTop.isLUB_sSup' ⟨a, haS⟩).1 haS sSup_le := fun S a ha => by - cases' S.eq_empty_or_nonempty with h h + rcases S.eq_empty_or_nonempty with h | h · show ite _ _ _ ≤ a split_ifs with h₁ h₂ · rw [h] at h₁ diff --git a/Mathlib/Order/Filter/Bases.lean b/Mathlib/Order/Filter/Bases.lean index def5854e20917..8f4c2975057fc 100644 --- a/Mathlib/Order/Filter/Bases.lean +++ b/Mathlib/Order/Filter/Bases.lean @@ -1044,7 +1044,7 @@ theorem countable_biInf_eq_iInf_seq [CompleteLattice α] {B : Set ι} (Bcbl : B. theorem countable_biInf_eq_iInf_seq' [CompleteLattice α] {B : Set ι} (Bcbl : B.Countable) (f : ι → α) {i₀ : ι} (h : f i₀ = ⊤) : ∃ x : ℕ → ι, ⨅ t ∈ B, f t = ⨅ i, f (x i) := by - cases' B.eq_empty_or_nonempty with hB Bnonempty + rcases B.eq_empty_or_nonempty with hB | Bnonempty · rw [hB, iInf_emptyset] use fun _ => i₀ simp [h] diff --git a/Mathlib/Order/Filter/FilterProduct.lean b/Mathlib/Order/Filter/FilterProduct.lean index 3517f85c97425..796014ad4ec45 100644 --- a/Mathlib/Order/Filter/FilterProduct.lean +++ b/Mathlib/Order/Filter/FilterProduct.lean @@ -129,7 +129,7 @@ noncomputable instance linearOrderedCommRing [LinearOrderedCommRing β] : Linear theorem max_def [LinearOrder β] (x y : β*) : max x y = map₂ max x y := inductionOn₂ x y fun a b => by - cases' le_total (a : β*) b with h h + rcases le_total (a : β*) b with h | h · rw [max_eq_right h, map₂_coe, coe_eq] exact h.mono fun i hi => (max_eq_right hi).symm · rw [max_eq_left h, map₂_coe, coe_eq] @@ -138,7 +138,7 @@ theorem max_def [LinearOrder β] (x y : β*) : max x y = map₂ max x y := theorem min_def [K : LinearOrder β] (x y : β*) : min x y = map₂ min x y := inductionOn₂ x y fun a b => by - cases' le_total (a : β*) b with h h + rcases le_total (a : β*) b with h | h · rw [min_eq_left h, map₂_coe, coe_eq] exact h.mono fun i hi => (min_eq_left hi).symm · rw [min_eq_right h, map₂_coe, coe_eq] diff --git a/Mathlib/Order/Filter/Interval.lean b/Mathlib/Order/Filter/Interval.lean index a5b3e3166251b..454c24edecf66 100644 --- a/Mathlib/Order/Filter/Interval.lean +++ b/Mathlib/Order/Filter/Interval.lean @@ -290,7 +290,7 @@ instance tendsto_uIcc_of_Icc {l : Filter α} [TendstoIxxClass Icc l l] : obtain ⟨t, htl, hts⟩ : ∃ t ∈ l, ∀ p ∈ (t : Set α) ×ˢ t, Icc (p : α × α).1 p.2 ∈ s exact mem_prod_self_iff.1 (mem_map.1 (tendsto_fst.Icc tendsto_snd hs)) refine' ⟨t, htl, fun p hp => _⟩ - cases' le_total p.1 p.2 with h h + rcases le_total p.1 p.2 with h | h · rw [mem_preimage, uIcc_of_le h] exact hts p hp · rw [mem_preimage, uIcc_of_ge h] diff --git a/Mathlib/Order/Height.lean b/Mathlib/Order/Height.lean index f19beaca313f4..5c576268ad108 100644 --- a/Mathlib/Order/Height.lean +++ b/Mathlib/Order/Height.lean @@ -92,7 +92,7 @@ theorem chainHeight_eq_iSup_subtype : s.chainHeight = ⨆ l : s.subchain, ↑l.1 theorem exists_chain_of_le_chainHeight {n : ℕ} (hn : ↑n ≤ s.chainHeight) : ∃ l ∈ s.subchain, length l = n := by - cases' (le_top : s.chainHeight ≤ ⊤).eq_or_lt with ha ha <;> + rcases (le_top : s.chainHeight ≤ ⊤).eq_or_lt with ha | ha <;> rw [chainHeight_eq_iSup_subtype] at ha · obtain ⟨_, ⟨⟨l, h₁, h₂⟩, rfl⟩, h₃⟩ := not_bddAbove_iff'.mp (WithTop.iSup_coe_eq_top.1 ha) n diff --git a/Mathlib/Order/LiminfLimsup.lean b/Mathlib/Order/LiminfLimsup.lean index 9dda3d4c05ac1..2c0eb89cd0d9b 100644 --- a/Mathlib/Order/LiminfLimsup.lean +++ b/Mathlib/Order/LiminfLimsup.lean @@ -823,7 +823,7 @@ theorem blimsup_congr' {f : Filter β} {p q : β → Prop} {u : β → α} simp only [blimsup_eq] congr with a refine' eventually_congr (h.mono fun b hb => _) - cases' eq_or_ne (u b) ⊥ with hu hu; · simp [hu] + rcases eq_or_ne (u b) ⊥ with hu | hu; · simp [hu] rw [hb hu] #align filter.blimsup_congr' Filter.blimsup_congr' diff --git a/Mathlib/Order/MinMax.lean b/Mathlib/Order/MinMax.lean index d9d18a4a0487a..2970f3dd0d6bc 100644 --- a/Mathlib/Order/MinMax.lean +++ b/Mathlib/Order/MinMax.lean @@ -244,7 +244,7 @@ theorem Max.right_comm (a b c : α) : max (max a b) c = max (max a c) b := theorem MonotoneOn.map_max (hf : MonotoneOn f s) (ha : a ∈ s) (hb : b ∈ s) : f (max a b) = max (f a) (f b) := by - cases' le_total a b with h h <;> + rcases le_total a b with h | h <;> simp only [max_eq_right, max_eq_left, hf ha hb, hf hb ha, h] #align monotone_on.map_max MonotoneOn.map_max @@ -261,7 +261,7 @@ theorem AntitoneOn.map_min (hf : AntitoneOn f s) (ha : a ∈ s) (hb : b ∈ s) : #align antitone_on.map_min AntitoneOn.map_min theorem Monotone.map_max (hf : Monotone f) : f (max a b) = max (f a) (f b) := by - cases' le_total a b with h h <;> simp [h, hf h] + rcases le_total a b with h | h <;> simp [h, hf h] #align monotone.map_max Monotone.map_max theorem Monotone.map_min (hf : Monotone f) : f (min a b) = min (f a) (f b) := @@ -269,7 +269,7 @@ theorem Monotone.map_min (hf : Monotone f) : f (min a b) = min (f a) (f b) := #align monotone.map_min Monotone.map_min theorem Antitone.map_max (hf : Antitone f) : f (max a b) = min (f a) (f b) := by - cases' le_total a b with h h <;> simp [h, hf h] + rcases le_total a b with h | h <;> simp [h, hf h] #align antitone.map_max Antitone.map_max theorem Antitone.map_min (hf : Antitone f) : f (min a b) = max (f a) (f b) := diff --git a/Mathlib/Order/ModularLattice.lean b/Mathlib/Order/ModularLattice.lean index b7b77c3ca333c..e6f4a6236245f 100644 --- a/Mathlib/Order/ModularLattice.lean +++ b/Mathlib/Order/ModularLattice.lean @@ -265,7 +265,7 @@ theorem wellFounded_lt_exact_sequence {β γ : Type*} [PartialOrder β] [Preorde simp only [Prod.lex_def, lt_iff_le_not_le, ← gci.l_le_l_iff, ← gi.u_le_u_iff, hf, hg, le_antisymm_iff] simp only [gci.l_le_l_iff, gi.u_le_u_iff, ← lt_iff_le_not_le, ← le_antisymm_iff] - cases' lt_or_eq_of_le (inf_le_inf_right K (le_of_lt hAB)) with h h + rcases lt_or_eq_of_le (inf_le_inf_right K (le_of_lt hAB)) with h | h · exact Or.inl h · exact Or.inr ⟨h, sup_lt_sup_of_lt_of_inf_le_inf hAB (le_of_eq h.symm)⟩) (InvImage.wf _ (h₁.prod_lex h₂)) diff --git a/Mathlib/Order/OmegaCompletePartialOrder.lean b/Mathlib/Order/OmegaCompletePartialOrder.lean index bc6f5cd05c86c..7724fb567a46a 100644 --- a/Mathlib/Order/OmegaCompletePartialOrder.lean +++ b/Mathlib/Order/OmegaCompletePartialOrder.lean @@ -357,7 +357,7 @@ theorem eq_of_chain {c : Chain (Part α)} {a b : α} (ha : some a ∈ c) (hb : s cases' ha with i ha; replace ha := ha.symm cases' hb with j hb; replace hb := hb.symm rw [eq_some_iff] at ha hb - cases' le_total i j with hij hji + rcases le_total i j with hij | hji · have := c.monotone hij _ ha; apply mem_unique this hb · have := c.monotone hji _ hb; apply Eq.symm; apply mem_unique this ha --Porting note: Old proof diff --git a/Mathlib/Order/OrderIsoNat.lean b/Mathlib/Order/OrderIsoNat.lean index 33dc27ccabbc3..77f40c8106489 100644 --- a/Mathlib/Order/OrderIsoNat.lean +++ b/Mathlib/Order/OrderIsoNat.lean @@ -251,7 +251,7 @@ theorem WellFounded.iSup_eq_monotonicSequenceLimit [CompleteLattice α] (h : WellFounded ((· > ·) : α → α → Prop)) (a : ℕ →o α) : iSup a = monotonicSequenceLimit a := by refine' (iSup_le fun m => _).antisymm (le_iSup a _) - cases' le_or_lt m (monotonicSequenceLimitIndex a) with hm hm + rcases le_or_lt m (monotonicSequenceLimitIndex a) with hm | hm · exact a.monotone hm · cases' WellFounded.monotone_chain_condition'.1 h a with n hn have : n ∈ {n | ∀ m, n ≤ m → a n = a m} := fun k hk => (a.mono hk).eq_of_not_lt (hn k hk) diff --git a/Mathlib/Order/SuccPred/Basic.lean b/Mathlib/Order/SuccPred/Basic.lean index 466b25a83d1e8..a51154c03d6ec 100644 --- a/Mathlib/Order/SuccPred/Basic.lean +++ b/Mathlib/Order/SuccPred/Basic.lean @@ -296,7 +296,7 @@ theorem isMax_iterate_succ_of_eq_of_lt {n m : ℕ} (h_eq : succ^[n] a = succ^[m] theorem isMax_iterate_succ_of_eq_of_ne {n m : ℕ} (h_eq : succ^[n] a = succ^[m] a) (h_ne : n ≠ m) : IsMax (succ^[n] a) := by - cases' le_total n m with h h + rcases le_total n m with h | h · exact isMax_iterate_succ_of_eq_of_lt h_eq (lt_of_le_of_ne h h_ne) · rw [h_eq] exact isMax_iterate_succ_of_eq_of_lt h_eq.symm (lt_of_le_of_ne h h_ne.symm) @@ -1512,7 +1512,7 @@ instance (priority := 100) IsWellOrder.toIsPredArchimedean [h : IsWellOrder α ( replace hab := eq_or_lt_of_le hab rcases hab with (rfl | hab) · exact ⟨0, rfl⟩ - cases' le_or_lt b (pred b) with hb hb + rcases le_or_lt b (pred b) with hb | hb · cases (min_of_le_pred hb).not_lt hab dsimp at ih obtain ⟨k, hk⟩ := ih (pred b) hb (le_pred_of_lt hab) diff --git a/Mathlib/Order/SuccPred/IntervalSucc.lean b/Mathlib/Order/SuccPred/IntervalSucc.lean index a742514cc52ae..6a4910db8cc5c 100644 --- a/Mathlib/Order/SuccPred/IntervalSucc.lean +++ b/Mathlib/Order/SuccPred/IntervalSucc.lean @@ -36,7 +36,7 @@ function `f` and `m n : α`, the union of intervals `Set.Ioc (f i) (f (Order.suc is equal to `Set.Ioc (f m) (f n)` -/ theorem biUnion_Ico_Ioc_map_succ [SuccOrder α] [IsSuccArchimedean α] [LinearOrder β] {f : α → β} (hf : Monotone f) (m n : α) : ⋃ i ∈ Ico m n, Ioc (f i) (f (succ i)) = Ioc (f m) (f n) := by - cases' le_total n m with hnm hmn + rcases le_total n m with hnm | hmn · rw [Ico_eq_empty_of_le hnm, Ioc_eq_empty_of_le (hf hnm), biUnion_empty] · refine' Succ.rec _ _ hmn · simp only [Ioc_self, Ico_self, biUnion_empty] diff --git a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean index 1a7f0ced832d4..40d28bfef987e 100644 --- a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean +++ b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean @@ -80,7 +80,7 @@ theorem isGLB_Ioc_of_isGLB_Ioi {i j k : ι} (hij_lt : i < j) (h : IsGLB (Set.Ioi simp_rw [IsGLB, IsGreatest, mem_upperBounds, mem_lowerBounds] at h ⊢ refine' ⟨fun x hx ↦ h.1 x hx.1, fun x hx ↦ h.2 x _⟩ intro y hy - cases' le_or_lt y j with h_le h_lt + rcases le_or_lt y j with h_le | h_lt · exact hx y ⟨hy, h_le⟩ · exact le_trans (hx j ⟨hij_lt, le_rfl⟩) h_lt.le #align linear_locally_finite_order.is_glb_Ioc_of_is_glb_Ioi LinearLocallyFiniteOrder.isGLB_Ioc_of_isGLB_Ioi @@ -149,7 +149,7 @@ instance (priority := 100) LinearLocallyFiniteOrder.isSuccArchimedean [LocallyFi obtain ⟨n, m, hnm_ne, hfnm⟩ : ∃ n m, n ≠ m ∧ f n = f m exact Finite.exists_ne_map_eq_of_infinite f have hnm_eq : succ^[n] i = succ^[m] i := by simpa only [Subtype.mk_eq_mk] using hfnm - cases' le_total n m with h_le h_le + rcases le_total n m with h_le | h_le · exact ⟨n, m, lt_of_le_of_ne h_le hnm_ne, hnm_eq⟩ · exact ⟨m, n, lt_of_le_of_ne h_le hnm_ne.symm, hnm_eq.symm⟩ have h_max : IsMax (succ^[n] i) := isMax_iterate_succ_of_eq_of_ne h_eq hnm.ne @@ -240,7 +240,7 @@ theorem toZ_iterate_succ_le (n : ℕ) : toZ i0 (succ^[n] i0) ≤ n := by #align to_Z_iterate_succ_le toZ_iterate_succ_le theorem toZ_iterate_pred_ge (n : ℕ) : -(n : ℤ) ≤ toZ i0 (pred^[n] i0) := by - cases' le_or_lt i0 (pred^[n] i0) with h h + rcases le_or_lt i0 (pred^[n] i0) with h | h · have h_eq : pred^[n] i0 = i0 := le_antisymm (pred_iterate_le _ _) h rw [h_eq, toZ_of_eq] simp only [Right.neg_nonpos_iff, Nat.cast_nonneg] @@ -282,7 +282,7 @@ theorem toZ_iterate_pred_of_not_isMin (n : ℕ) (hn : ¬IsMin (pred^[n] i0)) : #align to_Z_iterate_pred_of_not_is_min toZ_iterate_pred_of_not_isMin theorem le_of_toZ_le {j : ι} (h_le : toZ i0 i ≤ toZ i0 j) : i ≤ j := by - cases' le_or_lt i0 i with hi hi <;> cases' le_or_lt i0 j with hj hj + rcases le_or_lt i0 i with hi | hi <;> rcases le_or_lt i0 j with hj | hj · rw [← iterate_succ_toZ i hi, ← iterate_succ_toZ j hj] exact Monotone.monotone_iterate_of_le_map succ_mono (le_succ _) (Int.toNat_le_toNat h_le) · exact absurd ((toZ_neg hj).trans_le (toZ_nonneg hi)) (not_lt.mpr h_le) @@ -297,7 +297,7 @@ theorem toZ_mono {i j : ι} (h_le : i ≤ j) : toZ i0 i ≤ toZ i0 j := by · rw [le_antisymm h_le (hi_max h_le)] by_cases hj_min : IsMin j · rw [le_antisymm h_le (hj_min h_le)] - cases' le_or_lt i0 i with hi hi <;> cases' le_or_lt i0 j with hj hj + rcases le_or_lt i0 i with hi | hi <;> rcases le_or_lt i0 j with hj | hj · let m := Nat.find (exists_succ_iterate_of_le h_le) have hm : succ^[m] i = j := Nat.find_spec (exists_succ_iterate_of_le h_le) have hj_eq : j = succ^[(toZ i0 i).toNat + m] i0 := by @@ -383,7 +383,7 @@ noncomputable def orderIsoIntOfLinearSuccPredArch [NoMaxOrder ι] [NoMinOrder ι toFun := toZ hι.some invFun n := if 0 ≤ n then succ^[n.toNat] hι.some else pred^[(-n).toNat] hι.some left_inv i := by - cases' le_or_lt hι.some i with hi hi + rcases le_or_lt hι.some i with hi | hi · have h_nonneg : 0 ≤ toZ hι.some i := toZ_nonneg hi simp_rw [if_pos h_nonneg] exact iterate_succ_toZ i hi @@ -391,7 +391,7 @@ noncomputable def orderIsoIntOfLinearSuccPredArch [NoMaxOrder ι] [NoMinOrder ι simp_rw [if_neg (not_le.mpr h_neg)] exact iterate_pred_toZ i hi right_inv n := by - cases' le_or_lt 0 n with hn hn + rcases le_or_lt 0 n with hn | hn · simp_rw [if_pos hn] rw [toZ_iterate_succ] exact Int.toNat_of_nonneg hn diff --git a/Mathlib/Order/SuccPred/Relation.lean b/Mathlib/Order/SuccPred/Relation.lean index 26700fa8739d4..4e9b3252e0fee 100644 --- a/Mathlib/Order/SuccPred/Relation.lean +++ b/Mathlib/Order/SuccPred/Relation.lean @@ -30,7 +30,7 @@ theorem reflTransGen_of_succ_of_le (r : α → α → Prop) {n m : α} (h : ∀ exact ReflTransGen.refl · intro m hnm ih h have : ReflTransGen r n m := ih fun i hi => h i ⟨hi.1, hi.2.trans_le <| le_succ m⟩ - cases' (le_succ m).eq_or_lt with hm hm + rcases (le_succ m).eq_or_lt with hm | hm · rwa [← hm] exact this.tail (h m ⟨hnm, hm⟩) #align refl_trans_gen_of_succ_of_le reflTransGen_of_succ_of_le diff --git a/Mathlib/Probability/Kernel/Disintegration.lean b/Mathlib/Probability/Kernel/Disintegration.lean index 61ad8f3f40d03..9d1b2ad0afe80 100644 --- a/Mathlib/Probability/Kernel/Disintegration.lean +++ b/Mathlib/Probability/Kernel/Disintegration.lean @@ -145,9 +145,6 @@ theorem lintegral_condKernelReal_mem {s : Set (α × ℝ)} (hs : MeasurableSet s have h_prod_eq_snd : ∀ a ∈ t₁, {x : ℝ | (a, x) ∈ t₁ ×ˢ t₂} = t₂ := by intro a ha simp only [ha, prod_mk_mem_set_prod_eq, true_and_iff, setOf_mem_eq] - cases' eq_empty_or_nonempty t₂ with h h - · simp only [h, prod_empty, mem_empty_iff_false, setOf_false, measure_empty, lintegral_const, - zero_mul] rw [← lintegral_add_compl _ ht₁] have h_eq1 : ∫⁻ a in t₁, condKernelReal ρ a {x : ℝ | (a, x) ∈ t₁ ×ˢ t₂} ∂ρ.fst = ∫⁻ a in t₁, condKernelReal ρ a t₂ ∂ρ.fst := by diff --git a/Mathlib/Probability/Moments.lean b/Mathlib/Probability/Moments.lean index 498cec727efb3..cebe2c7be294b 100644 --- a/Mathlib/Probability/Moments.lean +++ b/Mathlib/Probability/Moments.lean @@ -329,7 +329,7 @@ set_option linter.uppercaseLean3 false in theorem measure_ge_le_exp_mul_mgf [IsFiniteMeasure μ] (ε : ℝ) (ht : 0 ≤ t) (h_int : Integrable (fun ω => exp (t * X ω)) μ) : (μ {ω | ε ≤ X ω}).toReal ≤ exp (-t * ε) * mgf X μ t := by - cases' ht.eq_or_lt with ht_zero_eq ht_pos + rcases ht.eq_or_lt with ht_zero_eq | ht_pos · rw [ht_zero_eq.symm] simp only [neg_zero, zero_mul, exp_zero, mgf_zero', one_mul] rw [ENNReal.toReal_le_toReal (measure_ne_top μ _) (measure_ne_top μ _)] diff --git a/Mathlib/Probability/Process/HittingTime.lean b/Mathlib/Probability/Process/HittingTime.lean index 5641ccfbc9722..22ec83acec12a 100644 --- a/Mathlib/Probability/Process/HittingTime.lean +++ b/Mathlib/Probability/Process/HittingTime.lean @@ -69,14 +69,12 @@ theorem hitting_of_lt {m : ι} (h : m < n) : hitting u s n m ω = m := by #align measure_theory.hitting_of_lt MeasureTheory.hitting_of_lt theorem hitting_le {m : ι} (ω : Ω) : hitting u s n m ω ≤ m := by - cases' le_or_lt n m with h_le h_lt - · simp only [hitting] - split_ifs with h - · obtain ⟨j, hj₁, hj₂⟩ := h - change j ∈ {i | u i ω ∈ s} at hj₂ - exact (csInf_le (BddBelow.inter_of_left bddBelow_Icc) (Set.mem_inter hj₁ hj₂)).trans hj₁.2 - · exact le_rfl - · rw [hitting_of_lt h_lt] + simp only [hitting] + split_ifs with h + · obtain ⟨j, hj₁, hj₂⟩ := h + change j ∈ {i | u i ω ∈ s} at hj₂ + exact (csInf_le (BddBelow.inter_of_left bddBelow_Icc) (Set.mem_inter hj₁ hj₂)).trans hj₁.2 + · exact le_rfl #align measure_theory.hitting_le MeasureTheory.hitting_le theorem not_mem_of_lt_hitting {m k : ι} (hk₁ : k < hitting u s n m ω) (hk₂ : n ≤ k) : @@ -229,7 +227,7 @@ theorem hitting_isStoppingTime [ConditionallyCompleteLinearOrder ι] [IsWellOrde {f : Filtration ι m} {u : ι → Ω → β} {s : Set β} {n n' : ι} (hu : Adapted f u) (hs : MeasurableSet s) : IsStoppingTime f (hitting u s n n') := by intro i - cases' le_or_lt n' i with hi hi + rcases le_or_lt n' i with hi | hi · have h_le : ∀ ω, hitting u s n n' ω ≤ i := fun x => (hitting_le x).trans hi simp [h_le] · have h_set_eq_Union : {ω | hitting u s n n' ω ≤ i} = ⋃ j ∈ Set.Icc n i, u j ⁻¹' s := by diff --git a/Mathlib/Probability/Process/Stopping.lean b/Mathlib/Probability/Process/Stopping.lean index 02a643943ff06..0d98a9b4bff96 100644 --- a/Mathlib/Probability/Process/Stopping.lean +++ b/Mathlib/Probability/Process/Stopping.lean @@ -916,7 +916,7 @@ theorem stoppedProcess_eq_of_mem_finset [LinearOrder ι] [AddCommMonoid E] {s : ∑ i in s.filter (· < n), Set.indicator {ω | τ ω = i} (u i) := by ext ω rw [Pi.add_apply, Finset.sum_apply] - cases' le_or_lt n (τ ω) with h h + rcases le_or_lt n (τ ω) with h | h · rw [stoppedProcess_eq_of_le h, Set.indicator_of_mem, Finset.sum_eq_zero, add_zero] · intro m hm refine' Set.indicator_of_not_mem _ _ diff --git a/Mathlib/RingTheory/Artinian.lean b/Mathlib/RingTheory/Artinian.lean index 8cee2bae5f281..5c5f7b67c8d16 100644 --- a/Mathlib/RingTheory/Artinian.lean +++ b/Mathlib/RingTheory/Artinian.lean @@ -243,7 +243,7 @@ lemma eventually_iInf_range_pow_eq (f : Module.End R M) : obtain ⟨n, hn : ∀ m, n ≤ m → LinearMap.range (f ^ n) = LinearMap.range (f ^ m)⟩ := monotone_stabilizes f.iterateRange refine eventually_atTop.mpr ⟨n, fun l hl ↦ le_antisymm (iInf_le _ _) (le_iInf fun m ↦ ?_)⟩ - cases' le_or_lt l m with h h + rcases le_or_lt l m with h | h · rw [← hn _ (hl.trans h), hn _ hl] · exact f.iterateRange.monotone h.le diff --git a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean index b12a797640f6d..8afc40f01f2f1 100644 --- a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean +++ b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean @@ -245,7 +245,7 @@ theorem DiscreteValuationRing.TFAE [IsNoetherianRing R] [LocalRing R] [IsDomain by_cases hJ : J = ⊥; · subst hJ; right; exact bot_le obtain ⟨n, rfl⟩ := H I hI obtain ⟨m, rfl⟩ := H J hJ - cases' le_total m n with h' h' + rcases le_total m n with h' | h' · left; exact Ideal.pow_le_pow_right h' · right; exact Ideal.pow_le_pow_right h' tfae_finish diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 17e7d6ced29fa..16b95872f7ee9 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -1271,7 +1271,7 @@ theorem subset_union_prime {R : Type u} [CommRing R] {s : Finset ι} {f : ι → rw [Finset.coe_insert, Set.biUnion_insert, ← Set.union_self (f b : Set R), subset_union_prime' hp', ← or_assoc, or_self_iff] at h rwa [Finset.exists_mem_insert] - cases' s.eq_empty_or_nonempty with hse hsne + rcases s.eq_empty_or_nonempty with hse | hsne · subst hse rw [Finset.coe_empty, Set.biUnion_empty, Set.subset_empty_iff] at h have : (I : Set R) ≠ ∅ := Set.Nonempty.ne_empty (Set.nonempty_of_mem I.zero_mem) diff --git a/Mathlib/RingTheory/Localization/Away/Basic.lean b/Mathlib/RingTheory/Localization/Away/Basic.lean index 6c138cc8007e4..01f42eef8da61 100644 --- a/Mathlib/RingTheory/Localization/Away/Basic.lean +++ b/Mathlib/RingTheory/Localization/Away/Basic.lean @@ -231,7 +231,7 @@ theorem selfZPow_sub_cast_nat {n m : ℕ} : @[simp] theorem selfZPow_add {n m : ℤ} : selfZPow x B (n + m) = selfZPow x B n * selfZPow x B m := by - cases' le_or_lt 0 n with hn hn <;> cases' le_or_lt 0 m with hm hm + rcases le_or_lt 0 n with hn | hn <;> rcases le_or_lt 0 m with hm | hm · rw [selfZPow_of_nonneg _ _ hn, selfZPow_of_nonneg _ _ hm, selfZPow_of_nonneg _ _ (add_nonneg hn hm), Int.natAbs_add_nonneg hn hm, pow_add] · have : n + m = n.natAbs - m.natAbs := by diff --git a/Mathlib/RingTheory/Noetherian.lean b/Mathlib/RingTheory/Noetherian.lean index 4c857f9a69cda..33ec72b17b6dc 100644 --- a/Mathlib/RingTheory/Noetherian.lean +++ b/Mathlib/RingTheory/Noetherian.lean @@ -449,7 +449,7 @@ lemma LinearMap.eventually_iSup_ker_pow_eq (f : M →ₗ[R] M) : monotone_stabilizes_iff_noetherian.mpr inferInstance f.iterateKer refine eventually_atTop.mpr ⟨n, fun m hm ↦ ?_⟩ refine le_antisymm (iSup_le fun l ↦ ?_) (le_iSup (fun i ↦ LinearMap.ker (f ^ i)) m) - cases' le_or_lt m l with h h + rcases le_or_lt m l with h | h · rw [← hn _ (hm.trans h), hn _ hm] · exact f.iterateKer.monotone h.le diff --git a/Mathlib/RingTheory/Polynomial/Basic.lean b/Mathlib/RingTheory/Polynomial/Basic.lean index 5b210a31edb35..1386a276f94ca 100644 --- a/Mathlib/RingTheory/Polynomial/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Basic.lean @@ -636,7 +636,7 @@ theorem mem_leadingCoeffNth (n : ℕ) (x) : mem_degreeLE] constructor · rintro ⟨p, ⟨hpdeg, hpI⟩, rfl⟩ - cases' lt_or_eq_of_le hpdeg with hpdeg hpdeg + rcases lt_or_eq_of_le hpdeg with hpdeg | hpdeg · refine' ⟨0, I.zero_mem, bot_le, _⟩ rw [leadingCoeff_zero, eq_comm] exact coeff_eq_zero_of_degree_lt hpdeg @@ -979,7 +979,7 @@ protected theorem Polynomial.isNoetherianRing [inst : IsNoetherianRing R] : IsNo intro p hp generalize hn : p.natDegree = k induction' k using Nat.strong_induction_on with k ih generalizing p - cases' le_or_lt k N with h h + rcases le_or_lt k N with h | h · subst k refine' hs2 ⟨Polynomial.mem_degreeLE.2 (le_trans Polynomial.degree_le_natDegree <| WithBot.coe_le_coe.2 h), hp⟩ diff --git a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean index d7ae21ff07f2c..c383b83153fbc 100644 --- a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean @@ -204,7 +204,7 @@ termination_by _ n k => (n, k) theorem coeff_hermite_of_even_add {n k : ℕ} (hnk : Even (n + k)) : coeff (hermite n) k = (-1) ^ ((n - k) / 2) * (n - k - 1)‼ * Nat.choose n k := by - cases' le_or_lt k n with h_le h_lt + rcases le_or_lt k n with h_le | h_lt · rw [Nat.even_add, ← Nat.even_sub h_le] at hnk obtain ⟨m, hm⟩ := hnk -- porting note: linarith failed to find a contradiction by itself diff --git a/Mathlib/RingTheory/Polynomial/Nilpotent.lean b/Mathlib/RingTheory/Polynomial/Nilpotent.lean index 72c4ee6eb3d5a..38917dbbcb84d 100644 --- a/Mathlib/RingTheory/Polynomial/Nilpotent.lean +++ b/Mathlib/RingTheory/Polynomial/Nilpotent.lean @@ -84,7 +84,7 @@ protected lemma isNilpotent_iff : @[simp] lemma isNilpotent_reflect_iff {P : R[X]} {N : ℕ} (hN : P.natDegree ≤ N): IsNilpotent (reflect N P) ↔ IsNilpotent P := by simp only [Polynomial.isNilpotent_iff, coeff_reverse] - refine' ⟨fun h i ↦ _, fun h i ↦ _⟩ <;> cases' le_or_lt i N with hi hi + refine' ⟨fun h i ↦ _, fun h i ↦ _⟩ <;> rcases le_or_lt i N with hi | hi · simpa [tsub_tsub_cancel_of_le hi] using h (N - i) · simp [coeff_eq_zero_of_natDegree_lt $ lt_of_le_of_lt hN hi] · simpa [hi, revAt_le] using h (N - i) diff --git a/Mathlib/RingTheory/RootsOfUnity/Basic.lean b/Mathlib/RingTheory/RootsOfUnity/Basic.lean index b4675545a7d52..8ec6708e83a0d 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Basic.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Basic.lean @@ -821,7 +821,7 @@ theorem card_rootsOfUnity {ζ : R} {n : ℕ+} (h : IsPrimitiveRoot ζ n) : if there is a primitive root of unity in `R`. -/ nonrec theorem card_nthRoots {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : Multiset.card (nthRoots n (1 : R)) = n := by - cases' Nat.eq_zero_or_pos n with hzero hpos + rcases Nat.eq_zero_or_pos n with hzero | hpos · simp only [hzero, Multiset.card_zero, nthRoots_zero] rw [eq_iff_le_not_lt] use card_nthRoots n 1 @@ -839,7 +839,7 @@ nonrec theorem card_nthRoots {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : /-- The multiset `nthRoots ↑n (1 : R)` has no repeated elements if there is a primitive root of unity in `R`. -/ theorem nthRoots_nodup {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : (nthRoots n (1 : R)).Nodup := by - cases' Nat.eq_zero_or_pos n with hzero hpos + rcases Nat.eq_zero_or_pos n with hzero | hpos · simp only [hzero, Multiset.nodup_zero, nthRoots_zero] apply (Multiset.dedup_eq_self (α := R)).1 rw [eq_iff_le_not_lt] diff --git a/Mathlib/RingTheory/Valuation/Basic.lean b/Mathlib/RingTheory/Valuation/Basic.lean index 90eea6f7c4739..58417fafc3598 100644 --- a/Mathlib/RingTheory/Valuation/Basic.lean +++ b/Mathlib/RingTheory/Valuation/Basic.lean @@ -455,7 +455,7 @@ theorem isEquiv_iff_val_eq_one [LinearOrderedCommGroupWithZero Γ₀] intro x constructor · intro hx - cases' lt_or_eq_of_le hx with hx' hx' + rcases lt_or_eq_of_le hx with hx' | hx' · have : v (1 + x) = 1 := by rw [← v.map_one] apply map_add_eq_of_lt_left @@ -467,7 +467,7 @@ theorem isEquiv_iff_val_eq_one [LinearOrderedCommGroupWithZero Γ₀] · rw [h] at hx' exact le_of_eq hx' · intro hx - cases' lt_or_eq_of_le hx with hx' hx' + rcases lt_or_eq_of_le hx with hx' | hx' · have : v' (1 + x) = 1 := by rw [← v'.map_one] apply map_add_eq_of_lt_left diff --git a/Mathlib/RingTheory/Valuation/ValuationRing.lean b/Mathlib/RingTheory/Valuation/ValuationRing.lean index 47e7b06d286f0..16304e2540146 100644 --- a/Mathlib/RingTheory/Valuation/ValuationRing.lean +++ b/Mathlib/RingTheory/Valuation/ValuationRing.lean @@ -352,7 +352,7 @@ instance (priority := 100) [ValuationRing R] : IsBezout R := by rw [IsBezout.iff_span_pair_isPrincipal] intro x y rw [Ideal.span_insert] - cases' le_total (Ideal.span {x} : Ideal R) (Ideal.span {y}) with h h + rcases le_total (Ideal.span {x} : Ideal R) (Ideal.span {y}) with h | h · erw [sup_eq_right.mpr h]; exact ⟨⟨_, rfl⟩⟩ · erw [sup_eq_left.mpr h]; exact ⟨⟨_, rfl⟩⟩ @@ -368,7 +368,7 @@ theorem iff_local_bezout_domain : ValuationRing R ↔ LocalRing R ∧ IsBezout R (show b ∈ Ideal.span {g} by rw [← e]; exact Ideal.subset_span (by simp)) obtain ⟨x, y, e'⟩ := Ideal.mem_span_pair.mp (show g ∈ Ideal.span {a * g, b * g} by rw [e]; exact Ideal.subset_span (by simp)) - cases' eq_or_ne g 0 with h h + rcases eq_or_ne g 0 with h | h · simp [h] have : x * a + y * b = 1 := by apply mul_left_injective₀ h; convert e' using 1 <;> ring @@ -412,7 +412,7 @@ is a valuation ring. -/ theorem of_integers : ValuationRing 𝒪 := by constructor intro a b - cases' le_total (v (algebraMap 𝒪 K a)) (v (algebraMap 𝒪 K b)) with h h + rcases le_total (v (algebraMap 𝒪 K a)) (v (algebraMap 𝒪 K b)) with h | h · obtain ⟨c, hc⟩ := Valuation.Integers.dvd_of_le hh h use c; exact Or.inr hc.symm · obtain ⟨c, hc⟩ := Valuation.Integers.dvd_of_le hh h @@ -449,7 +449,7 @@ instance (priority := 100) of_discreteValuationRing : ValuationRing A := by obtain ⟨ϖ, hϖ⟩ := DiscreteValuationRing.exists_irreducible A obtain ⟨m, u, rfl⟩ := DiscreteValuationRing.eq_unit_mul_pow_irreducible ha hϖ obtain ⟨n, v, rfl⟩ := DiscreteValuationRing.eq_unit_mul_pow_irreducible hb hϖ - cases' le_total m n with h h + rcases le_total m n with h | h · use (u⁻¹ * v : Aˣ) * ϖ ^ (n - m); left simp_rw [mul_comm (u : A), Units.val_mul, ← mul_assoc, mul_assoc _ (u : A)] simp only [Units.mul_inv, mul_one, mul_comm _ (v : A), mul_assoc, ← pow_add] diff --git a/Mathlib/RingTheory/Valuation/ValuationSubring.lean b/Mathlib/RingTheory/Valuation/ValuationSubring.lean index 75c840899626a..7813e797b658c 100644 --- a/Mathlib/RingTheory/Valuation/ValuationSubring.lean +++ b/Mathlib/RingTheory/Valuation/ValuationSubring.lean @@ -422,7 +422,7 @@ def valuationSubring : ValuationSubring K := { v.integer with mem_or_inv_mem' := by intro x - cases' le_or_lt (v x) 1 with h h + rcases le_or_lt (v x) 1 with h | h · left; exact h · right; change v x⁻¹ ≤ 1 rw [map_inv₀ v, ← inv_one, inv_le_inv₀] diff --git a/Mathlib/SetTheory/Cardinal/Divisibility.lean b/Mathlib/SetTheory/Cardinal/Divisibility.lean index 6b8c0748c6b1b..e3ad71bf49f26 100644 --- a/Mathlib/SetTheory/Cardinal/Divisibility.lean +++ b/Mathlib/SetTheory/Cardinal/Divisibility.lean @@ -77,7 +77,7 @@ theorem prime_of_aleph0_le (ha : ℵ₀ ≤ a) : Prime a := by refine' ⟨(aleph0_pos.trans_le ha).ne', _, fun b c hbc => _⟩ · rw [isUnit_iff] exact (one_lt_aleph0.trans_le ha).ne' - cases' eq_or_ne (b * c) 0 with hz hz + rcases eq_or_ne (b * c) 0 with hz | hz · rcases mul_eq_zero.mp hz with (rfl | rfl) <;> simp wlog h : c ≤ b · cases le_total c b <;> [skip; rw [or_comm]] <;> apply_assumption @@ -134,7 +134,7 @@ theorem nat_is_prime_iff : Prime (n : Cardinal) ↔ n.Prime := by #align cardinal.nat_is_prime_iff Cardinal.nat_is_prime_iff theorem is_prime_iff {a : Cardinal} : Prime a ↔ ℵ₀ ≤ a ∨ ∃ p : ℕ, a = p ∧ p.Prime := by - cases' le_or_lt ℵ₀ a with h h + rcases le_or_lt ℵ₀ a with h | h · simp [h] lift a to ℕ using id h simp [not_le.mpr h] diff --git a/Mathlib/SetTheory/Cardinal/Ordinal.lean b/Mathlib/SetTheory/Cardinal/Ordinal.lean index dce405235144d..ffbcf55781644 100644 --- a/Mathlib/SetTheory/Cardinal/Ordinal.lean +++ b/Mathlib/SetTheory/Cardinal/Ordinal.lean @@ -258,7 +258,7 @@ theorem aleph_le {o₁ o₂ : Ordinal} : aleph o₁ ≤ aleph o₂ ↔ o₁ ≤ @[simp] theorem max_aleph_eq (o₁ o₂ : Ordinal) : max (aleph o₁) (aleph o₂) = aleph (max o₁ o₂) := by - cases' le_total (aleph o₁) (aleph o₂) with h h + rcases le_total (aleph o₁) (aleph o₂) with h | h · rw [max_eq_right h, max_eq_right (aleph_le.1 h)] · rw [max_eq_left h, max_eq_left (aleph_le.1 h)] #align cardinal.max_aleph_eq Cardinal.max_aleph_eq @@ -609,7 +609,7 @@ theorem mul_le_max_of_aleph0_le_left {a b : Cardinal} (h : ℵ₀ ≤ a) : a * b theorem mul_eq_max_of_aleph0_le_left {a b : Cardinal} (h : ℵ₀ ≤ a) (h' : b ≠ 0) : a * b = max a b := by - cases' le_or_lt ℵ₀ b with hb hb + rcases le_or_lt ℵ₀ b with hb | hb · exact mul_eq_max h hb refine' (mul_le_max_of_aleph0_le_left h).antisymm _ have : b ≤ a := hb.le.trans h @@ -637,10 +637,10 @@ theorem mul_eq_max' {a b : Cardinal} (h : ℵ₀ ≤ a * b) : a * b = max a b := theorem mul_le_max (a b : Cardinal) : a * b ≤ max (max a b) ℵ₀ := by rcases eq_or_ne a 0 with (rfl | ha0); · simp rcases eq_or_ne b 0 with (rfl | hb0); · simp - cases' le_or_lt ℵ₀ a with ha ha + rcases le_or_lt ℵ₀ a with ha | ha · rw [mul_eq_max_of_aleph0_le_left ha hb0] exact le_max_left _ _ - · cases' le_or_lt ℵ₀ b with hb hb + · rcases le_or_lt ℵ₀ b with hb | hb · rw [mul_comm, mul_eq_max_of_aleph0_le_left hb ha0, max_comm] exact le_max_left _ _ · exact le_max_of_le_right (mul_lt_aleph0 ha hb).le @@ -667,7 +667,7 @@ theorem le_mul_right {a b : Cardinal} (h : b ≠ 0) : a ≤ a * b := by theorem mul_eq_left_iff {a b : Cardinal} : a * b = a ↔ max ℵ₀ b ≤ a ∧ b ≠ 0 ∨ b = 1 ∨ a = 0 := by rw [max_le_iff] refine' ⟨fun h => _, _⟩ - · cases' le_or_lt ℵ₀ a with ha ha + · rcases le_or_lt ℵ₀ a with ha | ha · have : a ≠ 0 := by rintro rfl exact ha.not_lt aleph0_pos @@ -745,10 +745,10 @@ theorem add_mk_eq_max' {α β : Type u} [Infinite β] : #α + #β = max #α #β #align cardinal.add_mk_eq_max' Cardinal.add_mk_eq_max' theorem add_le_max (a b : Cardinal) : a + b ≤ max (max a b) ℵ₀ := by - cases' le_or_lt ℵ₀ a with ha ha + rcases le_or_lt ℵ₀ a with ha | ha · rw [add_eq_max ha] exact le_max_left _ _ - · cases' le_or_lt ℵ₀ b with hb hb + · rcases le_or_lt ℵ₀ b with hb | hb · rw [add_comm, add_eq_max hb, max_comm] exact le_max_left _ _ · exact le_max_of_le_right (add_lt_aleph0 ha hb).le @@ -785,7 +785,7 @@ theorem add_eq_right {a b : Cardinal} (hb : ℵ₀ ≤ b) (ha : a ≤ b) : a + b theorem add_eq_left_iff {a b : Cardinal} : a + b = a ↔ max ℵ₀ b ≤ a ∨ b = 0 := by rw [max_le_iff] refine' ⟨fun h => _, _⟩ - · cases' le_or_lt ℵ₀ a with ha ha + · rcases le_or_lt ℵ₀ a with ha | ha · left use ha rw [← not_lt] @@ -824,7 +824,7 @@ theorem mk_add_one_eq {α : Type*} [Infinite α] : #α + 1 = #α := protected theorem eq_of_add_eq_add_left {a b c : Cardinal} (h : a + b = a + c) (ha : a < ℵ₀) : b = c := by - cases' le_or_lt ℵ₀ b with hb hb + rcases le_or_lt ℵ₀ b with hb | hb · have : a < b := ha.trans_le hb rw [add_eq_right hb this.le, eq_comm] at h rw [eq_of_add_eq_of_aleph0_le h this hb] @@ -959,7 +959,7 @@ theorem power_nat_eq {c : Cardinal.{u}} {n : ℕ} (h1 : ℵ₀ ≤ c) (h2 : 1 #align cardinal.power_nat_eq Cardinal.power_nat_eq theorem power_nat_le_max {c : Cardinal.{u}} {n : ℕ} : c ^ (n : Cardinal.{u}) ≤ max c ℵ₀ := by - cases' le_or_lt ℵ₀ c with hc hc + rcases le_or_lt ℵ₀ c with hc | hc · exact le_max_of_le_left (power_nat_le hc) · exact le_max_of_le_right (power_lt_aleph0 hc (nat_lt_aleph0 _)).le #align cardinal.power_nat_le_max Cardinal.power_nat_le_max @@ -975,7 +975,7 @@ theorem powerlt_aleph0 {c : Cardinal} (h : ℵ₀ ≤ c) : c ^< ℵ₀ = c := by #align cardinal.powerlt_aleph_0 Cardinal.powerlt_aleph0 theorem powerlt_aleph0_le (c : Cardinal) : c ^< ℵ₀ ≤ max c ℵ₀ := by - cases' le_or_lt ℵ₀ c with h h + rcases le_or_lt ℵ₀ c with h | h · rw [powerlt_aleph0 h] apply le_max_left rw [powerlt_le] @@ -1306,7 +1306,7 @@ theorem extend_function_of_lt {α β : Type*} {s : Set α} (f : s ↪ β) (hs : -- @[simp] -- theorem bit0_le_bit0 {a b : Cardinal} : bit0 a ≤ bit0 b ↔ a ≤ b := by --- cases' le_or_lt ℵ₀ a with ha ha <;> cases' le_or_lt ℵ₀ b with hb hb +-- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb -- · rw [bit0_eq_self ha, bit0_eq_self hb] -- · rw [bit0_eq_self ha] -- refine' iff_of_false (fun h => _) (hb.trans_le ha).not_le @@ -1322,7 +1322,7 @@ theorem extend_function_of_lt {α β : Type*} {s : Set α} (f : s ↪ β) (hs : -- @[simp] -- theorem bit0_le_bit1 {a b : Cardinal} : bit0 a ≤ bit1 b ↔ a ≤ b := by --- cases' le_or_lt ℵ₀ a with ha ha <;> cases' le_or_lt ℵ₀ b with hb hb +-- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb -- · rw [bit0_eq_self ha, bit1_eq_self_iff.2 hb] -- · rw [bit0_eq_self ha] -- refine' iff_of_false (fun h => _) (hb.trans_le ha).not_le @@ -1344,7 +1344,7 @@ theorem extend_function_of_lt {α β : Type*} {s : Set α} (f : s ↪ β) (hs : -- @[simp] -- theorem bit1_le_bit0 {a b : Cardinal} : bit1 a ≤ bit0 b ↔ a < b ∨ a ≤ b ∧ ℵ₀ ≤ a := by --- cases' le_or_lt ℵ₀ a with ha ha <;> cases' le_or_lt ℵ₀ b with hb hb +-- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb -- · simp only [bit1_eq_self_iff.mpr ha, bit0_eq_self hb, ha, and_true_iff] -- refine' ⟨fun h => Or.inr h, fun h => _⟩ -- cases h @@ -1365,7 +1365,7 @@ theorem extend_function_of_lt {α β : Type*} {s : Set α} (f : s ↪ β) (hs : -- @[simp] -- theorem bit0_lt_bit0 {a b : Cardinal} : bit0 a < bit0 b ↔ a < b := by --- cases' le_or_lt ℵ₀ a with ha ha <;> cases' le_or_lt ℵ₀ b with hb hb +-- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb -- · rw [bit0_eq_self ha, bit0_eq_self hb] -- · rw [bit0_eq_self ha] -- refine' iff_of_false (fun h => _) (hb.le.trans ha).not_lt @@ -1381,7 +1381,7 @@ theorem extend_function_of_lt {α β : Type*} {s : Set α} (f : s ↪ β) (hs : -- @[simp] -- theorem bit1_lt_bit0 {a b : Cardinal} : bit1 a < bit0 b ↔ a < b := by --- cases' le_or_lt ℵ₀ a with ha ha <;> cases' le_or_lt ℵ₀ b with hb hb +-- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb -- · rw [bit1_eq_self_iff.2 ha, bit0_eq_self hb] -- · rw [bit1_eq_self_iff.2 ha] -- refine' iff_of_false (fun h => _) (hb.le.trans ha).not_lt @@ -1397,7 +1397,7 @@ theorem extend_function_of_lt {α β : Type*} {s : Set α} (f : s ↪ β) (hs : -- @[simp] -- theorem bit1_lt_bit1 {a b : Cardinal} : bit1 a < bit1 b ↔ a < b := by --- cases' le_or_lt ℵ₀ a with ha ha <;> cases' le_or_lt ℵ₀ b with hb hb +-- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb -- · rw [bit1_eq_self_iff.2 ha, bit1_eq_self_iff.2 hb] -- · rw [bit1_eq_self_iff.2 ha] -- refine' iff_of_false (fun h => _) (hb.le.trans ha).not_lt @@ -1413,7 +1413,7 @@ theorem extend_function_of_lt {α β : Type*} {s : Set α} (f : s ↪ β) (hs : -- @[simp] -- theorem bit0_lt_bit1 {a b : Cardinal} : bit0 a < bit1 b ↔ a < b ∨ a ≤ b ∧ a < ℵ₀ := by --- cases' le_or_lt ℵ₀ a with ha ha <;> cases' le_or_lt ℵ₀ b with hb hb +-- rcases le_or_lt ℵ₀ a with ha | ha <;> rcases le_or_lt ℵ₀ b with hb | hb -- · simp [bit0_eq_self ha, bit1_eq_self_iff.2 hb, not_lt.mpr ha] -- · rw [bit0_eq_self ha] -- refine' iff_of_false (fun h => _) fun h => _ diff --git a/Mathlib/SetTheory/Ordinal/Arithmetic.lean b/Mathlib/SetTheory/Ordinal/Arithmetic.lean index c43ad501a0e19..c2d839ab22772 100644 --- a/Mathlib/SetTheory/Ordinal/Arithmetic.lean +++ b/Mathlib/SetTheory/Ordinal/Arithmetic.lean @@ -2345,7 +2345,7 @@ theorem nat_cast_pos {n : ℕ} : (0 : Ordinal) < n ↔ 0 < n := @[simp, norm_cast] theorem nat_cast_sub (m n : ℕ) : ((m - n : ℕ) : Ordinal) = m - n := by - cases' le_total m n with h h + rcases le_total m n with h | h · rw [tsub_eq_zero_iff_le.2 h, Ordinal.sub_eq_zero_iff_le.2 (nat_cast_le.2 h)] rfl · apply (add_left_cancel n).1 diff --git a/Mathlib/SetTheory/Ordinal/CantorNormalForm.lean b/Mathlib/SetTheory/Ordinal/CantorNormalForm.lean index bed9105c56c5b..c22ce85dd8cb5 100644 --- a/Mathlib/SetTheory/Ordinal/CantorNormalForm.lean +++ b/Mathlib/SetTheory/Ordinal/CantorNormalForm.lean @@ -163,7 +163,7 @@ set_option linter.uppercaseLean3 false in theorem CNF_sorted (b o : Ordinal) : ((CNF b o).map Prod.fst).Sorted (· > ·) := by refine' CNFRec b _ (fun o ho IH ↦ _) o · simp only [gt_iff_lt, CNF_zero, map_nil, sorted_nil] - · cases' le_or_lt b 1 with hb hb + · rcases le_or_lt b 1 with hb | hb · simp only [CNF_of_le_one hb ho, gt_iff_lt, map_cons, map, sorted_singleton] · cases' lt_or_le o b with hob hbo · simp only [CNF_of_lt ho hob, gt_iff_lt, map_cons, map, sorted_singleton] diff --git a/Mathlib/SetTheory/Ordinal/Exponential.lean b/Mathlib/SetTheory/Ordinal/Exponential.lean index 6d08cedf7a25c..b186345e94f2e 100644 --- a/Mathlib/SetTheory/Ordinal/Exponential.lean +++ b/Mathlib/SetTheory/Ordinal/Exponential.lean @@ -136,7 +136,7 @@ theorem opow_isLimit_left {a b : Ordinal} (l : IsLimit a) (hb : b ≠ 0) : IsLim #align ordinal.opow_is_limit_left Ordinal.opow_isLimit_left theorem opow_le_opow_right {a b c : Ordinal} (h₁ : 0 < a) (h₂ : b ≤ c) : a ^ b ≤ a ^ c := by - cases' lt_or_eq_of_le (one_le_iff_pos.2 h₁) with h₁ h₁ + rcases lt_or_eq_of_le (one_le_iff_pos.2 h₁) with h₁ | h₁ · exact (opow_le_opow_iff_right h₁).2 h₂ · subst a -- Porting note: `le_refl` is required. @@ -164,7 +164,7 @@ theorem opow_le_opow_left {a b : Ordinal} (c : Ordinal) (ab : a ≤ b) : a ^ c theorem left_le_opow (a : Ordinal) {b : Ordinal} (b1 : 0 < b) : a ≤ a ^ b := by nth_rw 1 [← opow_one a] cases' le_or_gt a 1 with a1 a1 - · cases' lt_or_eq_of_le a1 with a0 a1 + · rcases lt_or_eq_of_le a1 with a0 | a1 · rw [lt_one_iff_zero] at a0 rw [a0, zero_opow Ordinal.one_ne_zero] exact Ordinal.zero_le _ @@ -346,7 +346,7 @@ theorem log_pos {b o : Ordinal} (hb : 1 < b) (ho : o ≠ 0) (hbo : b ≤ o) : 0 theorem log_eq_zero {b o : Ordinal} (hbo : o < b) : log b o = 0 := by rcases eq_or_ne o 0 with (rfl | ho) · exact log_zero_right b - cases' le_or_lt b 1 with hb hb + rcases le_or_lt b 1 with hb | hb · rcases le_one_iff.1 hb with (rfl | rfl) · exact log_zero_left o · exact log_one_left o @@ -383,7 +383,7 @@ theorem mod_opow_log_lt_self (b : Ordinal) {o : Ordinal} (ho : o ≠ 0) : o % (b theorem log_mod_opow_log_lt_log_self {b o : Ordinal} (hb : 1 < b) (ho : o ≠ 0) (hbo : b ≤ o) : log b (o % (b ^ log b o)) < log b o := by - cases' eq_or_ne (o % (b ^ log b o)) 0 with h h + rcases eq_or_ne (o % (b ^ log b o)) 0 with h | h · rw [h, log_zero_right] apply log_pos hb ho hbo · rw [← succ_le_iff, succ_log_def hb h] diff --git a/Mathlib/SetTheory/Ordinal/FixedPoint.lean b/Mathlib/SetTheory/Ordinal/FixedPoint.lean index 49233ab33c76c..24e54dbca4207 100644 --- a/Mathlib/SetTheory/Ordinal/FixedPoint.lean +++ b/Mathlib/SetTheory/Ordinal/FixedPoint.lean @@ -205,7 +205,7 @@ theorem le_iff_derivFamily (H : ∀ i, IsNormal (f i)) {a} : rw [derivFamily_zero] exact nfpFamily_le_fp (fun i => (H i).monotone) (Ordinal.zero_le _) ha · intro h₁ - cases' le_or_lt a (derivFamily.{u, v} f o) with h h + rcases le_or_lt a (derivFamily.{u, v} f o) with h | h · exact IH h refine' ⟨succ o, le_antisymm _ h₁⟩ rw [derivFamily_succ] @@ -649,7 +649,7 @@ theorem deriv_mul_zero : deriv (HMul.hMul 0) = id := theorem nfp_mul_eq_opow_omega {a b : Ordinal} (hb : 0 < b) (hba : b ≤ (a^omega)) : nfp (a * ·) b = (a^omega.{u}) := by - cases' eq_zero_or_pos a with ha ha + rcases eq_zero_or_pos a with ha | ha · rw [ha, zero_opow omega_ne_zero] at hba ⊢ rw [Ordinal.le_zero.1 hba, nfp_zero_mul] rfl @@ -662,7 +662,7 @@ theorem nfp_mul_eq_opow_omega {a b : Ordinal} (hb : 0 < b) (hba : b ≤ (a^omega theorem eq_zero_or_opow_omega_le_of_mul_eq_right {a b : Ordinal} (hab : a * b = b) : b = 0 ∨ (a^omega.{u}) ≤ b := by - cases' eq_zero_or_pos a with ha ha + rcases eq_zero_or_pos a with ha | ha · rw [ha, zero_opow omega_ne_zero] exact Or.inr (Ordinal.zero_le b) rw [or_iff_not_imp_left] @@ -673,7 +673,7 @@ theorem eq_zero_or_opow_omega_le_of_mul_eq_right {a b : Ordinal} (hab : a * b = #align ordinal.eq_zero_or_opow_omega_le_of_mul_eq_right Ordinal.eq_zero_or_opow_omega_le_of_mul_eq_right theorem mul_eq_right_iff_opow_omega_dvd {a b : Ordinal} : a * b = b ↔ (a^omega) ∣ b := by - cases' eq_zero_or_pos a with ha ha + rcases eq_zero_or_pos a with ha | ha · rw [ha, zero_mul, zero_opow omega_ne_zero, zero_dvd_iff] exact eq_comm refine' ⟨fun hab => _, fun h => _⟩ diff --git a/Mathlib/SetTheory/Ordinal/Notation.lean b/Mathlib/SetTheory/Ordinal/Notation.lean index 113f6b9987dd5..3e30da76b787b 100644 --- a/Mathlib/SetTheory/Ordinal/Notation.lean +++ b/Mathlib/SetTheory/Ordinal/Notation.lean @@ -873,7 +873,7 @@ theorem repr_opow_aux₁ {e a} [Ne : NF e] [Na : NF a] {a' : Ordinal} (e0 : repr apply (opow_le_opow_left b <| this.le).trans rw [← opow_mul, ← opow_mul] apply opow_le_opow_right omega_pos - cases' le_or_lt ω (repr e) with h h + rcases le_or_lt ω (repr e) with h | h · apply (mul_le_mul_left' (le_succ b) _).trans rw [← add_one_eq_succ, add_mul_succ _ (one_add_of_omega_le h), add_one_eq_succ, succ_le_iff, Ordinal.mul_lt_mul_iff_left (Ordinal.pos_iff_ne_zero.2 e0)] diff --git a/Mathlib/SetTheory/Ordinal/Principal.lean b/Mathlib/SetTheory/Ordinal/Principal.lean index ae41f60a023dc..1d686f3c59747 100644 --- a/Mathlib/SetTheory/Ordinal/Principal.lean +++ b/Mathlib/SetTheory/Ordinal/Principal.lean @@ -128,7 +128,7 @@ theorem principal_add_isLimit {o : Ordinal} (ho₁ : 1 < o) (ho : Principal (· refine' ⟨fun ho₀ => _, fun a hao => _⟩ · rw [ho₀] at ho₁ exact not_lt_of_gt zero_lt_one ho₁ - · cases' eq_or_ne a 0 with ha ha + · rcases eq_or_ne a 0 with ha | ha · rw [ha, succ_zero] exact ho₁ · refine' lt_of_le_of_lt _ (ho hao hao) @@ -373,7 +373,7 @@ theorem principal_add_of_principal_mul_opow {o b : Ordinal} (hb : 1 < b) theorem principal_mul_iff_le_two_or_omega_opow_opow {o : Ordinal} : Principal (· * ·) o ↔ o ≤ 2 ∨ ∃ a : Ordinal, o = (omega^omega^a) := by refine' ⟨fun ho => _, _⟩ - · cases' le_or_lt o 2 with ho₂ ho₂ + · rcases le_or_lt o 2 with ho₂ | ho₂ · exact Or.inl ho₂ rcases principal_add_iff_zero_or_omega_opow.1 (principal_add_of_principal_mul ho ho₂.ne') with (rfl | ⟨a, rfl⟩) diff --git a/Mathlib/SetTheory/Ordinal/Topology.lean b/Mathlib/SetTheory/Ordinal/Topology.lean index fb0415372b704..e23eae9da1d32 100644 --- a/Mathlib/SetTheory/Ordinal/Topology.lean +++ b/Mathlib/SetTheory/Ordinal/Topology.lean @@ -96,7 +96,7 @@ theorem mem_closure_tfae (a : Ordinal.{u}) (s : Set Ordinal) : exact id tfae_have 2 → 3 · intro h - cases' (s ∩ Iic a).eq_empty_or_nonempty with he hne + rcases (s ∩ Iic a).eq_empty_or_nonempty with he | hne · simp [he] at h · refine ⟨hne, (isLUB_of_mem_closure ?_ h).csSup_eq hne⟩ exact fun x hx => hx.2 diff --git a/Mathlib/Topology/Algebra/Order/Compact.lean b/Mathlib/Topology/Algebra/Order/Compact.lean index f189ef8dcb66b..b1f67c71e7223 100644 --- a/Mathlib/Topology/Algebra/Order/Compact.lean +++ b/Mathlib/Topology/Algebra/Order/Compact.lean @@ -70,7 +70,7 @@ instance (priority := 100) ConditionallyCompleteLinearOrder.toCompactIccSpace ( [ConditionallyCompleteLinearOrder α] [TopologicalSpace α] [OrderTopology α] : CompactIccSpace α := by refine' .mk'' fun {a b} hlt => ?_ - cases' le_or_lt a b with hab hab + rcases le_or_lt a b with hab | hab swap · simp [hab] refine' isCompact_iff_ultrafilter_le_nhds.2 fun f hf => _ diff --git a/Mathlib/Topology/Algebra/Order/IntermediateValue.lean b/Mathlib/Topology/Algebra/Order/IntermediateValue.lean index 101a5ddc2e180..892a2125a47a9 100644 --- a/Mathlib/Topology/Algebra/Order/IntermediateValue.lean +++ b/Mathlib/Topology/Algebra/Order/IntermediateValue.lean @@ -411,7 +411,7 @@ theorem isPreconnected_Icc : IsPreconnected (Icc a b) := (by rintro s t hs ht hab ⟨x, hx⟩ ⟨y, hy⟩ -- This used to use `wlog`, but it was causing timeouts. - cases' le_total x y with h h + rcases le_total x y with h | h · exact isPreconnected_Icc_aux x y s t h hs ht hab hx hy · rw [inter_comm s t] rw [union_comm s t] at hab @@ -606,7 +606,7 @@ theorem ContinuousOn.surjOn_Icc {s : Set α} [hs : OrdConnected s] {f : α → `b` are two points of this set, then `f` sends `s` to a superset of `[f x, f y]`. -/ theorem ContinuousOn.surjOn_uIcc {s : Set α} [hs : OrdConnected s] {f : α → δ} (hf : ContinuousOn f s) {a b : α} (ha : a ∈ s) (hb : b ∈ s) : SurjOn f s (uIcc (f a) (f b)) := - by cases' le_total (f a) (f b) with hab hab <;> simp [hf.surjOn_Icc, *] + by rcases le_total (f a) (f b) with hab | hab <;> simp [hf.surjOn_Icc, *] #align continuous_on.surj_on_uIcc ContinuousOn.surjOn_uIcc /-- A continuous function which tendsto `Filter.atTop` along `Filter.atTop` and to `atBot` along diff --git a/Mathlib/Topology/Algebra/ValuedField.lean b/Mathlib/Topology/Algebra/ValuedField.lean index c1c14cf3b87b5..e426a61d2ffeb 100644 --- a/Mathlib/Topology/Algebra/ValuedField.lean +++ b/Mathlib/Topology/Algebra/ValuedField.lean @@ -322,7 +322,7 @@ theorem closure_coe_completion_v_lt {γ : Γ₀ˣ} : ext x let γ₀ := extensionValuation x suffices γ₀ ≠ 0 → (x ∈ closure ((↑) '' { x : K | v x < (γ : Γ₀) }) ↔ γ₀ < (γ : Γ₀)) by - cases' eq_or_ne γ₀ 0 with h h + rcases eq_or_ne γ₀ 0 with h | h · simp only [h, (Valuation.zero_iff _).mp h, mem_setOf_eq, Valuation.map_zero, Units.zero_lt, iff_true_iff] apply subset_closure diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index e681390b4ad7e..b24f17c03d94f 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -731,7 +731,7 @@ theorem isOpenMap_snd : IsOpenMap (@Prod.snd α β) := empty -/ theorem isOpen_prod_iff' {s : Set α} {t : Set β} : IsOpen (s ×ˢ t) ↔ IsOpen s ∧ IsOpen t ∨ s = ∅ ∨ t = ∅ := by - cases' (s ×ˢ t).eq_empty_or_nonempty with h h + rcases (s ×ˢ t).eq_empty_or_nonempty with h | h · simp [h, prod_eq_empty_iff.1 h] · have st : s.Nonempty ∧ t.Nonempty := prod_nonempty_iff.1 h constructor diff --git a/Mathlib/Topology/FiberBundle/Basic.lean b/Mathlib/Topology/FiberBundle/Basic.lean index d95f99bad8467..1f322bc36579d 100644 --- a/Mathlib/Topology/FiberBundle/Basic.lean +++ b/Mathlib/Topology/FiberBundle/Basic.lean @@ -333,7 +333,7 @@ theorem FiberBundle.exists_trivialization_Icc_subset [ConditionallyCompleteLinea have hsc : IsLUB s c := isLUB_csSup sne sbd have hc : c ∈ Icc a b := ⟨hsc.1 ha, hsc.2 hsb⟩ obtain ⟨-, ec : Trivialization F (π F E), hec : Icc a c ⊆ ec.baseSet⟩ : c ∈ s := by - cases' hc.1.eq_or_lt with heq hlt + rcases hc.1.eq_or_lt with heq | hlt · rwa [← heq] refine ⟨hc, ?_⟩ /- In order to show that `c ∈ s`, consider a trivialization `ec` of `proj` over a neighborhood @@ -351,7 +351,7 @@ theorem FiberBundle.exists_trivialization_Icc_subset [ConditionallyCompleteLinea /- So, `c ∈ s`. Let `ec` be a trivialization of `proj` over `[a, c]`. If `c = b`, then we are done. Otherwise we show that `proj` can be trivialized over a larger interval `[a, d]`, `d ∈ (c, b]`, hence `c` is not an upper bound of `s`. -/ - cases' hc.2.eq_or_lt with heq hlt + rcases hc.2.eq_or_lt with heq | hlt · exact ⟨ec, heq ▸ hec⟩ rsuffices ⟨d, hdcb, hd⟩ : ∃ d ∈ Ioc c b, ∃ e : Trivialization F (π F E), Icc a d ⊆ e.baseSet · exact ((hsc.1 ⟨⟨hc.1.trans hdcb.1.le, hdcb.2⟩, hd⟩).not_lt hdcb.1).elim diff --git a/Mathlib/Topology/Maps.lean b/Mathlib/Topology/Maps.lean index f997d612dcc52..c8f5f542b227f 100644 --- a/Mathlib/Topology/Maps.lean +++ b/Mathlib/Topology/Maps.lean @@ -504,7 +504,7 @@ theorem of_inverse {f : α → β} {f' : β → α} (h : Continuous f') (l_inv : theorem of_nonempty {f : α → β} (h : ∀ s, IsClosed s → s.Nonempty → IsClosed (f '' s)) : IsClosedMap f := by - intro s hs; cases' eq_empty_or_nonempty s with h2s h2s + intro s hs; rcases eq_empty_or_nonempty s with h2s | h2s · simp_rw [h2s, image_empty, isClosed_empty] · exact h s hs h2s #align is_closed_map.of_nonempty IsClosedMap.of_nonempty diff --git a/Mathlib/Topology/MetricSpace/Baire.lean b/Mathlib/Topology/MetricSpace/Baire.lean index 875a80922ec47..4df164b42b20e 100644 --- a/Mathlib/Topology/MetricSpace/Baire.lean +++ b/Mathlib/Topology/MetricSpace/Baire.lean @@ -195,7 +195,7 @@ theorem dense_iInter_of_isOpen_nat {f : ℕ → Set α} (ho : ∀ n, IsOpen (f n /-- Baire theorem: a countable intersection of dense open sets is dense. Formulated here with ⋂₀. -/ theorem dense_sInter_of_isOpen {S : Set (Set α)} (ho : ∀ s ∈ S, IsOpen s) (hS : S.Countable) (hd : ∀ s ∈ S, Dense s) : Dense (⋂₀ S) := by - cases' S.eq_empty_or_nonempty with h h + rcases S.eq_empty_or_nonempty with h | h · simp [h] · rcases hS.exists_eq_range h with ⟨f, hf⟩ have F : ∀ n, f n ∈ S := fun n => by rw [hf]; exact mem_range_self _ diff --git a/Mathlib/Topology/MetricSpace/Cauchy.lean b/Mathlib/Topology/MetricSpace/Cauchy.lean index 18016cb1982ff..2a82221a27baf 100644 --- a/Mathlib/Topology/MetricSpace/Cauchy.lean +++ b/Mathlib/Topology/MetricSpace/Cauchy.lean @@ -117,7 +117,7 @@ theorem cauchySeq_bdd {u : ℕ → α} (hu : CauchySeq u) : ∃ R > 0, ∀ m n, lt_of_le_of_lt (dist_triangle_right _ _ _) (add_lt_add (H m) (H n))⟩ let R := Finset.sup (Finset.range N) fun n => nndist (u n) (u N) refine' ⟨↑R + 1, add_pos_of_nonneg_of_pos R.2 zero_lt_one, fun n => _⟩ - cases' le_or_lt N n with h h + rcases le_or_lt N n with h | h · exact lt_of_lt_of_le (hN _ h) (le_add_of_nonneg_left R.2) · have : _ ≤ R := Finset.le_sup (Finset.mem_range.2 h) exact lt_of_le_of_lt this (lt_add_of_pos_right _ zero_lt_one) diff --git a/Mathlib/Topology/MetricSpace/HausdorffDistance.lean b/Mathlib/Topology/MetricSpace/HausdorffDistance.lean index 52960eda285c9..13fdb18b576a5 100644 --- a/Mathlib/Topology/MetricSpace/HausdorffDistance.lean +++ b/Mathlib/Topology/MetricSpace/HausdorffDistance.lean @@ -432,8 +432,8 @@ theorem nonempty_of_hausdorffEdist_ne_top (hs : s.Nonempty) (fin : hausdorffEdis theorem empty_or_nonempty_of_hausdorffEdist_ne_top (fin : hausdorffEdist s t ≠ ⊤) : (s = ∅ ∧ t = ∅) ∨ (s.Nonempty ∧ t.Nonempty) := by - cases' s.eq_empty_or_nonempty with hs hs - · cases' t.eq_empty_or_nonempty with ht ht + rcases s.eq_empty_or_nonempty with hs | hs + · rcases t.eq_empty_or_nonempty with ht | ht · exact Or.inl ⟨hs, ht⟩ · rw [hausdorffEdist_comm] at fin exact Or.inr ⟨nonempty_of_hausdorffEdist_ne_top ht fin, ht⟩ @@ -622,7 +622,7 @@ theorem infDist_inter_closedBall_of_mem (h : y ∈ s) : refine le_antisymm ?_ (infDist_le_infDist_of_subset (inter_subset_left _ _) ⟨y, h⟩) refine' not_lt.1 fun hlt => _ rcases (infDist_lt_iff ⟨y, h.1⟩).mp hlt with ⟨z, hzs, hz⟩ - cases' le_or_lt (dist z x) (dist y x) with hle hlt + rcases le_or_lt (dist z x) (dist y x) with hle | hlt · exact hz.not_le (infDist_le_dist_of_mem ⟨hzs, hle⟩) · rw [dist_comm z, dist_comm y] at hlt exact (hlt.trans hz).not_le (infDist_le_dist_of_mem h) @@ -727,7 +727,7 @@ theorem hausdorffDist_comm : hausdorffDist s t = hausdorffDist t s := by value ∞ instead, use `EMetric.hausdorffEdist`, which takes values in ℝ≥0∞) -/ @[simp] theorem hausdorffDist_empty : hausdorffDist s ∅ = 0 := by - cases' s.eq_empty_or_nonempty with h h + rcases s.eq_empty_or_nonempty with h | h · simp [h] · simp [hausdorffDist, hausdorffEdist_empty h] #align metric.Hausdorff_dist_empty Metric.hausdorffDist_empty @@ -744,9 +744,9 @@ theorem hausdorffDist_le_of_infDist {r : ℝ} (hr : 0 ≤ r) (H1 : ∀ x ∈ s, (H2 : ∀ x ∈ t, infDist x s ≤ r) : hausdorffDist s t ≤ r := by by_cases h1 : hausdorffEdist s t = ⊤ · rwa [hausdorffDist, h1, ENNReal.top_toReal] - cases' s.eq_empty_or_nonempty with hs hs + rcases s.eq_empty_or_nonempty with hs | hs · rwa [hs, hausdorffDist_empty'] - cases' t.eq_empty_or_nonempty with ht ht + rcases t.eq_empty_or_nonempty with ht | ht · rwa [ht, hausdorffDist_empty] have : hausdorffEdist s t ≤ ENNReal.ofReal r := by apply hausdorffEdist_le_of_infEdist _ _ @@ -962,7 +962,7 @@ theorem frontier_thickening_subset (E : Set α) {δ : ℝ} : theorem frontier_thickening_disjoint (A : Set α) : Pairwise (Disjoint on fun r : ℝ => frontier (thickening r A)) := by refine' (pairwise_disjoint_on _).2 fun r₁ r₂ hr => _ - cases' le_total r₁ 0 with h₁ h₁ + rcases le_total r₁ 0 with h₁ | h₁ · simp [thickening_of_nonpos h₁] refine' ((disjoint_singleton.2 fun h => hr.ne _).preimage _).mono (frontier_thickening_subset _) (frontier_thickening_subset _) diff --git a/Mathlib/Topology/MetricSpace/Kuratowski.lean b/Mathlib/Topology/MetricSpace/Kuratowski.lean index 17bd6111f318e..26abf589eb0a9 100644 --- a/Mathlib/Topology/MetricSpace/Kuratowski.lean +++ b/Mathlib/Topology/MetricSpace/Kuratowski.lean @@ -93,7 +93,7 @@ theorem embeddingOfSubset_isometry (H : DenseRange x) : Isometry (embeddingOfSub /-- Every separable metric space embeds isometrically in `ℓ^∞(ℕ)`. -/ theorem exists_isometric_embedding (α : Type u) [MetricSpace α] [SeparableSpace α] : ∃ f : α → ℓ^∞(ℕ), Isometry f := by - cases' (univ : Set α).eq_empty_or_nonempty with h h + rcases (univ : Set α).eq_empty_or_nonempty with h | h · use fun _ => 0; intro x; exact absurd h (Nonempty.ne_empty ⟨x, mem_univ x⟩) · -- We construct a map x : ℕ → α with dense image rcases h with ⟨basepoint⟩ diff --git a/Mathlib/Topology/MetricSpace/PseudoMetric.lean b/Mathlib/Topology/MetricSpace/PseudoMetric.lean index 745d0b44e1553..ac9ed4e043fd0 100644 --- a/Mathlib/Topology/MetricSpace/PseudoMetric.lean +++ b/Mathlib/Topology/MetricSpace/PseudoMetric.lean @@ -870,7 +870,7 @@ theorem totallyBounded_of_finite_discretization {s : Set α} (H : ∀ ε > (0 : ℝ), ∃ (β : Type u) (_ : Fintype β) (F : s → β), ∀ x y, F x = F y → dist (x : α) y < ε) : TotallyBounded s := by - cases' s.eq_empty_or_nonempty with hs hs + rcases s.eq_empty_or_nonempty with hs | hs · rw [hs] exact totallyBounded_empty rcases hs with ⟨x0, hx0⟩ @@ -2166,7 +2166,7 @@ theorem exists_pos_lt_subset_ball (hr : 0 < r) (hs : IsClosed s) (h : s ⊆ ball /-- If a ball in a proper space includes a closed set `s`, then there exists a ball with the same center and a strictly smaller radius that includes `s`. -/ theorem exists_lt_subset_ball (hs : IsClosed s) (h : s ⊆ ball x r) : ∃ r' < r, s ⊆ ball x r' := by - cases' le_or_lt r 0 with hr hr + rcases le_or_lt r 0 with hr | hr · rw [ball_eq_empty.2 hr, subset_empty_iff] at h subst s exact (exists_lt r).imp fun r' hr' => ⟨hr', empty_subset _⟩ diff --git a/Mathlib/Topology/Metrizable/Uniformity.lean b/Mathlib/Topology/Metrizable/Uniformity.lean index a92d51d8e47da..889c5b56b6931 100644 --- a/Mathlib/Topology/Metrizable/Uniformity.lean +++ b/Mathlib/Topology/Metrizable/Uniformity.lean @@ -128,7 +128,7 @@ theorem le_two_mul_dist_ofPreNNDist (d : X → X → ℝ≥0) (dist_self : ∀ x subst n set L := zipWith d (x::l) (l ++ [y]) have hL_len : length L = length l + 1 := by simp - cases' eq_or_ne (d x y) 0 with hd₀ hd₀ + rcases eq_or_ne (d x y) 0 with hd₀ | hd₀ · simp only [hd₀, zero_le] rsuffices ⟨z, z', hxz, hzz', hz'y⟩ : ∃ z z' : X, d x z ≤ L.sum ∧ d z z' ≤ L.sum ∧ d z' y ≤ L.sum · exact (hd x z z' y).trans (mul_le_mul_left' (max_le hxz (max_le hzz' hz'y)) _) diff --git a/Mathlib/Topology/Metrizable/Urysohn.lean b/Mathlib/Topology/Metrizable/Urysohn.lean index a845af699534a..53ccf9f534404 100644 --- a/Mathlib/Topology/Metrizable/Urysohn.lean +++ b/Mathlib/Topology/Metrizable/Urysohn.lean @@ -87,7 +87,7 @@ theorem exists_inducing_l_infty : ∃ f : X → ℕ →ᵇ ℝ, Inducing f := by refine' (eventually_all_finite h_fin).2 fun UV _ => _ exact (f UV).continuous.tendsto x (closedBall_mem_nhds _ δ0) refine' this.mono fun y hy => (BoundedContinuousFunction.dist_le δ0.le).2 fun UV => _ - cases' le_total δ (ε UV) with hle hle + rcases le_total δ (ε UV) with hle | hle exacts [hy _ hle, (Real.dist_le_of_mem_Icc (hf0ε _ _) (hf0ε _ _)).trans (by rwa [sub_zero])] · /- Finally, we prove that each neighborhood `V` of `x : X` includes a preimage of a neighborhood of `F x` under `F`. diff --git a/Mathlib/Topology/Order/Basic.lean b/Mathlib/Topology/Order/Basic.lean index 1e1b84e6a24ad..9b2facc704b4e 100644 --- a/Mathlib/Topology/Order/Basic.lean +++ b/Mathlib/Topology/Order/Basic.lean @@ -2774,7 +2774,7 @@ theorem IsClosed.sInf_mem {α : Type u} [TopologicalSpace α] [CompleteLinearOrd this supremum to the supremum of the image of this set. -/ theorem Monotone.map_sSup_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sSup s)) (Mf : Monotone f) (fbot : f ⊥ = ⊥) : f (sSup s) = sSup (f '' s) := by - cases' s.eq_empty_or_nonempty with h h + rcases s.eq_empty_or_nonempty with h | h · simp [h, fbot] · exact Mf.map_sSup_of_continuousAt' Cf h #align monotone.map_Sup_of_continuous_at Monotone.map_sSup_of_continuousAt diff --git a/Mathlib/Topology/Separation.lean b/Mathlib/Topology/Separation.lean index d828fd9ce59af..2be4ca20a9a76 100644 --- a/Mathlib/Topology/Separation.lean +++ b/Mathlib/Topology/Separation.lean @@ -1954,7 +1954,7 @@ instance (priority := 100) NormalSpace.of_regularSpace_secondCountableTopology exact (hUd u huU).le_bot ⟨hxu, hx⟩ · simp only [disjoint_left, mem_iUnion, mem_diff, not_exists, not_and, not_forall, not_not] rintro a ⟨u, huU, hau, haV⟩ v hvV hav - cases' le_total (Encodable.encode u) (Encodable.encode v) with hle hle + rcases le_total (Encodable.encode u) (Encodable.encode v) with hle | hle exacts [⟨u, huU, hle, subset_closure hau⟩, (haV _ hvV hle <| subset_closure hav).elim] #align normal_space_of_t3_second_countable NormalSpace.of_regularSpace_secondCountableTopology diff --git a/Mathlib/Topology/TietzeExtension.lean b/Mathlib/Topology/TietzeExtension.lean index 99c309dc19fa3..50ab9d32d156b 100644 --- a/Mathlib/Topology/TietzeExtension.lean +++ b/Mathlib/Topology/TietzeExtension.lean @@ -77,13 +77,13 @@ theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : ClosedEmbed · refine' (dist_le <| mul_nonneg h23.le hf.le).mpr fun x => _ have hfx : -‖f‖ ≤ f x ∧ f x ≤ ‖f‖ := by simpa only [Real.norm_eq_abs, abs_le] using f.norm_coe_le_norm x - cases' le_total (f x) (-‖f‖ / 3) with hle₁ hle₁ + rcases le_total (f x) (-‖f‖ / 3) with hle₁ | hle₁ · calc |g (e x) - f x| = -‖f‖ / 3 - f x := by rw [hg₁ (mem_image_of_mem _ hle₁), Function.const_apply, abs_of_nonneg (sub_nonneg.2 hle₁)] _ ≤ 2 / 3 * ‖f‖ := by linarith - · cases' le_total (f x) (‖f‖ / 3) with hle₂ hle₂ + · rcases le_total (f x) (‖f‖ / 3) with hle₂ | hle₂ · simp only [neg_div] at * calc dist (g (e x)) (f x) ≤ |g (e x)| + |f x| := dist_le_norm_add_norm _ _ @@ -253,7 +253,7 @@ theorem exists_extension_forall_exists_le_ge_of_closedEmbedding [Nonempty X] (f · exact hlt.trans_le ((le_add_iff_nonneg_right _).2 <| (dgmem y).1) rcases ha.exists_between hay with ⟨_, ⟨x, rfl⟩, _, hxy⟩ refine' ⟨x, hxy.le, _⟩ - cases' le_total c (g y) with hc hc + rcases le_total c (g y) with hc | hc · simp [dg0 (Or.inr hc), (hg_mem y).2] · calc g y + dg y ≤ c + (c - a) := add_le_add hc (dgmem _).2 diff --git a/Mathlib/Topology/UniformSpace/Cauchy.lean b/Mathlib/Topology/UniformSpace/Cauchy.lean index 7dd68c154886e..d52a1695cb10f 100644 --- a/Mathlib/Topology/UniformSpace/Cauchy.lean +++ b/Mathlib/Topology/UniformSpace/Cauchy.lean @@ -655,7 +655,7 @@ theorem CauchySeq.totallyBounded_range {s : ℕ → α} (hs : CauchySeq s) : rw [range_subset_iff, biUnion_image] intro m rw [mem_iUnion₂] - cases' le_total m n with hm hm + rcases le_total m n with hm | hm exacts [⟨m, hm, refl_mem_uniformity ha⟩, ⟨n, le_refl n, hn m hm n le_rfl⟩] #align cauchy_seq.totally_bounded_range CauchySeq.totallyBounded_range From da34c254e89b2cde09d066068c17cf30ebe603f8 Mon Sep 17 00:00:00 2001 From: Wrenna Robson Date: Thu, 21 Dec 2023 16:16:28 +0000 Subject: [PATCH 114/353] fix(Data/Option/Defs): Remove `Option.rel` and `Option.maybe`, superceded by std4 (#9178) Remove `Option.rel` and `Option.maybe`, which have identical definitions to `Option.Rel` and `Option.sequence`, and aren't used anywhere. --- Mathlib/Data/Option/Defs.lean | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/Mathlib/Data/Option/Defs.lean b/Mathlib/Data/Option/Defs.lean index b761023e997b3..7d315c0c52ce9 100644 --- a/Mathlib/Data/Option/Defs.lean +++ b/Mathlib/Data/Option/Defs.lean @@ -21,15 +21,6 @@ namespace Option #align option.lift_or_get Option.liftOrGet -/-- Lifts a relation `α → β → Prop` to a relation `Option α → Option β → Prop` by just adding -`none ~ none`. -/ -inductive rel (r : α → β → Prop) : Option α → Option β → Prop - | /-- If `a ~ b`, then `some a ~ some b` -/ - some {a b} : r a b → rel r (some a) (some b) - | /-- `none ~ none` -/ - none : rel r none none -#align option.rel Option.rel - /-- Traverse an object of `Option α` with a function `f : α → F β` for an applicative `F`. -/ protected def traverse.{u, v} {F : Type u → Type v} [Applicative F] {α : Type*} {β : Type u} (f : α → F β) : @@ -38,13 +29,7 @@ protected def traverse.{u, v} | some x => some <$> f x #align option.traverse Option.traverse -/-- If you maybe have a monadic computation in a `[Monad m]` which produces a term of type `α`, -then there is a naturally associated way to always perform a computation in `m` which maybe -produces a result. -/ -def maybe.{u, v} {m : Type u → Type v} [Monad m] {α : Type u} : Option (m α) → m (Option α) - | none => pure none - | some fn => some <$> fn -#align option.maybe Option.maybe +#align option.maybe Option.sequence #align option.mmap Option.mapM #align option.melim Option.elimM From 14c729603a56a1a02f31a1b28b852fe56d29c058 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Thu, 21 Dec 2023 20:35:54 +0000 Subject: [PATCH 115/353] =?UTF-8?q?chore(*):=20use=20`=E2=88=83=20x=20?= =?UTF-8?q?=E2=88=88=20s,=20=5F`=20instead=20of=20`=E2=88=83=20(x)=20(=5F?= =?UTF-8?q?=20:=20x=20=E2=88=88=20s),=20=5F`=20(#9184)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Search for `[∀∃].*(_` and manually replace some occurrences with more readable versions. In case of `∀`, the new expressions are defeq to the old ones. In case of `∃`, they differ by `exists_prop`. In some rare cases, golf proofs that needed fixing. --- Archive/Imo/Imo1994Q1.lean | 2 +- .../LinearOrderWithPosMulPosEqZero.lean | 2 +- Mathlib/Algebra/Algebra/Operations.lean | 4 +- Mathlib/Algebra/BigOperators/Basic.lean | 2 +- .../Algebra/BigOperators/Multiset/Basic.lean | 4 +- Mathlib/Algebra/BigOperators/Order.lean | 4 +- Mathlib/Algebra/GroupPower/Order.lean | 4 +- Mathlib/Algebra/Order/Support.lean | 4 +- .../PrimeSpectrum/Noetherian.lean | 4 +- Mathlib/Analysis/Analytic/Basic.lean | 2 +- Mathlib/Analysis/Calculus/FDeriv/Extend.lean | 4 +- .../Analysis/Calculus/FDeriv/Measurable.lean | 6 +-- Mathlib/Analysis/Calculus/Taylor.lean | 8 +-- Mathlib/Analysis/ConstantSpeed.lean | 2 +- Mathlib/Analysis/Convex/Caratheodory.lean | 4 +- Mathlib/Analysis/Convex/Combination.lean | 17 +++--- Mathlib/Analysis/Convex/Extreme.lean | 4 +- Mathlib/Analysis/Convex/Segment.lean | 54 +++++++------------ Mathlib/Analysis/Convex/Side.lean | 12 ++--- .../Convex/SimplicialComplex/Basic.lean | 8 +-- .../LocallyConvex/BalancedCoreHull.lean | 6 +-- Mathlib/Analysis/LocallyConvex/Bounded.lean | 6 +-- .../LocallyConvex/ContinuousOfBounded.lean | 10 ++-- .../Analysis/LocallyConvex/WithSeminorms.lean | 4 +- .../Analysis/NormedSpace/AddTorsorBases.lean | 2 +- Mathlib/Analysis/NormedSpace/LpEquiv.lean | 8 +-- Mathlib/Analysis/NormedSpace/lpSpace.lean | 2 +- Mathlib/Analysis/SpecificLimits/Normed.lean | 2 +- Mathlib/Combinatorics/Configuration.lean | 4 +- Mathlib/Combinatorics/Pigeonhole.lean | 8 +-- .../Combinatorics/SimpleGraph/Ends/Defs.lean | 2 +- Mathlib/Computability/Partrec.lean | 2 +- Mathlib/Data/Finset/Basic.lean | 6 +-- Mathlib/Data/Finset/Card.lean | 12 ++--- Mathlib/Data/Finset/Lattice.lean | 14 ++--- Mathlib/Data/Finset/PiInduction.lean | 2 +- Mathlib/Data/Finset/Powerset.lean | 4 +- Mathlib/Data/Finset/Preimage.lean | 8 +-- Mathlib/Data/List/Basic.lean | 6 +-- Mathlib/Data/List/BigOperators/Basic.lean | 4 +- Mathlib/Data/List/Chain.lean | 2 +- Mathlib/Data/List/Cycle.lean | 6 +-- Mathlib/Data/List/Nodup.lean | 2 +- Mathlib/Data/List/NodupEquivFin.lean | 2 +- Mathlib/Data/List/Sort.lean | 8 +-- Mathlib/Data/List/Zip.lean | 4 +- Mathlib/Data/Matrix/Basic.lean | 10 ++-- Mathlib/Data/Multiset/Basic.lean | 4 +- Mathlib/Data/MvPolynomial/Variables.lean | 3 +- Mathlib/Data/Polynomial/AlgebraMap.lean | 4 +- Mathlib/Data/Real/CauSeq.lean | 2 +- Mathlib/Data/Semiquot.lean | 6 +-- Mathlib/Data/Set/Basic.lean | 21 ++++---- Mathlib/Data/Set/Card.lean | 2 +- Mathlib/Data/Set/Function.lean | 12 ++--- Mathlib/Data/Set/Image.lean | 2 +- Mathlib/Data/Set/Intervals/OrdConnected.lean | 2 +- Mathlib/Data/Set/Intervals/Pi.lean | 2 +- .../Data/Set/Intervals/UnorderedInterval.lean | 2 +- Mathlib/Data/Set/Lattice.lean | 2 +- Mathlib/Data/Set/Pairwise/Basic.lean | 8 +-- Mathlib/Data/Set/Prod.lean | 4 +- Mathlib/Data/Set/UnionLift.lean | 8 +-- Mathlib/FieldTheory/Subfield.lean | 3 +- Mathlib/GroupTheory/MonoidLocalization.lean | 10 ++-- Mathlib/GroupTheory/Perm/Cycle/Basic.lean | 14 +++-- Mathlib/GroupTheory/Perm/Cycle/Concrete.lean | 2 +- Mathlib/GroupTheory/Subgroup/Basic.lean | 2 +- Mathlib/LinearAlgebra/FreeModule/PID.lean | 2 +- Mathlib/LinearAlgebra/LinearIndependent.lean | 4 +- .../LinearAlgebra/Matrix/ToLinearEquiv.lean | 14 ++--- .../Constructions/BorelSpace/Metrizable.lean | 3 +- .../Constructions/Cylinders.lean | 12 ++--- Mathlib/MeasureTheory/Function/Egorov.lean | 8 ++- .../Function/StronglyMeasurable/Basic.lean | 8 +-- Mathlib/MeasureTheory/Measure/Doubling.lean | 2 +- .../MeasureTheory/Measure/Haar/OfBasis.lean | 2 +- .../MeasureTheory/Measure/MeasureSpace.lean | 4 +- Mathlib/MeasureTheory/Measure/Restrict.lean | 2 +- .../MeasureTheory/Measure/VectorMeasure.lean | 4 +- Mathlib/MeasureTheory/PiSystem.lean | 10 ---- Mathlib/Order/Filter/Interval.lean | 2 +- Mathlib/Order/Zorn.lean | 18 +++---- Mathlib/RingTheory/AlgebraicIndependent.lean | 2 +- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 8 +-- .../RingTheory/UniqueFactorizationDomain.lean | 16 +++--- Mathlib/Topology/Algebra/FilterBasis.lean | 4 +- Mathlib/Topology/Algebra/Semigroup.lean | 2 +- .../Topology/Algebra/UniformFilterBasis.lean | 4 +- Mathlib/Topology/Algebra/Valuation.lean | 2 +- Mathlib/Topology/Bornology/Basic.lean | 11 ++-- .../Category/Profinite/CofilteredLimit.lean | 5 +- Mathlib/Topology/Connected/PathConnected.lean | 4 +- .../Topology/ContinuousFunction/Bounded.lean | 3 +- .../Topology/ContinuousFunction/Ideals.lean | 2 +- .../ContinuousFunction/StoneWeierstrass.lean | 4 +- .../Topology/UniformSpace/Equicontinuity.lean | 8 --- 97 files changed, 266 insertions(+), 316 deletions(-) diff --git a/Archive/Imo/Imo1994Q1.lean b/Archive/Imo/Imo1994Q1.lean index bc6aa2a85adca..51ca17387c707 100644 --- a/Archive/Imo/Imo1994Q1.lean +++ b/Archive/Imo/Imo1994Q1.lean @@ -53,7 +53,7 @@ open Imo1994Q1 theorem imo1994_q1 (n : ℕ) (m : ℕ) (A : Finset ℕ) (hm : A.card = m + 1) (hrange : ∀ a ∈ A, 0 < a ∧ a ≤ n) - (hadd : ∀ (a) (_ : a ∈ A) (b) (_ : b ∈ A), a + b ≤ n → a + b ∈ A) : + (hadd : ∀ a ∈ A, ∀ b ∈ A, a + b ≤ n → a + b ∈ A) : (m + 1) * (n + 1) ≤ 2 * ∑ x in A, x := by set a := orderEmbOfFin A hm -- We sort the elements of `A` diff --git a/Counterexamples/LinearOrderWithPosMulPosEqZero.lean b/Counterexamples/LinearOrderWithPosMulPosEqZero.lean index ff58359a39436..47722ac7375f8 100644 --- a/Counterexamples/LinearOrderWithPosMulPosEqZero.lean +++ b/Counterexamples/LinearOrderWithPosMulPosEqZero.lean @@ -86,7 +86,7 @@ instance : LinearOrderedCommMonoidWithZero Foo := zero_le_one := by decide } theorem not_mul_pos : ¬∀ {M : Type} [LinearOrderedCommMonoidWithZero M], - ∀ (a b : M) (_ : 0 < a) (_ : 0 < b), 0 < a * b := by + ∀ a b : M, 0 < a → 0 < b → 0 < a * b := by intro h specialize h ε ε (by boom) (by boom) exact (lt_irrefl 0 (h.trans_le (by boom))).elim diff --git a/Mathlib/Algebra/Algebra/Operations.lean b/Mathlib/Algebra/Algebra/Operations.lean index b7415a695316f..4b6ddcd580de4 100644 --- a/Mathlib/Algebra/Algebra/Operations.lean +++ b/Mathlib/Algebra/Algebra/Operations.lean @@ -186,8 +186,8 @@ protected theorem mul_induction_on {C : A → Prop} {r : A} (hr : r ∈ M * N) /-- A dependent version of `mul_induction_on`. -/ @[elab_as_elim] protected theorem mul_induction_on' {C : ∀ r, r ∈ M * N → Prop} - (hm : ∀ m (_ : m ∈ M), ∀ n (_ : n ∈ N), C (m * n) (mul_mem_mul ‹_› ‹_›)) - (ha : ∀ x hx y hy, C x hx → C y hy → C (x + y) (add_mem ‹_› ‹_›)) {r : A} (hr : r ∈ M * N) : + (hm : ∀ m (hm : m ∈ M) n (hn : n ∈ N), C (m * n) (mul_mem_mul hm hn)) + (ha : ∀ x hx y hy, C x hx → C y hy → C (x + y) (add_mem hx hy)) {r : A} (hr : r ∈ M * N) : C r hr := by refine' Exists.elim _ fun (hr : r ∈ M * N) (hc : C r hr) => hc exact diff --git a/Mathlib/Algebra/BigOperators/Basic.lean b/Mathlib/Algebra/BigOperators/Basic.lean index 7162439d9775c..51ccd6cddc5a1 100644 --- a/Mathlib/Algebra/BigOperators/Basic.lean +++ b/Mathlib/Algebra/BigOperators/Basic.lean @@ -2239,7 +2239,7 @@ theorem add_eq_union_right_of_le {x y z : Multiset α} (h : z ≤ y) : theorem finset_sum_eq_sup_iff_disjoint {β : Type*} {i : Finset β} {f : β → Multiset α} : i.sum f = i.sup f ↔ - ∀ (x) (_ : x ∈ i) (y) (_ : y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by + ∀ᵉ (x ∈ i) (y ∈ i), x ≠ y → Multiset.Disjoint (f x) (f y) := by induction' i using Finset.cons_induction_on with z i hz hr · simp only [Finset.not_mem_empty, IsEmpty.forall_iff, imp_true_iff, Finset.sum_empty, Finset.sup_empty, bot_eq_zero, eq_self_iff_true] diff --git a/Mathlib/Algebra/BigOperators/Multiset/Basic.lean b/Mathlib/Algebra/BigOperators/Multiset/Basic.lean index ec9c61a8bfc53..7ad7b4546aed5 100644 --- a/Mathlib/Algebra/BigOperators/Multiset/Basic.lean +++ b/Mathlib/Algebra/BigOperators/Multiset/Basic.lean @@ -133,14 +133,14 @@ theorem prod_replicate (n : ℕ) (a : α) : (replicate n a).prod = a ^ n := by @[to_additive] theorem prod_map_eq_pow_single [DecidableEq ι] (i : ι) - (hf : ∀ (i') (_ : i' ≠ i), i' ∈ m → f i' = 1) : (m.map f).prod = f i ^ m.count i := by + (hf : ∀ i' ≠ i, i' ∈ m → f i' = 1) : (m.map f).prod = f i ^ m.count i := by induction' m using Quotient.inductionOn with l simp [List.prod_map_eq_pow_single i f hf] #align multiset.prod_map_eq_pow_single Multiset.prod_map_eq_pow_single #align multiset.sum_map_eq_nsmul_single Multiset.sum_map_eq_nsmul_single @[to_additive] -theorem prod_eq_pow_single [DecidableEq α] (a : α) (h : ∀ (a') (_ : a' ≠ a), a' ∈ s → a' = 1) : +theorem prod_eq_pow_single [DecidableEq α] (a : α) (h : ∀ a' ≠ a, a' ∈ s → a' = 1) : s.prod = a ^ s.count a := by induction' s using Quotient.inductionOn with l simp [List.prod_eq_pow_single a h] diff --git a/Mathlib/Algebra/BigOperators/Order.lean b/Mathlib/Algebra/BigOperators/Order.lean index 525adafdbbca4..4df228d936023 100644 --- a/Mathlib/Algebra/BigOperators/Order.lean +++ b/Mathlib/Algebra/BigOperators/Order.lean @@ -242,7 +242,7 @@ variable {ι' : Type*} [DecidableEq ι'] -- Porting note: Mathport warning: expanding binder collection (y «expr ∉ » t) @[to_additive sum_fiberwise_le_sum_of_sum_fiber_nonneg] theorem prod_fiberwise_le_prod_of_one_le_prod_fiber' {t : Finset ι'} {g : ι → ι'} {f : ι → N} - (h : ∀ (y) (_ : y ∉ t), (1 : N) ≤ ∏ x in s.filter fun x ↦ g x = y, f x) : + (h : ∀ y ∉ t, (1 : N) ≤ ∏ x in s.filter fun x ↦ g x = y, f x) : (∏ y in t, ∏ x in s.filter fun x ↦ g x = y, f x) ≤ ∏ x in s, f x := calc (∏ y in t, ∏ x in s.filter fun x ↦ g x = y, f x) ≤ @@ -256,7 +256,7 @@ theorem prod_fiberwise_le_prod_of_one_le_prod_fiber' {t : Finset ι'} {g : ι -- Porting note: Mathport warning: expanding binder collection (y «expr ∉ » t) @[to_additive sum_le_sum_fiberwise_of_sum_fiber_nonpos] theorem prod_le_prod_fiberwise_of_prod_fiber_le_one' {t : Finset ι'} {g : ι → ι'} {f : ι → N} - (h : ∀ (y) (_ : y ∉ t), ∏ x in s.filter fun x ↦ g x = y, f x ≤ 1) : + (h : ∀ y ∉ t, ∏ x in s.filter fun x ↦ g x = y, f x ≤ 1) : ∏ x in s, f x ≤ ∏ y in t, ∏ x in s.filter fun x ↦ g x = y, f x := @prod_fiberwise_le_prod_of_one_le_prod_fiber' _ Nᵒᵈ _ _ _ _ _ _ _ h #align finset.prod_le_prod_fiberwise_of_prod_fiber_le_one' Finset.prod_le_prod_fiberwise_of_prod_fiber_le_one' diff --git a/Mathlib/Algebra/GroupPower/Order.lean b/Mathlib/Algebra/GroupPower/Order.lean index b75018c35ff98..efb81ce3e9cac 100644 --- a/Mathlib/Algebra/GroupPower/Order.lean +++ b/Mathlib/Algebra/GroupPower/Order.lean @@ -65,12 +65,12 @@ theorem pow_add_pow_le (hx : 0 ≤ x) (hy : 0 ≤ y) (hn : n ≠ 0) : x ^ n + y exact mul_le_mul_of_nonneg_left (ih (Nat.succ_ne_zero k)) h2 #align pow_add_pow_le pow_add_pow_le -theorem pow_le_one : ∀ (n : ℕ) (_ : 0 ≤ a) (_ : a ≤ 1), a ^ n ≤ 1 +theorem pow_le_one : ∀ n : ℕ, 0 ≤ a → a ≤ 1 → a ^ n ≤ 1 | 0, _, _ => (pow_zero a).le | n + 1, h₀, h₁ => (pow_succ' a n).le.trans (mul_le_one (pow_le_one n h₀ h₁) h₀ h₁) #align pow_le_one pow_le_one -theorem pow_lt_one (h₀ : 0 ≤ a) (h₁ : a < 1) : ∀ {n : ℕ} (_ : n ≠ 0), a ^ n < 1 +theorem pow_lt_one (h₀ : 0 ≤ a) (h₁ : a < 1) : ∀ {n : ℕ}, n ≠ 0 → a ^ n < 1 | 0, h => (h rfl).elim | n + 1, _ => by rw [pow_succ] diff --git a/Mathlib/Algebra/Order/Support.lean b/Mathlib/Algebra/Order/Support.lean index 28ea061c38512..00240d105fb77 100644 --- a/Mathlib/Algebra/Order/Support.lean +++ b/Mathlib/Algebra/Order/Support.lean @@ -91,7 +91,7 @@ lemma le_mulIndicator_apply (hfg : a ∈ s → y ≤ g a) (hf : a ∉ s → y #align set.le_indicator_apply Set.le_indicator_apply @[to_additive] -lemma le_mulIndicator (hfg : ∀ a ∈ s, f a ≤ g a) (hf : ∀ (a) (_ : a ∉ s), f a ≤ 1) : +lemma le_mulIndicator (hfg : ∀ a ∈ s, f a ≤ g a) (hf : ∀ a ∉ s, f a ≤ 1) : f ≤ mulIndicator s g := fun _ ↦ le_mulIndicator_apply (hfg _) (hf _) #align set.le_mul_indicator Set.le_mulIndicator #align set.le_indicator Set.le_indicator @@ -143,7 +143,7 @@ lemma mulIndicator_le_mulIndicator_of_subset (h : s ⊆ t) (hf : ∀ a, 1 ≤ f #align set.indicator_le_indicator_of_subset Set.indicator_le_indicator_of_subset @[to_additive] -lemma mulIndicator_le_self' (hf : ∀ (x) (_ : x ∉ s), 1 ≤ f x) : mulIndicator s f ≤ f := +lemma mulIndicator_le_self' (hf : ∀ x ∉ s, 1 ≤ f x) : mulIndicator s f ≤ f := mulIndicator_le' (fun _ _ ↦ le_rfl) hf #align set.mul_indicator_le_self' Set.mulIndicator_le_self' #align set.indicator_le_self' Set.indicator_le_self' diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean index 0f34e56882c70..7048cabc717c3 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean @@ -37,7 +37,7 @@ theorem exists_primeSpectrum_prod_le (I : Ideal R) : by_cases htop : M = ⊤ · rw [htop] exact ⟨0, le_top⟩ - have lt_add : ∀ (z) (_ : z ∉ M), M < M + span R {z} := by + have lt_add : ∀ z ∉ M, M < M + span R {z} := by intro z hz refine' lt_of_le_of_ne le_sup_left fun m_eq => hz _ rw [m_eq] @@ -81,7 +81,7 @@ theorem exists_primeSpectrum_prod_le_and_ne_bot_of_domain (h_fA : ¬IsField A) { rw [Multiset.map_singleton, Multiset.prod_singleton] exact ⟨le_rfl, h_nzM⟩ obtain ⟨x, hx, y, hy, h_xy⟩ := (Ideal.not_isPrime_iff.mp h_prM).resolve_left h_topM - have lt_add : ∀ (z) (_ : z ∉ M), M < M + span A {z} := by + have lt_add : ∀ z ∉ M, M < M + span A {z} := by intro z hz refine' lt_of_le_of_ne le_sup_left fun m_eq => hz _ rw [m_eq] diff --git a/Mathlib/Analysis/Analytic/Basic.lean b/Mathlib/Analysis/Analytic/Basic.lean index 2aaf73ecbaa09..a274ece0a5b77 100644 --- a/Mathlib/Analysis/Analytic/Basic.lean +++ b/Mathlib/Analysis/Analytic/Basic.lean @@ -802,7 +802,7 @@ ball, the norm of the difference `f y - f z - p 1 (fun _ ↦ y - z)` is bounded `C * (max ‖y - x‖ ‖z - x‖) * ‖y - z‖`. -/ theorem HasFPowerSeriesOnBall.image_sub_sub_deriv_le (hf : HasFPowerSeriesOnBall f p x r) (hr : r' < r) : - ∃ C, ∀ (y) (_ : y ∈ EMetric.ball x r') (z) (_ : z ∈ EMetric.ball x r'), + ∃ C, ∀ᵉ (y ∈ EMetric.ball x r') (z ∈ EMetric.ball x r'), ‖f y - f z - p 1 fun _ => y - z‖ ≤ C * max ‖y - x‖ ‖z - x‖ * ‖y - z‖ := by simpa only [isBigO_principal, mul_assoc, norm_mul, norm_norm, Prod.forall, EMetric.mem_ball, Prod.edist_eq, max_lt_iff, and_imp, @forall_swap (_ < _) E] using diff --git a/Mathlib/Analysis/Calculus/FDeriv/Extend.lean b/Mathlib/Analysis/Calculus/FDeriv/Extend.lean index e2859c8d2b745..dacf4e3860f91 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Extend.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Extend.lean @@ -178,7 +178,7 @@ theorem has_deriv_at_interval_right_endpoint_of_tendsto_deriv {s : Set ℝ} {e : /-- If a real function `f` has a derivative `g` everywhere but at a point, and `f` and `g` are continuous at this point, then `g` is also the derivative of `f` at this point. -/ theorem hasDerivAt_of_hasDerivAt_of_ne {f g : ℝ → E} {x : ℝ} - (f_diff : ∀ (y) (_ : y ≠ x), HasDerivAt f (g y) y) (hf : ContinuousAt f x) + (f_diff : ∀ y ≠ x, HasDerivAt f (g y) y) (hf : ContinuousAt f x) (hg : ContinuousAt g x) : HasDerivAt f (g x) x := by have A : HasDerivWithinAt f (g x) (Ici x) x := by have diff : DifferentiableOn ℝ f (Ioi x) := fun y hy => @@ -212,7 +212,7 @@ theorem hasDerivAt_of_hasDerivAt_of_ne {f g : ℝ → E} {x : ℝ} /-- If a real function `f` has a derivative `g` everywhere but at a point, and `f` and `g` are continuous at this point, then `g` is the derivative of `f` everywhere. -/ theorem hasDerivAt_of_hasDerivAt_of_ne' {f g : ℝ → E} {x : ℝ} - (f_diff : ∀ (y) (_ : y ≠ x), HasDerivAt f (g y) y) (hf : ContinuousAt f x) + (f_diff : ∀ y ≠ x, HasDerivAt f (g y) y) (hf : ContinuousAt f x) (hg : ContinuousAt g x) (y : ℝ) : HasDerivAt f (g y) y := by rcases eq_or_ne y x with (rfl | hne) · exact hasDerivAt_of_hasDerivAt_of_ne f_diff hf hg diff --git a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean index f68b4dd71db0b..6d204ec85a7c8 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean @@ -459,10 +459,8 @@ namespace RightDerivMeasurableAux at scale `r` by the linear map `h ↦ h • L`, up to an error `ε`. We tweak the definition to make sure that this is open on the right. -/ def A (f : ℝ → F) (L : F) (r ε : ℝ) : Set ℝ := - { x | - ∃ r' ∈ Ioc (r / 2) r, - ∀ (y) (_ : y ∈ Icc x (x + r')) (z) (_ : z ∈ Icc x (x + r')), - ‖f z - f y - (z - y) • L‖ ≤ ε * r } + { x | ∃ r' ∈ Ioc (r / 2) r, ∀ᵉ (y ∈ Icc x (x + r')) (z ∈ Icc x (x + r')), + ‖f z - f y - (z - y) • L‖ ≤ ε * r } #align right_deriv_measurable_aux.A RightDerivMeasurableAux.A /-- The set `B f K r s ε` is the set of points `x` around which there exists a vector diff --git a/Mathlib/Analysis/Calculus/Taylor.lean b/Mathlib/Analysis/Calculus/Taylor.lean index bd699753cc52e..770a826763612 100644 --- a/Mathlib/Analysis/Calculus/Taylor.lean +++ b/Mathlib/Analysis/Calculus/Taylor.lean @@ -239,7 +239,7 @@ theorem taylor_mean_remainder {f : ℝ → ℝ} {g g' : ℝ → ℝ} {x x₀ : (gcont : ContinuousOn g (Icc x₀ x)) (gdiff : ∀ x_1 : ℝ, x_1 ∈ Ioo x₀ x → HasDerivAt g (g' x_1) x_1) (g'_ne : ∀ x_1 : ℝ, x_1 ∈ Ioo x₀ x → g' x_1 ≠ 0) : - ∃ (x' : ℝ) (_ : x' ∈ Ioo x₀ x), f x - taylorWithinEval f n (Icc x₀ x) x₀ x = + ∃ x' ∈ Ioo x₀ x, f x - taylorWithinEval f n (Icc x₀ x) x₀ x = ((x - x') ^ n / n ! * (g x - g x₀) / g' x') • iteratedDerivWithin (n + 1) f (Icc x₀ x) x' := by -- We apply the mean value theorem rcases exists_ratio_hasDerivAt_eq_ratio_slope (fun t => taylorWithinEval f n (Icc x₀ x) t x) @@ -265,7 +265,7 @@ derivative. -/ theorem taylor_mean_remainder_lagrange {f : ℝ → ℝ} {x x₀ : ℝ} {n : ℕ} (hx : x₀ < x) (hf : ContDiffOn ℝ n f (Icc x₀ x)) (hf' : DifferentiableOn ℝ (iteratedDerivWithin n f (Icc x₀ x)) (Ioo x₀ x)) : - ∃ (x' : ℝ) (_ : x' ∈ Ioo x₀ x), f x - taylorWithinEval f n (Icc x₀ x) x₀ x = + ∃ x' ∈ Ioo x₀ x, f x - taylorWithinEval f n (Icc x₀ x) x₀ x = iteratedDerivWithin (n + 1) f (Icc x₀ x) x' * (x - x₀) ^ (n + 1) / (n + 1)! := by have gcont : ContinuousOn (fun t : ℝ => (x - t) ^ (n + 1)) (Icc x₀ x) := by refine' Continuous.continuousOn _ @@ -297,7 +297,7 @@ derivative. -/ theorem taylor_mean_remainder_cauchy {f : ℝ → ℝ} {x x₀ : ℝ} {n : ℕ} (hx : x₀ < x) (hf : ContDiffOn ℝ n f (Icc x₀ x)) (hf' : DifferentiableOn ℝ (iteratedDerivWithin n f (Icc x₀ x)) (Ioo x₀ x)) : - ∃ (x' : ℝ) (_ : x' ∈ Ioo x₀ x), f x - taylorWithinEval f n (Icc x₀ x) x₀ x = + ∃ x' ∈ Ioo x₀ x, f x - taylorWithinEval f n (Icc x₀ x) x₀ x = iteratedDerivWithin (n + 1) f (Icc x₀ x) x' * (x - x') ^ n / n ! * (x - x₀) := by have gcont : ContinuousOn id (Icc x₀ x) := Continuous.continuousOn (by continuity) have gdiff : ∀ x_1 : ℝ, x_1 ∈ Ioo x₀ x → HasDerivAt id ((fun _ : ℝ => (1 : ℝ)) x_1) x_1 := @@ -327,7 +327,7 @@ theorem taylor_mean_remainder_bound {f : ℝ → E} {a b C x : ℝ} {n : ℕ} (h hf.differentiableOn_iteratedDerivWithin (WithTop.coe_lt_coe.mpr n.lt_succ_self) (uniqueDiffOn_Icc h) -- We can uniformly bound the derivative of the Taylor polynomial - have h' : ∀ (y : ℝ) (_ : y ∈ Ico a x), + have h' : ∀ y ∈ Ico a x, ‖((n ! : ℝ)⁻¹ * (x - y) ^ n) • iteratedDerivWithin (n + 1) f (Icc a b) y‖ ≤ (n ! : ℝ)⁻¹ * |x - a| ^ n * C := by rintro y ⟨hay, hyx⟩ diff --git a/Mathlib/Analysis/ConstantSpeed.lean b/Mathlib/Analysis/ConstantSpeed.lean index 9732aca5e18ba..263fe13e875a2 100644 --- a/Mathlib/Analysis/ConstantSpeed.lean +++ b/Mathlib/Analysis/ConstantSpeed.lean @@ -155,7 +155,7 @@ theorem HasConstantSpeedOnWith.Icc_Icc {x y z : ℝ} (hfs : HasConstantSpeedOnWi #align has_constant_speed_on_with.Icc_Icc HasConstantSpeedOnWith.Icc_Icc theorem hasConstantSpeedOnWith_zero_iff : - HasConstantSpeedOnWith f s 0 ↔ ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), edist (f x) (f y) = 0 := by + HasConstantSpeedOnWith f s 0 ↔ ∀ᵉ (x ∈ s) (y ∈ s), edist (f x) (f y) = 0 := by dsimp [HasConstantSpeedOnWith] simp only [zero_mul, ENNReal.ofReal_zero, ← eVariationOn.eq_zero_iff] constructor diff --git a/Mathlib/Analysis/Convex/Caratheodory.lean b/Mathlib/Analysis/Convex/Caratheodory.lean index c925952710fd8..ae7ed055806d1 100644 --- a/Mathlib/Analysis/Convex/Caratheodory.lean +++ b/Mathlib/Analysis/Convex/Caratheodory.lean @@ -166,8 +166,8 @@ theorem convexHull_eq_union : convexHull 𝕜 s = /-- A more explicit version of `convexHull_eq_union`. -/ theorem eq_pos_convex_span_of_mem_convexHull {x : E} (hx : x ∈ convexHull 𝕜 s) : ∃ (ι : Sort (u + 1)) (_ : Fintype ι), - ∃ (z : ι → E) (w : ι → 𝕜) (_ : Set.range z ⊆ s) (_ : AffineIndependent 𝕜 z) - (_ : ∀ i, 0 < w i), ∑ i, w i = 1 ∧ ∑ i, w i • z i = x := by + ∃ (z : ι → E) (w : ι → 𝕜), Set.range z ⊆ s ∧ AffineIndependent 𝕜 z ∧ (∀ i, 0 < w i) ∧ + ∑ i, w i = 1 ∧ ∑ i, w i • z i = x := by rw [convexHull_eq_union] at hx simp only [exists_prop, Set.mem_iUnion] at hx obtain ⟨t, ht₁, ht₂, ht₃⟩ := hx diff --git a/Mathlib/Analysis/Convex/Combination.lean b/Mathlib/Analysis/Convex/Combination.lean index fdbee74f4f2bb..0c4700816b842 100644 --- a/Mathlib/Analysis/Convex/Combination.lean +++ b/Mathlib/Analysis/Convex/Combination.lean @@ -290,8 +290,8 @@ theorem Finset.centroid_mem_convexHull (s : Finset E) (hs : s.Nonempty) : #align finset.centroid_mem_convex_hull Finset.centroid_mem_convexHull theorem convexHull_range_eq_exists_affineCombination (v : ι → E) : convexHull R (range v) = - { x | ∃ (s : Finset ι) (w : ι → R) (_ : ∀ i ∈ s, 0 ≤ w i) (_ : s.sum w = 1), - s.affineCombination R v w = x } := by + { x | ∃ (s : Finset ι) (w : ι → R), (∀ i ∈ s, 0 ≤ w i) ∧ s.sum w = 1 ∧ + s.affineCombination R v w = x } := by refine' Subset.antisymm (convexHull_min _ _) _ · intro x hx obtain ⟨i, hi⟩ := Set.mem_range.mp hx @@ -326,8 +326,8 @@ For universe reasons, you shouldn't use this lemma to prove that a given center to the convex hull. Use convexity of the convex hull instead. -/ theorem convexHull_eq (s : Set E) : convexHull R s = - { x : E | ∃ (ι : Type) (t : Finset ι) (w : ι → R) (z : ι → E) (_ : ∀ i ∈ t, 0 ≤ w i) - (_ : ∑ i in t, w i = 1) (_ : ∀ i ∈ t, z i ∈ s), t.centerMass w z = x } := by + { x : E | ∃ (ι : Type) (t : Finset ι) (w : ι → R) (z : ι → E), (∀ i ∈ t, 0 ≤ w i) ∧ + ∑ i in t, w i = 1 ∧ (∀ i ∈ t, z i ∈ s) ∧ t.centerMass w z = x } := by refine' Subset.antisymm (convexHull_min _ _) _ · intro x hx use PUnit, {PUnit.unit}, fun _ => 1, fun _ => x, fun _ _ => zero_le_one, sum_singleton _ _, @@ -350,8 +350,7 @@ theorem convexHull_eq (s : Set E) : convexHull R s = #align convex_hull_eq convexHull_eq theorem Finset.convexHull_eq (s : Finset E) : convexHull R ↑s = - { x : E | ∃ (w : E → R) (_ : ∀ y ∈ s, 0 ≤ w y) (_ : ∑ y in s, w y = 1), - s.centerMass w id = x } := by + { x : E | ∃ w : E → R, (∀ y ∈ s, 0 ≤ w y) ∧ ∑ y in s, w y = 1 ∧ s.centerMass w id = x } := by refine' Set.Subset.antisymm (convexHull_min _ _) _ · intro x hx rw [Finset.mem_coe] at hx @@ -372,13 +371,13 @@ theorem Finset.convexHull_eq (s : Finset E) : convexHull R ↑s = #align finset.convex_hull_eq Finset.convexHull_eq theorem Finset.mem_convexHull {s : Finset E} {x : E} : x ∈ convexHull R (s : Set E) ↔ - ∃ (w : E → R) (_ : ∀ y ∈ s, 0 ≤ w y) (_ : ∑ y in s, w y = 1), s.centerMass w id = x := by + ∃ w : E → R, (∀ y ∈ s, 0 ≤ w y) ∧ ∑ y in s, w y = 1 ∧ s.centerMass w id = x := by rw [Finset.convexHull_eq, Set.mem_setOf_eq] #align finset.mem_convex_hull Finset.mem_convexHull theorem Set.Finite.convexHull_eq {s : Set E} (hs : s.Finite) : convexHull R s = - { x : E | ∃ (w : E → R) (_ : ∀ y ∈ s, 0 ≤ w y) (_ : ∑ y in hs.toFinset, w y = 1), - hs.toFinset.centerMass w id = x } := by + { x : E | ∃ w : E → R, (∀ y ∈ s, 0 ≤ w y) ∧ ∑ y in hs.toFinset, w y = 1 ∧ + hs.toFinset.centerMass w id = x } := by simpa only [Set.Finite.coe_toFinset, Set.Finite.mem_toFinset, exists_prop] using hs.toFinset.convexHull_eq #align set.finite.convex_hull_eq Set.Finite.convexHull_eq diff --git a/Mathlib/Analysis/Convex/Extreme.lean b/Mathlib/Analysis/Convex/Extreme.lean index 66b12335c033e..cfe46e0dc24a4 100644 --- a/Mathlib/Analysis/Convex/Extreme.lean +++ b/Mathlib/Analysis/Convex/Extreme.lean @@ -127,7 +127,7 @@ theorem isExtreme_sInter {F : Set (Set E)} (hF : F.Nonempty) (hAF : ∀ B ∈ F, #align is_extreme_sInter isExtreme_sInter theorem mem_extremePoints : x ∈ A.extremePoints 𝕜 ↔ - x ∈ A ∧ ∀ (x₁) (_ : x₁ ∈ A) (x₂) (_ : x₂ ∈ A), x ∈ openSegment 𝕜 x₁ x₂ → x₁ = x ∧ x₂ = x := + x ∈ A ∧ ∀ᵉ (x₁ ∈ A) (x₂ ∈ A), x ∈ openSegment 𝕜 x₁ x₂ → x₁ = x ∧ x₂ = x := Iff.rfl #align mem_extreme_points mem_extremePoints @@ -256,7 +256,7 @@ variable [DenselyOrdered 𝕜] [NoZeroSMulDivisors 𝕜 E] {A B : Set E} {x : E} /-- A useful restatement using `segment`: `x` is an extreme point iff the only (closed) segments that contain it are those with `x` as one of their endpoints. -/ theorem mem_extremePoints_iff_forall_segment : x ∈ A.extremePoints 𝕜 ↔ - x ∈ A ∧ ∀ (x₁) (_ : x₁ ∈ A) (x₂) (_ : x₂ ∈ A), x ∈ segment 𝕜 x₁ x₂ → x₁ = x ∨ x₂ = x := by + x ∈ A ∧ ∀ᵉ (x₁ ∈ A) (x₂ ∈ A), x ∈ segment 𝕜 x₁ x₂ → x₁ = x ∨ x₂ = x := by refine' and_congr_right fun hxA ↦ forall₄_congr fun x₁ h₁ x₂ h₂ ↦ _ constructor · rw [← insert_endpoints_openSegment] diff --git a/Mathlib/Analysis/Convex/Segment.lean b/Mathlib/Analysis/Convex/Segment.lean index d239ef0cefc71..860810871d8dc 100644 --- a/Mathlib/Analysis/Convex/Segment.lean +++ b/Mathlib/Analysis/Convex/Segment.lean @@ -48,13 +48,13 @@ variable (𝕜) [SMul 𝕜 E] {s : Set E} {x y : E} /-- Segments in a vector space. -/ def segment (x y : E) : Set E := - { z : E | ∃ (a b : 𝕜) (_ : 0 ≤ a) (_ : 0 ≤ b) (_ : a + b = 1), a • x + b • y = z } + { z : E | ∃ a b : 𝕜, 0 ≤ a ∧ 0 ≤ b ∧ a + b = 1 ∧ a • x + b • y = z } #align segment segment /-- Open segment in a vector space. Note that `openSegment 𝕜 x x = {x}` instead of being `∅` when the base semiring has some element between `0` and `1`. -/ def openSegment (x y : E) : Set E := - { z : E | ∃ (a b : 𝕜) (_ : 0 < a) (_ : 0 < b) (_ : a + b = 1), a • x + b • y = z } + { z : E | ∃ a b : 𝕜, 0 < a ∧ 0 < b ∧ a + b = 1 ∧ a • x + b • y = z } #align open_segment openSegment scoped[Convex] notation (priority := high) "[" x "-[" 𝕜 "]" y "]" => segment 𝕜 x y @@ -561,7 +561,6 @@ theorem segment_eq_uIcc (x y : 𝕜) : [x -[𝕜] y] = uIcc x y := theorem Convex.mem_Icc (h : x ≤ y) : z ∈ Icc x y ↔ ∃ a b, 0 ≤ a ∧ 0 ≤ b ∧ a + b = 1 ∧ a * x + b * y = z := by rw [← segment_eq_Icc h] - simp_rw [← exists_prop] rfl #align convex.mem_Icc Convex.mem_Icc @@ -570,7 +569,6 @@ theorem Convex.mem_Icc (h : x ≤ y) : theorem Convex.mem_Ioo (h : x < y) : z ∈ Ioo x y ↔ ∃ a b, 0 < a ∧ 0 < b ∧ a + b = 1 ∧ a * x + b * y = z := by rw [← openSegment_eq_Ioo h] - simp_rw [← exists_prop] rfl #align convex.mem_Ioo Convex.mem_Ioo @@ -629,39 +627,31 @@ theorem openSegment_subset (x y : E × F) : theorem image_mk_segment_left (x₁ x₂ : E) (y : F) : (fun x => (x, y)) '' [x₁ -[𝕜] x₂] = [(x₁, y) -[𝕜] (x₂, y)] := by - ext ⟨x', y'⟩ - simp_rw [Set.mem_image, segment, Set.mem_setOf, Prod.smul_mk, Prod.mk_add_mk, Prod.mk.inj_iff, ← - exists_and_right, @exists_comm E, exists_eq_left'] - refine' exists₅_congr fun a b ha hb hab => _ - rw [Convex.combo_self hab] + rw [segment_eq_image₂, segment_eq_image₂, image_image] + refine EqOn.image_eq fun a ha ↦ ?_ + simp [Convex.combo_self ha.2.2] #align prod.image_mk_segment_left Prod.image_mk_segment_left theorem image_mk_segment_right (x : E) (y₁ y₂ : F) : (fun y => (x, y)) '' [y₁ -[𝕜] y₂] = [(x, y₁) -[𝕜] (x, y₂)] := by - ext ⟨x', y'⟩ - simp_rw [Set.mem_image, segment, Set.mem_setOf, Prod.smul_mk, Prod.mk_add_mk, Prod.mk.inj_iff, ← - exists_and_right, @exists_comm F, exists_eq_left'] - refine' exists₅_congr fun a b ha hb hab => _ - rw [Convex.combo_self hab] + rw [segment_eq_image₂, segment_eq_image₂, image_image] + refine EqOn.image_eq fun a ha ↦ ?_ + simp [Convex.combo_self ha.2.2] #align prod.image_mk_segment_right Prod.image_mk_segment_right theorem image_mk_openSegment_left (x₁ x₂ : E) (y : F) : (fun x => (x, y)) '' openSegment 𝕜 x₁ x₂ = openSegment 𝕜 (x₁, y) (x₂, y) := by - ext ⟨x', y'⟩ - simp_rw [Set.mem_image, openSegment, Set.mem_setOf, Prod.smul_mk, Prod.mk_add_mk, Prod.mk.inj_iff, - ← exists_and_right, @exists_comm E, exists_eq_left'] - refine' exists₅_congr fun a b ha hb hab => _ - rw [Convex.combo_self hab] + rw [openSegment_eq_image₂, openSegment_eq_image₂, image_image] + refine EqOn.image_eq fun a ha ↦ ?_ + simp [Convex.combo_self ha.2.2] #align prod.image_mk_open_segment_left Prod.image_mk_openSegment_left @[simp] theorem image_mk_openSegment_right (x : E) (y₁ y₂ : F) : (fun y => (x, y)) '' openSegment 𝕜 y₁ y₂ = openSegment 𝕜 (x, y₁) (x, y₂) := by - ext ⟨x', y'⟩ - simp_rw [Set.mem_image, openSegment, Set.mem_setOf, Prod.smul_mk, Prod.mk_add_mk, Prod.mk.inj_iff, - ← exists_and_right, @exists_comm F, exists_eq_left'] - refine' exists₅_congr fun a b ha hb hab => _ - rw [Convex.combo_self hab] + rw [openSegment_eq_image₂, openSegment_eq_image₂, image_image] + refine EqOn.image_eq fun a ha ↦ ?_ + simp [Convex.combo_self ha.2.2] #align prod.image_mk_open_segment_right Prod.image_mk_openSegment_right end Prod @@ -685,20 +675,16 @@ variable [DecidableEq ι] theorem image_update_segment (i : ι) (x₁ x₂ : π i) (y : ∀ i, π i) : update y i '' [x₁ -[𝕜] x₂] = [update y i x₁ -[𝕜] update y i x₂] := by - ext z - simp_rw [Set.mem_image, segment, Set.mem_setOf, ← update_smul, ← update_add, update_eq_iff, ← - exists_and_right, @exists_comm (π i), exists_eq_left'] - refine' exists₅_congr fun a b ha hb hab => _ - rw [Convex.combo_self hab] + rw [segment_eq_image₂, segment_eq_image₂, image_image] + refine EqOn.image_eq fun a ha ↦ ?_ + simp only [← update_smul, ← update_add, Convex.combo_self ha.2.2] #align pi.image_update_segment Pi.image_update_segment theorem image_update_openSegment (i : ι) (x₁ x₂ : π i) (y : ∀ i, π i) : update y i '' openSegment 𝕜 x₁ x₂ = openSegment 𝕜 (update y i x₁) (update y i x₂) := by - ext z - simp_rw [Set.mem_image, openSegment, Set.mem_setOf, ← update_smul, ← update_add, update_eq_iff, ← - exists_and_right, @exists_comm (π i), exists_eq_left'] - refine' exists₅_congr fun a b ha hb hab => _ - rw [Convex.combo_self hab] + rw [openSegment_eq_image₂, openSegment_eq_image₂, image_image] + refine EqOn.image_eq fun a ha ↦ ?_ + simp only [← update_smul, ← update_add, Convex.combo_self ha.2.2] #align pi.image_update_open_segment Pi.image_update_openSegment end Pi diff --git a/Mathlib/Analysis/Convex/Side.lean b/Mathlib/Analysis/Convex/Side.lean index dab41b1bd1647..02b4eb7b3b161 100644 --- a/Mathlib/Analysis/Convex/Side.lean +++ b/Mathlib/Analysis/Convex/Side.lean @@ -42,7 +42,7 @@ variable [AddCommGroup V'] [Module R V'] [AddTorsor V' P'] /-- The points `x` and `y` are weakly on the same side of `s`. -/ def WSameSide (s : AffineSubspace R P) (x y : P) : Prop := - ∃ (p₁ : _) (_ : p₁ ∈ s) (p₂ : _) (_ : p₂ ∈ s), SameRay R (x -ᵥ p₁) (y -ᵥ p₂) + ∃ᵉ (p₁ ∈ s) (p₂ ∈ s), SameRay R (x -ᵥ p₁) (y -ᵥ p₂) #align affine_subspace.w_same_side AffineSubspace.WSameSide /-- The points `x` and `y` are strictly on the same side of `s`. -/ @@ -52,7 +52,7 @@ def SSameSide (s : AffineSubspace R P) (x y : P) : Prop := /-- The points `x` and `y` are weakly on opposite sides of `s`. -/ def WOppSide (s : AffineSubspace R P) (x y : P) : Prop := - ∃ (p₁ : _) (_ : p₁ ∈ s) (p₂ : _) (_ : p₂ ∈ s), SameRay R (x -ᵥ p₁) (p₂ -ᵥ y) + ∃ᵉ (p₁ ∈ s) (p₂ ∈ s), SameRay R (x -ᵥ p₁) (p₂ -ᵥ y) #align affine_subspace.w_opp_side AffineSubspace.WOppSide /-- The points `x` and `y` are strictly on opposite sides of `s`. -/ @@ -140,22 +140,22 @@ theorem _root_.AffineEquiv.sOppSide_map_iff {s : AffineSubspace R P} {x y : P} ( theorem WSameSide.nonempty {s : AffineSubspace R P} {x y : P} (h : s.WSameSide x y) : (s : Set P).Nonempty := - ⟨h.choose, h.choose_spec.choose⟩ + ⟨h.choose, h.choose_spec.left⟩ #align affine_subspace.w_same_side.nonempty AffineSubspace.WSameSide.nonempty theorem SSameSide.nonempty {s : AffineSubspace R P} {x y : P} (h : s.SSameSide x y) : (s : Set P).Nonempty := - ⟨h.1.choose, h.1.choose_spec.choose⟩ + ⟨h.1.choose, h.1.choose_spec.left⟩ #align affine_subspace.s_same_side.nonempty AffineSubspace.SSameSide.nonempty theorem WOppSide.nonempty {s : AffineSubspace R P} {x y : P} (h : s.WOppSide x y) : (s : Set P).Nonempty := - ⟨h.choose, h.choose_spec.choose⟩ + ⟨h.choose, h.choose_spec.left⟩ #align affine_subspace.w_opp_side.nonempty AffineSubspace.WOppSide.nonempty theorem SOppSide.nonempty {s : AffineSubspace R P} {x y : P} (h : s.SOppSide x y) : (s : Set P).Nonempty := - ⟨h.1.choose, h.1.choose_spec.choose⟩ + ⟨h.1.choose, h.1.choose_spec.left⟩ #align affine_subspace.s_opp_side.nonempty AffineSubspace.SOppSide.nonempty theorem SSameSide.wSameSide {s : AffineSubspace R P} {x y : P} (h : s.SSameSide x y) : diff --git a/Mathlib/Analysis/Convex/SimplicialComplex/Basic.lean b/Mathlib/Analysis/Convex/SimplicialComplex/Basic.lean index 8e9400a8bcbf4..b452cde9bab88 100644 --- a/Mathlib/Analysis/Convex/SimplicialComplex/Basic.lean +++ b/Mathlib/Analysis/Convex/SimplicialComplex/Basic.lean @@ -79,8 +79,8 @@ def space (K : SimplicialComplex 𝕜 E) : Set E := #align geometry.simplicial_complex.space Geometry.SimplicialComplex.space -- Porting note: Expanded `∃ s ∈ K.faces` to get the type to match more closely with Lean 3 -theorem mem_space_iff : x ∈ K.space ↔ ∃ (s : _) (_ : s ∈ K.faces), x ∈ convexHull 𝕜 (s : Set E) := - mem_iUnion₂ +theorem mem_space_iff : x ∈ K.space ↔ ∃ s ∈ K.faces, x ∈ convexHull 𝕜 (s : Set E) := by + simp [space] #align geometry.simplicial_complex.mem_space_iff Geometry.SimplicialComplex.mem_space_iff -- Porting note: Original proof was `:= subset_biUnion_of_mem hs` @@ -118,8 +118,8 @@ theorem disjoint_or_exists_inter_eq_convexHull (hs : s ∈ K.faces) (ht : t ∈ /-- Construct a simplicial complex by removing the empty face for you. -/ @[simps] def ofErase (faces : Set (Finset E)) (indep : ∀ s ∈ faces, AffineIndependent 𝕜 ((↑) : s → E)) - (down_closed : ∀ s ∈ faces, ∀ (t) (_ : t ⊆ s), t ∈ faces) - (inter_subset_convexHull : ∀ (s) (_ : s ∈ faces) (t) (_ : t ∈ faces), + (down_closed : ∀ s ∈ faces, ∀ t ⊆ s, t ∈ faces) + (inter_subset_convexHull : ∀ᵉ (s ∈ faces) (t ∈ faces), convexHull 𝕜 ↑s ∩ convexHull 𝕜 ↑t ⊆ convexHull 𝕜 (s ∩ t : Set E)) : SimplicialComplex 𝕜 E where faces := faces \ {∅} diff --git a/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean b/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean index 9c2ca6088ebb9..0bb4d16213d5f 100644 --- a/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean +++ b/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean @@ -105,8 +105,8 @@ theorem mem_balancedCoreAux_iff : x ∈ balancedCoreAux 𝕜 s ↔ ∀ r : 𝕜, mem_iInter₂ #align mem_balanced_core_aux_iff mem_balancedCoreAux_iff -theorem mem_balancedHull_iff : x ∈ balancedHull 𝕜 s ↔ ∃ (r : 𝕜) (_ : ‖r‖ ≤ 1), x ∈ r • s := - mem_iUnion₂ +theorem mem_balancedHull_iff : x ∈ balancedHull 𝕜 s ↔ ∃ r : 𝕜, ‖r‖ ≤ 1 ∧ x ∈ r • s := by + simp [balancedHull] #align mem_balanced_hull_iff mem_balancedHull_iff /-- The balanced hull of `s` is minimal in the sense that it is contained in any balanced superset @@ -202,7 +202,7 @@ theorem balancedCore_eq_iInter (hs : (0 : E) ∈ s) : exact balancedCore_subset_balancedCoreAux (balancedCore_zero_mem hs) #align balanced_core_eq_Inter balancedCore_eq_iInter -theorem subset_balancedCore (ht : (0 : E) ∈ t) (hst : ∀ (a : 𝕜) (_ : ‖a‖ ≤ 1), a • s ⊆ t) : +theorem subset_balancedCore (ht : (0 : E) ∈ t) (hst : ∀ a : 𝕜, ‖a‖ ≤ 1 → a • s ⊆ t) : s ⊆ balancedCore 𝕜 t := by rw [balancedCore_eq_iInter ht] refine' subset_iInter₂ fun a ha => _ diff --git a/Mathlib/Analysis/LocallyConvex/Bounded.lean b/Mathlib/Analysis/LocallyConvex/Bounded.lean index 54236bc00f595..30d5f00d87141 100644 --- a/Mathlib/Analysis/LocallyConvex/Bounded.lean +++ b/Mathlib/Analysis/LocallyConvex/Bounded.lean @@ -79,7 +79,7 @@ theorem isVonNBounded_iff (s : Set E) : IsVonNBounded 𝕜 s ↔ ∀ V ∈ 𝓝 #align bornology.is_vonN_bounded_iff Bornology.isVonNBounded_iff theorem _root_.Filter.HasBasis.isVonNBounded_basis_iff {q : ι → Prop} {s : ι → Set E} {A : Set E} - (h : (𝓝 (0 : E)).HasBasis q s) : IsVonNBounded 𝕜 A ↔ ∀ (i) (_ : q i), Absorbs 𝕜 (s i) A := by + (h : (𝓝 (0 : E)).HasBasis q s) : IsVonNBounded 𝕜 A ↔ ∀ i, q i → Absorbs 𝕜 (s i) A := by refine' ⟨fun hA i hi => hA (h.mem_of_mem hi), fun hA V hV => _⟩ rcases h.mem_iff.mp hV with ⟨i, hi, hV⟩ exact (hA i hi).mono_left hV @@ -295,12 +295,12 @@ theorem isVonNBounded_iff (s : Set E) : Bornology.IsVonNBounded 𝕜 s ↔ Borno #align normed_space.is_vonN_bounded_iff NormedSpace.isVonNBounded_iff theorem isVonNBounded_iff' (s : Set E) : - Bornology.IsVonNBounded 𝕜 s ↔ ∃ r : ℝ, ∀ (x : E) (_ : x ∈ s), ‖x‖ ≤ r := by + Bornology.IsVonNBounded 𝕜 s ↔ ∃ r : ℝ, ∀ x ∈ s, ‖x‖ ≤ r := by rw [NormedSpace.isVonNBounded_iff, isBounded_iff_forall_norm_le] #align normed_space.is_vonN_bounded_iff' NormedSpace.isVonNBounded_iff' theorem image_isVonNBounded_iff (f : E' → E) (s : Set E') : - Bornology.IsVonNBounded 𝕜 (f '' s) ↔ ∃ r : ℝ, ∀ (x : E') (_ : x ∈ s), ‖f x‖ ≤ r := by + Bornology.IsVonNBounded 𝕜 (f '' s) ↔ ∃ r : ℝ, ∀ x ∈ s, ‖f x‖ ≤ r := by simp_rw [isVonNBounded_iff', Set.ball_image_iff] #align normed_space.image_is_vonN_bounded_iff NormedSpace.image_isVonNBounded_iff diff --git a/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean b/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean index 846052ea3c1c6..307f82fe49f7c 100644 --- a/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean +++ b/Mathlib/Analysis/LocallyConvex/ContinuousOfBounded.lean @@ -44,7 +44,7 @@ variable [NontriviallyNormedField 𝕜] [Module 𝕜 E] [Module 𝕜 F] [Continu /-- Construct a continuous linear map from a linear map `f : E →ₗ[𝕜] F` and the existence of a neighborhood of zero that gets mapped into a bounded set in `F`. -/ def LinearMap.clmOfExistsBoundedImage (f : E →ₗ[𝕜] F) - (h : ∃ (V : Set E) (_ : V ∈ 𝓝 (0 : E)), Bornology.IsVonNBounded 𝕜 (f '' V)) : E →L[𝕜] F := + (h : ∃ V ∈ 𝓝 (0 : E), Bornology.IsVonNBounded 𝕜 (f '' V)) : E →L[𝕜] F := ⟨f, by -- It suffices to show that `f` is continuous at `0`. refine' continuous_of_continuousAt_zero f _ @@ -73,14 +73,14 @@ def LinearMap.clmOfExistsBoundedImage (f : E →ₗ[𝕜] F) #align linear_map.clm_of_exists_bounded_image LinearMap.clmOfExistsBoundedImage theorem LinearMap.clmOfExistsBoundedImage_coe {f : E →ₗ[𝕜] F} - {h : ∃ (V : Set E) (_ : V ∈ 𝓝 (0 : E)), Bornology.IsVonNBounded 𝕜 (f '' V)} : + {h : ∃ V ∈ 𝓝 (0 : E), Bornology.IsVonNBounded 𝕜 (f '' V)} : (f.clmOfExistsBoundedImage h : E →ₗ[𝕜] F) = f := rfl #align linear_map.clm_of_exists_bounded_image_coe LinearMap.clmOfExistsBoundedImage_coe @[simp] theorem LinearMap.clmOfExistsBoundedImage_apply {f : E →ₗ[𝕜] F} - {h : ∃ (V : Set E) (_ : V ∈ 𝓝 (0 : E)), Bornology.IsVonNBounded 𝕜 (f '' V)} {x : E} : + {h : ∃ V ∈ 𝓝 (0 : E), Bornology.IsVonNBounded 𝕜 (f '' V)} {x : E} : f.clmOfExistsBoundedImage h x = f x := rfl #align linear_map.clm_of_exists_bounded_image_apply LinearMap.clmOfExistsBoundedImage_apply @@ -100,7 +100,7 @@ variable [IsROrC 𝕜'] [Module 𝕜' F] [ContinuousSMul 𝕜' F] variable {σ : 𝕜 →+* 𝕜'} theorem LinearMap.continuousAt_zero_of_locally_bounded (f : E →ₛₗ[σ] F) - (hf : ∀ (s : Set E) (_ : IsVonNBounded 𝕜 s), IsVonNBounded 𝕜' (f '' s)) : ContinuousAt f 0 := by + (hf : ∀ s, IsVonNBounded 𝕜 s → IsVonNBounded 𝕜' (f '' s)) : ContinuousAt f 0 := by -- Assume that f is not continuous at 0 by_contra h -- We use a decreasing balanced basis for 0 : E and a balanced basis for 0 : F @@ -174,7 +174,7 @@ theorem LinearMap.continuousAt_zero_of_locally_bounded (f : E →ₛₗ[σ] F) /-- If `E` is first countable, then every locally bounded linear map `E →ₛₗ[σ] F` is continuous. -/ theorem LinearMap.continuous_of_locally_bounded [UniformAddGroup F] (f : E →ₛₗ[σ] F) - (hf : ∀ (s : Set E) (_ : IsVonNBounded 𝕜 s), IsVonNBounded 𝕜' (f '' s)) : Continuous f := + (hf : ∀ s, IsVonNBounded 𝕜 s → IsVonNBounded 𝕜' (f '' s)) : Continuous f := (uniformContinuous_of_continuousAt_zero f <| f.continuousAt_zero_of_locally_bounded hf).continuous #align linear_map.continuous_of_locally_bounded LinearMap.continuous_of_locally_bounded diff --git a/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean b/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean index 25b8fa02ce467..43d2de5b7bce1 100644 --- a/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean +++ b/Mathlib/Analysis/LocallyConvex/WithSeminorms.lean @@ -78,8 +78,8 @@ def basisSets (p : SeminormFamily 𝕜 E ι) : Set (Set E) := variable (p : SeminormFamily 𝕜 E ι) theorem basisSets_iff {U : Set E} : - U ∈ p.basisSets ↔ ∃ (i : Finset ι) (r : _) (_ : 0 < r), U = ball (i.sup p) 0 r := by - simp only [basisSets, mem_iUnion, mem_singleton_iff] + U ∈ p.basisSets ↔ ∃ (i : Finset ι) (r : ℝ), 0 < r ∧ U = ball (i.sup p) 0 r := by + simp only [basisSets, mem_iUnion, exists_prop, mem_singleton_iff] #align seminorm_family.basis_sets_iff SeminormFamily.basisSets_iff theorem basisSets_mem (i : Finset ι) {r : ℝ} (hr : 0 < r) : (i.sup p).ball 0 r ∈ p.basisSets := diff --git a/Mathlib/Analysis/NormedSpace/AddTorsorBases.lean b/Mathlib/Analysis/NormedSpace/AddTorsorBases.lean index dd7d76256f9a6..1448306a2e444 100644 --- a/Mathlib/Analysis/NormedSpace/AddTorsorBases.lean +++ b/Mathlib/Analysis/NormedSpace/AddTorsorBases.lean @@ -100,7 +100,7 @@ theorem IsOpen.exists_between_affineIndependent_span_eq_top {s u : Set P} (hu : rw [Metric.mem_closedBall, lineMap_apply, dist_vadd_left, norm_smul, Real.norm_eq_abs, dist_eq_norm_vsub V y q, abs_div, abs_of_pos ε0, abs_of_nonneg (norm_nonneg _), div_mul_comm] exact mul_le_of_le_one_left ε0.le (div_self_le_one _) - have hεyq : ∀ (y) (_ : y ∉ s), ε / dist y q ≠ 0 := fun y hy => + have hεyq : ∀ y ∉ s, ε / dist y q ≠ 0 := fun y hy => div_ne_zero ε0.ne' (dist_ne_zero.2 (ne_of_mem_of_not_mem hq hy).symm) classical let w : t → ℝˣ := fun p => if hp : (p : P) ∈ s then 1 else Units.mk0 _ (hεyq (↑p) hp) diff --git a/Mathlib/Analysis/NormedSpace/LpEquiv.lean b/Mathlib/Analysis/NormedSpace/LpEquiv.lean index f6ea5c4a383a2..a2c1cf290307b 100644 --- a/Mathlib/Analysis/NormedSpace/LpEquiv.lean +++ b/Mathlib/Analysis/NormedSpace/LpEquiv.lean @@ -141,7 +141,7 @@ variable [NormedAddCommGroup E] [NormedSpace 𝕜 E] [NonUnitalNormedRing R] section NormedAddCommGroup -/-- The canonical map between `lp (λ (_ : α), E) ∞` and `α →ᵇ E` as an `AddEquiv`. -/ +/-- The canonical map between `lp (fun _ : α ↦ E) ∞` and `α →ᵇ E` as an `AddEquiv`. -/ noncomputable def AddEquiv.lpBcf : lp (fun _ : α => E) ∞ ≃+ (α →ᵇ E) where toFun f := ofNormedAddCommGroupDiscrete f ‖f‖ <| le_ciSup (memℓp_infty_iff.mp f.prop) invFun f := ⟨⇑f, f.bddAbove_range_norm_comp⟩ @@ -164,7 +164,7 @@ variable (E) annotating with `(E := E)` everywhere, so we just make it explicit. This file has no dependencies. -/ -/-- The canonical map between `lp (λ (_ : α), E) ∞` and `α →ᵇ E` as a `LinearIsometryEquiv`. -/ +/-- The canonical map between `lp (fun _ : α ↦ E) ∞` and `α →ᵇ E` as a `LinearIsometryEquiv`. -/ noncomputable def lpBcfₗᵢ : lp (fun _ : α => E) ∞ ≃ₗᵢ[𝕜] α →ᵇ E := { AddEquiv.lpBcf with map_smul' := fun k f => rfl @@ -186,7 +186,7 @@ end NormedAddCommGroup section RingAlgebra -/-- The canonical map between `lp (λ (_ : α), R) ∞` and `α →ᵇ R` as a `RingEquiv`. -/ +/-- The canonical map between `lp (fun _ : α ↦ R) ∞` and `α →ᵇ R` as a `RingEquiv`. -/ noncomputable def RingEquiv.lpBcf : lp (fun _ : α => R) ∞ ≃+* (α →ᵇ R) := { @AddEquiv.lpBcf _ R _ _ _ with map_mul' := fun _f _g => BoundedContinuousFunction.ext fun _x => rfl } @@ -207,7 +207,7 @@ variable (α) -- even `α` needs to be explicit here for elaboration -- the `NormOneClass A` shouldn't really be necessary, but currently it is for -- `one_memℓp_infty` to get the `Ring` instance on `lp`. -/-- The canonical map between `lp (λ (_ : α), A) ∞` and `α →ᵇ A` as an `AlgEquiv`. -/ +/-- The canonical map between `lp (fun _ : α ↦ A) ∞` and `α →ᵇ A` as an `AlgEquiv`. -/ noncomputable def AlgEquiv.lpBcf : lp (fun _ : α => A) ∞ ≃ₐ[𝕜] α →ᵇ A := { RingEquiv.lpBcf A with commutes' := fun _k => rfl } #align alg_equiv.lp_bcf AlgEquiv.lpBcf diff --git a/Mathlib/Analysis/NormedSpace/lpSpace.lean b/Mathlib/Analysis/NormedSpace/lpSpace.lean index 27b681eb4f3f0..b88d4fc8f2f99 100644 --- a/Mathlib/Analysis/NormedSpace/lpSpace.lean +++ b/Mathlib/Analysis/NormedSpace/lpSpace.lean @@ -1059,7 +1059,7 @@ protected theorem norm_sub_norm_compl_sub_single (hp : 0 < p.toReal) (f : lp E p ∑ i in s, ‖f i‖ ^ p.toReal := by refine' ((hasSum_norm hp f).sub (hasSum_norm hp (f - ∑ i in s, lp.single p i (f i)))).unique _ let F : α → ℝ := fun i => ‖f i‖ ^ p.toReal - ‖(f - ∑ i in s, lp.single p i (f i)) i‖ ^ p.toReal - have hF : ∀ (i) (_ : i ∉ s), F i = 0 := by + have hF : ∀ i ∉ s, F i = 0 := by intro i hi suffices ‖f i‖ ^ p.toReal - ‖f i - ite (i ∈ s) (f i) 0‖ ^ p.toReal = 0 by simpa only [coeFn_sum, lp.single_apply, coeFn_sub, Pi.sub_apply, Finset.sum_apply, diff --git a/Mathlib/Analysis/SpecificLimits/Normed.lean b/Mathlib/Analysis/SpecificLimits/Normed.lean index 4240f7b44c35e..ea331b41d8fae 100644 --- a/Mathlib/Analysis/SpecificLimits/Normed.lean +++ b/Mathlib/Analysis/SpecificLimits/Normed.lean @@ -127,7 +127,7 @@ theorem TFAE_exists_lt_isLittleO_pow (f : ℕ → ℝ) (R : ℝ) : TFAE [∃ a ∈ Ioo (-R) R, f =o[atTop] (a ^ ·), ∃ a ∈ Ioo 0 R, f =o[atTop] (a ^ ·), ∃ a ∈ Ioo (-R) R, f =O[atTop] (a ^ ·), ∃ a ∈ Ioo 0 R, f =O[atTop] (a ^ ·), - ∃ a < R, ∃ (C : _) (_ : 0 < C ∨ 0 < R), ∀ n, |f n| ≤ C * a ^ n, + ∃ a < R, ∃ C : ℝ, (0 < C ∨ 0 < R) ∧ ∀ n, |f n| ≤ C * a ^ n, ∃ a ∈ Ioo 0 R, ∃ C > 0, ∀ n, |f n| ≤ C * a ^ n, ∃ a < R, ∀ᶠ n in atTop, |f n| ≤ a ^ n, ∃ a ∈ Ioo 0 R, ∀ᶠ n in atTop, |f n| ≤ a ^ n] := by have A : Ico 0 R ⊆ Ioo (-R) R := diff --git a/Mathlib/Combinatorics/Configuration.lean b/Mathlib/Combinatorics/Configuration.lean index 65966f41c5df0..b798e25edacf1 100644 --- a/Mathlib/Combinatorics/Configuration.lean +++ b/Mathlib/Combinatorics/Configuration.lean @@ -76,13 +76,13 @@ class Nondegenerate : Prop where /-- A nondegenerate configuration in which every pair of lines has an intersection point. -/ class HasPoints extends Nondegenerate P L where - mkPoint : ∀ {l₁ l₂ : L} (_ : l₁ ≠ l₂), P + mkPoint : ∀ {l₁ l₂ : L}, l₁ ≠ l₂ → P mkPoint_ax : ∀ {l₁ l₂ : L} (h : l₁ ≠ l₂), mkPoint h ∈ l₁ ∧ mkPoint h ∈ l₂ #align configuration.has_points Configuration.HasPoints /-- A nondegenerate configuration in which every pair of points has a line through them. -/ class HasLines extends Nondegenerate P L where - mkLine : ∀ {p₁ p₂ : P} (_ : p₁ ≠ p₂), L + mkLine : ∀ {p₁ p₂ : P}, p₁ ≠ p₂ → L mkLine_ax : ∀ {p₁ p₂ : P} (h : p₁ ≠ p₂), p₁ ∈ mkLine h ∧ p₂ ∈ mkLine h #align configuration.has_lines Configuration.HasLines diff --git a/Mathlib/Combinatorics/Pigeonhole.lean b/Mathlib/Combinatorics/Pigeonhole.lean index e49fbe1b1ac0f..a48948e0b3a6a 100644 --- a/Mathlib/Combinatorics/Pigeonhole.lean +++ b/Mathlib/Combinatorics/Pigeonhole.lean @@ -134,7 +134,7 @@ pigeonholes, and for all but `n` pigeonholes the total weight of the pigeons the then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole is greater than `b`. -/ theorem exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum - (ht : ∀ (y) (_ : y ∉ t), ∑ x in s.filter fun x => f x = y, w x ≤ 0) + (ht : ∀ y ∉ t, ∑ x in s.filter fun x => f x = y, w x ≤ 0) (hb : t.card • b < ∑ x in s, w x) : ∃ y ∈ t, b < ∑ x in s.filter fun x => f x = y, w x := exists_lt_of_sum_lt <| calc @@ -149,7 +149,7 @@ pigeonholes, and for all but `n` pigeonholes the total weight of the pigeons the then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole is less than `b`. -/ theorem exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul - (ht : ∀ (y) (_ : y ∉ t), (0 : M) ≤ ∑ x in s.filter fun x => f x = y, w x) + (ht : ∀ y ∉ t, (0 : M) ≤ ∑ x in s.filter fun x => f x = y, w x) (hb : ∑ x in s, w x < t.card • b) : ∃ y ∈ t, ∑ x in s.filter fun x => f x = y, w x < b := exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum (M := Mᵒᵈ) ht hb #align finset.exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul Finset.exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul @@ -183,7 +183,7 @@ are sorted into some pigeonholes, and for all but `n > 0` pigeonholes the total pigeons there is nonpositive, then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole is greater than or equal to `b`. -/ theorem exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum - (hf : ∀ (y) (_ : y ∉ t), ∑ x in s.filter fun x => f x = y, w x ≤ 0) (ht : t.Nonempty) + (hf : ∀ y ∉ t, ∑ x in s.filter fun x => f x = y, w x ≤ 0) (ht : t.Nonempty) (hb : t.card • b ≤ ∑ x in s, w x) : ∃ y ∈ t, b ≤ ∑ x in s.filter fun x => f x = y, w x := exists_le_of_sum_le ht <| calc @@ -198,7 +198,7 @@ sorted into some pigeonholes, and for all but `n > 0` pigeonholes the total weig there is nonnegative, then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole is less than or equal to `b`. -/ theorem exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul - (hf : ∀ (y) (_ : y ∉ t), (0 : M) ≤ ∑ x in s.filter fun x => f x = y, w x) (ht : t.Nonempty) + (hf : ∀ y ∉ t, (0 : M) ≤ ∑ x in s.filter fun x => f x = y, w x) (ht : t.Nonempty) (hb : ∑ x in s, w x ≤ t.card • b) : ∃ y ∈ t, ∑ x in s.filter fun x => f x = y, w x ≤ b := exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum (M := Mᵒᵈ) hf ht hb #align finset.exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul Finset.exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul diff --git a/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean b/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean index b0bb6263e91f4..8a73d3d3b4cc5 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean @@ -89,7 +89,7 @@ namespace ComponentCompl for adjacent vertices. -/ protected def lift {β : Sort*} (f : ∀ ⦃v⦄ (_ : v ∉ K), β) - (h : ∀ ⦃v w⦄ (hv : v ∉ K) (hw : w ∉ K) (_ : G.Adj v w), f hv = f hw) : G.ComponentCompl K → β := + (h : ∀ ⦃v w⦄ (hv : v ∉ K) (hw : w ∉ K), G.Adj v w → f hv = f hw) : G.ComponentCompl K → β := ConnectedComponent.lift (fun vv => f vv.prop) fun v w p => by induction' p with _ u v w a q ih · rintro _ diff --git a/Mathlib/Computability/Partrec.lean b/Mathlib/Computability/Partrec.lean index 44bcfcec9636f..9c3c8dde19db6 100644 --- a/Mathlib/Computability/Partrec.lean +++ b/Mathlib/Computability/Partrec.lean @@ -817,7 +817,7 @@ theorem fix_aux {α σ} (f : α →. Sum σ α) (a : α) (b : σ) : b ∈ PFun.fix f a := by intro F; refine' ⟨fun h => _, fun h => _⟩ · rcases h with ⟨n, ⟨_x, h₁⟩, h₂⟩ - have : ∀ (m a') (_ : Sum.inr a' ∈ F a m) (_ : b ∈ PFun.fix f a'), b ∈ PFun.fix f a := by + have : ∀ m a', Sum.inr a' ∈ F a m → b ∈ PFun.fix f a' → b ∈ PFun.fix f a := by intro m a' am ba induction' m with m IH generalizing a' <;> simp at am · rwa [← am] diff --git a/Mathlib/Data/Finset/Basic.lean b/Mathlib/Data/Finset/Basic.lean index edbb46ab77321..23e20a7b8c00b 100644 --- a/Mathlib/Data/Finset/Basic.lean +++ b/Mathlib/Data/Finset/Basic.lean @@ -2540,7 +2540,7 @@ theorem piecewise_eq_of_not_mem {i : α} (hi : i ∉ s) : s.piecewise f g i = g #align finset.piecewise_eq_of_not_mem Finset.piecewise_eq_of_not_mem theorem piecewise_congr {f f' g g' : ∀ i, δ i} (hf : ∀ i ∈ s, f i = f' i) - (hg : ∀ (i) (_ : i ∉ s), g i = g' i) : s.piecewise f g = s.piecewise f' g' := + (hg : ∀ i ∉ s, g i = g' i) : s.piecewise f g = s.piecewise f' g' := funext fun i => if_ctx_congr Iff.rfl (hf i) (hg i) #align finset.piecewise_congr Finset.piecewise_congr @@ -2633,7 +2633,7 @@ theorem le_piecewise_of_le_of_le {δ : α → Type*} [∀ i, Preorder (δ i)] {f #align finset.le_piecewise_of_le_of_le Finset.le_piecewise_of_le_of_le theorem piecewise_le_piecewise' {δ : α → Type*} [∀ i, Preorder (δ i)] {f g f' g' : ∀ i, δ i} - (Hf : ∀ x ∈ s, f x ≤ f' x) (Hg : ∀ (x) (_ : x ∉ s), g x ≤ g' x) : + (Hf : ∀ x ∈ s, f x ≤ f' x) (Hg : ∀ x ∉ s, g x ≤ g' x) : s.piecewise f g ≤ s.piecewise f' g' := fun x => by by_cases hx : x ∈ s <;> simp [hx, *] #align finset.piecewise_le_piecewise' Finset.piecewise_le_piecewise' @@ -3245,7 +3245,7 @@ theorem toFinset_add (s t : Multiset α) : toFinset (s + t) = toFinset s ∪ toF #align multiset.to_finset_add Multiset.toFinset_add @[simp] -theorem toFinset_nsmul (s : Multiset α) : ∀ (n : ℕ) (_ : n ≠ 0), (n • s).toFinset = s.toFinset +theorem toFinset_nsmul (s : Multiset α) : ∀ n ≠ 0, (n • s).toFinset = s.toFinset | 0, h => by contradiction | n + 1, _ => by by_cases h : n = 0 diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean index cf1d121c7c88d..8a0629a17e43e 100644 --- a/Mathlib/Data/Finset/Card.lean +++ b/Mathlib/Data/Finset/Card.lean @@ -552,7 +552,7 @@ theorem card_eq_one : s.card = 1 ↔ ∃ a, s = {a} := by #align finset.card_eq_one Finset.card_eq_one theorem exists_eq_insert_iff [DecidableEq α] {s t : Finset α} : - (∃ (a : _) (_ : a ∉ s), insert a s = t) ↔ s ⊆ t ∧ s.card + 1 = t.card := by + (∃ a ∉ s, insert a s = t) ↔ s ⊆ t ∧ s.card + 1 = t.card := by constructor · rintro ⟨a, ha, rfl⟩ exact ⟨subset_insert _ _, (card_insert_of_not_mem ha).symm⟩ @@ -698,7 +698,7 @@ end DecidableEq /-- Suppose that, given objects defined on all strict subsets of any finset `s`, one knows how to define an object on `s`. Then one can inductively define an object on all finsets, starting from the empty set and iterating. This can be used either to define data, or to prove properties. -/ -def strongInduction {p : Finset α → Sort*} (H : ∀ s, (∀ (t) (_ : t ⊂ s), p t) → p s) : +def strongInduction {p : Finset α → Sort*} (H : ∀ s, (∀ t ⊂ s, p t) → p s) : ∀ s : Finset α, p s | s => H s fun t h => @@ -708,7 +708,7 @@ def strongInduction {p : Finset α → Sort*} (H : ∀ s, (∀ (t) (_ : t ⊂ s) #align finset.strong_induction Finset.strongInduction @[nolint unusedHavesSuffices] --Porting note: false positive -theorem strongInduction_eq {p : Finset α → Sort*} (H : ∀ s, (∀ (t) (_ : t ⊂ s), p t) → p s) +theorem strongInduction_eq {p : Finset α → Sort*} (H : ∀ s, (∀ t ⊂ s, p t) → p s) (s : Finset α) : strongInduction H s = H s fun t _ => strongInduction H t := by rw [strongInduction] #align finset.strong_induction_eq Finset.strongInduction_eq @@ -716,12 +716,12 @@ theorem strongInduction_eq {p : Finset α → Sort*} (H : ∀ s, (∀ (t) (_ : t /-- Analogue of `strongInduction` with order of arguments swapped. -/ @[elab_as_elim] def strongInductionOn {p : Finset α → Sort*} (s : Finset α) : - (∀ s, (∀ (t) (_ : t ⊂ s), p t) → p s) → p s := fun H => strongInduction H s + (∀ s, (∀ t ⊂ s, p t) → p s) → p s := fun H => strongInduction H s #align finset.strong_induction_on Finset.strongInductionOn @[nolint unusedHavesSuffices] --Porting note: false positive theorem strongInductionOn_eq {p : Finset α → Sort*} (s : Finset α) - (H : ∀ s, (∀ (t) (_ : t ⊂ s), p t) → p s) : + (H : ∀ s, (∀ t ⊂ s, p t) → p s) : s.strongInductionOn H = H s fun t _ => t.strongInductionOn H := by dsimp only [strongInductionOn] rw [strongInduction] @@ -729,7 +729,7 @@ theorem strongInductionOn_eq {p : Finset α → Sort*} (s : Finset α) @[elab_as_elim] theorem case_strong_induction_on [DecidableEq α] {p : Finset α → Prop} (s : Finset α) (h₀ : p ∅) - (h₁ : ∀ a s, a ∉ s → (∀ (t) (_ : t ⊆ s), p t) → p (insert a s)) : p s := + (h₁ : ∀ a s, a ∉ s → (∀ t ⊆ s, p t) → p (insert a s)) : p s := Finset.strongInductionOn s fun s => Finset.induction_on s (fun _ => h₀) fun a s n _ ih => (h₁ a s n) fun t ss => ih _ (lt_of_le_of_lt ss (ssubset_insert n) : t < _) diff --git a/Mathlib/Data/Finset/Lattice.lean b/Mathlib/Data/Finset/Lattice.lean index 1ed6d7f180521..e70596fc8e45e 100644 --- a/Mathlib/Data/Finset/Lattice.lean +++ b/Mathlib/Data/Finset/Lattice.lean @@ -259,7 +259,7 @@ theorem sup_le_of_le_directed {α : Type*} [SemilatticeSup α] [OrderBot α] (s -- If we acquire sublattices -- the hypotheses should be reformulated as `s : SubsemilatticeSupBot` -theorem sup_mem (s : Set α) (w₁ : ⊥ ∈ s) (w₂ : ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), x ⊔ y ∈ s) +theorem sup_mem (s : Set α) (w₁ : ⊥ ∈ s) (w₂ : ∀ᵉ (x ∈ s) (y ∈ s), x ⊔ y ∈ s) {ι : Type*} (t : Finset ι) (p : ι → α) (h : ∀ i ∈ t, p i ∈ s) : t.sup p ∈ s := @sup_induction _ _ _ _ _ _ (· ∈ s) w₁ w₂ h #align finset.sup_mem Finset.sup_mem @@ -457,7 +457,7 @@ theorem inf_induction {p : α → Prop} (ht : p ⊤) (hp : ∀ a₁, p a₁ → @sup_induction αᵒᵈ _ _ _ _ _ _ ht hp hs #align finset.inf_induction Finset.inf_induction -theorem inf_mem (s : Set α) (w₁ : ⊤ ∈ s) (w₂ : ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), x ⊓ y ∈ s) +theorem inf_mem (s : Set α) (w₁ : ⊤ ∈ s) (w₂ : ∀ᵉ (x ∈ s) (y ∈ s), x ⊓ y ∈ s) {ι : Type*} (t : Finset ι) (p : ι → α) (h : ∀ i ∈ t, p i ∈ s) : t.inf p ∈ s := @inf_induction _ _ _ _ _ _ (· ∈ s) w₁ w₂ h #align finset.inf_mem Finset.inf_mem @@ -878,7 +878,7 @@ theorem sup'_induction {p : α → Prop} (hp : ∀ a₁, p a₁ → ∀ a₂, p | coe a₂ => exact hp a₁ h₁ a₂ h₂ #align finset.sup'_induction Finset.sup'_induction -theorem sup'_mem (s : Set α) (w : ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), x ⊔ y ∈ s) {ι : Type*} +theorem sup'_mem (s : Set α) (w : ∀ᵉ (x ∈ s) (y ∈ s), x ⊔ y ∈ s) {ι : Type*} (t : Finset ι) (H : t.Nonempty) (p : ι → α) (h : ∀ i ∈ t, p i ∈ s) : t.sup' H p ∈ s := sup'_induction H p w h #align finset.sup'_mem Finset.sup'_mem @@ -1015,7 +1015,7 @@ theorem inf'_induction {p : α → Prop} (hp : ∀ a₁, p a₁ → ∀ a₂, p sup'_induction (α := αᵒᵈ) H f hp hs #align finset.inf'_induction Finset.inf'_induction -theorem inf'_mem (s : Set α) (w : ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), x ⊓ y ∈ s) {ι : Type*} +theorem inf'_mem (s : Set α) (w : ∀ᵉ (x ∈ s) (y ∈ s), x ⊓ y ∈ s) {ι : Type*} (t : Finset ι) (H : t.Nonempty) (p : ι → α) (h : ∀ i ∈ t, p i ∈ s) : t.inf' H p ∈ s := inf'_induction H p w h #align finset.inf'_mem Finset.inf'_mem @@ -1669,10 +1669,10 @@ theorem exists_next_left {x : α} {s : Finset α} (h : ∃ y ∈ s, y < x) : /-- If finsets `s` and `t` are interleaved, then `Finset.card s ≤ Finset.card t + 1`. -/ theorem card_le_of_interleaved {s t : Finset α} - (h : ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), + (h : ∀ᵉ (x ∈ s) (y ∈ s), x < y → (∀ z ∈ s, z ∉ Set.Ioo x y) → ∃ z ∈ t, x < z ∧ z < y) : s.card ≤ t.card + 1 := by - replace h : ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), x < y → ∃ z ∈ t, x < z ∧ z < y + replace h : ∀ᵉ (x ∈ s) (y ∈ s), x < y → ∃ z ∈ t, x < z ∧ z < y · intro x hx y hy hxy rcases exists_next_right ⟨y, hy, hxy⟩ with ⟨a, has, hxa, ha⟩ rcases h x hx a has hxa fun z hzs hz => hz.2.not_le <| ha _ hzs hz.1 with ⟨b, hbt, hxb, hba⟩ @@ -1699,7 +1699,7 @@ theorem card_le_of_interleaved {s t : Finset α} /-- If finsets `s` and `t` are interleaved, then `Finset.card s ≤ Finset.card (t \ s) + 1`. -/ theorem card_le_diff_of_interleaved {s t : Finset α} (h : - ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), + ∀ᵉ (x ∈ s) (y ∈ s), x < y → (∀ z ∈ s, z ∉ Set.Ioo x y) → ∃ z ∈ t, x < z ∧ z < y) : s.card ≤ (t \ s).card + 1 := card_le_of_interleaved fun x hx y hy hxy hs => diff --git a/Mathlib/Data/Finset/PiInduction.lean b/Mathlib/Data/Finset/PiInduction.lean index 94bf98d382ed1..053908fcc912a 100644 --- a/Mathlib/Data/Finset/PiInduction.lean +++ b/Mathlib/Data/Finset/PiInduction.lean @@ -35,7 +35,7 @@ namespace Finset /-- General theorem for `Finset.induction_on_pi`-style induction principles. -/ theorem induction_on_pi_of_choice (r : ∀ i, α i → Finset (α i) → Prop) - (H_ex : ∀ (i) (s : Finset (α i)) (_ : s.Nonempty), ∃ x ∈ s, r i x (s.erase x)) + (H_ex : ∀ (i) (s : Finset (α i)), s.Nonempty → ∃ x ∈ s, r i x (s.erase x)) {p : (∀ i, Finset (α i)) → Prop} (f : ∀ i, Finset (α i)) (h0 : p fun _ ↦ ∅) (step : ∀ (g : ∀ i, Finset (α i)) (i : ι) (x : α i), diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean index 385a252311344..2415b0408eb2a 100644 --- a/Mathlib/Data/Finset/Powerset.lean +++ b/Mathlib/Data/Finset/Powerset.lean @@ -113,14 +113,14 @@ theorem powerset_insert [DecidableEq α] (s : Finset α) (a : α) : #align finset.powerset_insert Finset.powerset_insert /-- For predicate `p` decidable on subsets, it is decidable whether `p` holds for any subset. -/ -instance decidableExistsOfDecidableSubsets {s : Finset α} {p : ∀ (t) (_ : t ⊆ s), Prop} +instance decidableExistsOfDecidableSubsets {s : Finset α} {p : ∀ t ⊆ s, Prop} [∀ (t) (h : t ⊆ s), Decidable (p t h)] : Decidable (∃ (t : _) (h : t ⊆ s), p t h) := decidable_of_iff (∃ (t : _) (hs : t ∈ s.powerset), p t (mem_powerset.1 hs)) ⟨fun ⟨t, _, hp⟩ => ⟨t, _, hp⟩, fun ⟨t, hs, hp⟩ => ⟨t, mem_powerset.2 hs, hp⟩⟩ #align finset.decidable_exists_of_decidable_subsets Finset.decidableExistsOfDecidableSubsets /-- For predicate `p` decidable on subsets, it is decidable whether `p` holds for every subset. -/ -instance decidableForallOfDecidableSubsets {s : Finset α} {p : ∀ (t) (_ : t ⊆ s), Prop} +instance decidableForallOfDecidableSubsets {s : Finset α} {p : ∀ t ⊆ s, Prop} [∀ (t) (h : t ⊆ s), Decidable (p t h)] : Decidable (∀ (t) (h : t ⊆ s), p t h) := decidable_of_iff (∀ (t) (h : t ∈ s.powerset), p t (mem_powerset.1 h)) ⟨fun h t hs => h t (mem_powerset.2 hs), fun h _ _ => h _ _⟩ diff --git a/Mathlib/Data/Finset/Preimage.lean b/Mathlib/Data/Finset/Preimage.lean index 464e81e77b163..8e8a66a5bab5e 100644 --- a/Mathlib/Data/Finset/Preimage.lean +++ b/Mathlib/Data/Finset/Preimage.lean @@ -113,13 +113,9 @@ theorem preimage_subset {f : α ↪ β} {s : Finset β} {t : Finset α} (hs : s #align finset.preimage_subset Finset.preimage_subset theorem subset_map_iff {f : α ↪ β} {s : Finset β} {t : Finset α} : - s ⊆ t.map f ↔ ∃ (u : _) (_ : u ⊆ t), s = u.map f := by + s ⊆ t.map f ↔ ∃ u, u ⊆ t ∧ s = u.map f := by classical - refine' ⟨fun h => ⟨_, preimage_subset h, _⟩, _⟩ - · rw [map_eq_image, image_preimage, filter_true_of_mem] - exact fun x hx ↦ coe_map_subset_range _ _ (h hx) - · rintro ⟨u, hut, rfl⟩ - exact map_subset_map.2 hut + simp_rw [← coe_subset, coe_map, subset_image_iff, map_eq_image, eq_comm] #align finset.subset_map_iff Finset.subset_map_iff theorem sigma_preimage_mk {β : α → Type*} [DecidableEq α] (s : Finset (Σa, β a)) (t : Finset α) : diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index c06f864687508..aff660eff8f4f 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -2458,7 +2458,7 @@ for the seed element `b : β` and for all incremental `op : α → β → β` performed on the elements `(a : α) ∈ l`. The principle is given for a `Sort`-valued predicate, i.e., it can also be used to construct data. -/ def foldrRecOn {C : β → Sort*} (l : List α) (op : α → β → β) (b : β) (hb : C b) - (hl : ∀ (b : β) (_ : C b) (a : α) (_ : a ∈ l), C (op a b)) : C (foldr op b l) := by + (hl : ∀ b, C b → ∀ a ∈ l, C (op a b)) : C (foldr op b l) := by induction l with | nil => exact hb | cons hd tl IH => @@ -2473,7 +2473,7 @@ for the seed element `b : β` and for all incremental `op : β → α → β` performed on the elements `(a : α) ∈ l`. The principle is given for a `Sort`-valued predicate, i.e., it can also be used to construct data. -/ def foldlRecOn {C : β → Sort*} (l : List α) (op : β → α → β) (b : β) (hb : C b) - (hl : ∀ (b : β) (_ : C b) (a : α) (_ : a ∈ l), C (op b a)) : C (foldl op b l) := by + (hl : ∀ b, C b → ∀ a ∈ l, C (op b a)) : C (foldl op b l) := by induction l generalizing b with | nil => exact hb | cons hd tl IH => @@ -2491,7 +2491,7 @@ theorem foldrRecOn_nil {C : β → Sort*} (op : α → β → β) (b) (hb : C b) @[simp] theorem foldrRecOn_cons {C : β → Sort*} (x : α) (l : List α) (op : α → β → β) (b) (hb : C b) - (hl : ∀ (b : β) (_ : C b) (a : α) (_ : a ∈ x :: l), C (op a b)) : + (hl : ∀ b, C b → ∀ a ∈ x :: l, C (op a b)) : foldrRecOn (x :: l) op b hb hl = hl _ (foldrRecOn l op b hb fun b hb a ha => hl b hb a (mem_cons_of_mem _ ha)) x (mem_cons_self _ _) := diff --git a/Mathlib/Data/List/BigOperators/Basic.lean b/Mathlib/Data/List/BigOperators/Basic.lean index b9e9540de0234..92b1aa09509f2 100644 --- a/Mathlib/Data/List/BigOperators/Basic.lean +++ b/Mathlib/Data/List/BigOperators/Basic.lean @@ -155,7 +155,7 @@ theorem prod_map_hom (L : List ι) (f : ι → M) {G : Type*} [MonoidHomClass G #align list.sum_map_hom List.sum_map_hom @[to_additive] -theorem prod_isUnit : ∀ {L : List M} (_ : ∀ m ∈ L, IsUnit m), IsUnit L.prod +theorem prod_isUnit : ∀ {L : List M}, (∀ m ∈ L, IsUnit m) → IsUnit L.prod | [], _ => by simp | h :: t, u => by simp only [List.prod_cons] @@ -499,7 +499,7 @@ theorem monotone_prod_take [CanonicallyOrderedCommMonoid M] (L : List M) : @[to_additive sum_pos] theorem one_lt_prod_of_one_lt [OrderedCommMonoid M] : - ∀ (l : List M) (_ : ∀ x ∈ l, (1 : M) < x) (_ : l ≠ []), 1 < l.prod + ∀ l : List M, (∀ x ∈ l, (1 : M) < x) → l ≠ [] → 1 < l.prod | [], _, h => (h rfl).elim | [b], h, _ => by simpa using h | a :: b :: l, hl₁, _ => by diff --git a/Mathlib/Data/List/Chain.lean b/Mathlib/Data/List/Chain.lean index d70d94cd275ed..121900441ad38 100644 --- a/Mathlib/Data/List/Chain.lean +++ b/Mathlib/Data/List/Chain.lean @@ -255,7 +255,7 @@ theorem Chain'.cons {x y l} (h₁ : R x y) (h₂ : Chain' R (y :: l)) : Chain' R chain'_cons.2 ⟨h₁, h₂⟩ #align list.chain'.cons List.Chain'.cons -theorem Chain'.tail : ∀ {l} (_ : Chain' R l), Chain' R l.tail +theorem Chain'.tail : ∀ {l}, Chain' R l → Chain' R l.tail | [], _ => trivial | [_], _ => trivial | _ :: _ :: _, h => (chain'_cons.mp h).right diff --git a/Mathlib/Data/List/Cycle.lean b/Mathlib/Data/List/Cycle.lean index d2fa37f01ded9..dd05fdadd5d24 100644 --- a/Mathlib/Data/List/Cycle.lean +++ b/Mathlib/Data/List/Cycle.lean @@ -94,7 +94,7 @@ theorem nextOr_concat {xs : List α} {x : α} (d : α) (h : x ∉ xs) : nextOr ( theorem nextOr_mem {xs : List α} {x d : α} (hd : d ∈ xs) : nextOr xs x d ∈ xs := by revert hd - suffices ∀ (xs' : List α) (_ : ∀ x ∈ xs, x ∈ xs') (_ : d ∈ xs'), nextOr xs x d ∈ xs' by + suffices ∀ xs' : List α, (∀ x ∈ xs, x ∈ xs') → d ∈ xs' → nextOr xs x d ∈ xs' by exact this xs fun _ => id intro xs' hxs' hd induction' xs with y ys ih @@ -132,7 +132,7 @@ so it will match on first hit, ignoring later duplicates. * `prev [1, 2, 3, 4, 2] 2 _ = 1` * `prev [1, 1, 2] 1 _ = 2` -/ -def prev : ∀ (l : List α) (x : α) (_h : x ∈ l), α +def prev : ∀ l : List α, ∀ x ∈ l, α | [], _, h => by simp at h | [y], _, _ => y | y :: z :: xs, x, h => @@ -614,7 +614,7 @@ theorem Subsingleton.congr {s : Cycle α} (h : Subsingleton s) : /-- A `s : Cycle α` that is made up of at least two unique elements. -/ def Nontrivial (s : Cycle α) : Prop := - ∃ (x y : α) (_h : x ≠ y), x ∈ s ∧ y ∈ s + ∃ x y : α, x ≠ y ∧ x ∈ s ∧ y ∈ s #align cycle.nontrivial Cycle.Nontrivial @[simp] diff --git a/Mathlib/Data/List/Nodup.lean b/Mathlib/Data/List/Nodup.lean index 3224e8499607c..9a92d4ed69d74 100644 --- a/Mathlib/Data/List/Nodup.lean +++ b/Mathlib/Data/List/Nodup.lean @@ -144,7 +144,7 @@ theorem Nodup.ne_singleton_iff {l : List α} (h : Nodup l) (x : α) : · rw [← Ne.def, hl] at hx rcases hx with (rfl | ⟨y, hy, hx⟩) · simp - · suffices ∃ (y : α) (_ : y ∈ hd :: tl), y ≠ x by simpa [ne_nil_of_mem hy] + · suffices ∃ y ∈ hd :: tl, y ≠ x by simpa [ne_nil_of_mem hy] exact ⟨y, mem_cons_of_mem _ hy, hx⟩ #align list.nodup.ne_singleton_iff List.Nodup.ne_singleton_iff diff --git a/Mathlib/Data/List/NodupEquivFin.lean b/Mathlib/Data/List/NodupEquivFin.lean index 34d464b62aa54..e5d629d605d16 100644 --- a/Mathlib/Data/List/NodupEquivFin.lean +++ b/Mathlib/Data/List/NodupEquivFin.lean @@ -173,7 +173,7 @@ theorem sublist_iff_exists_fin_orderEmbedding_get_eq {l l' : List α} : rw [sublist_iff_exists_orderEmbedding_get?_eq] constructor · rintro ⟨f, hf⟩ - have h : ∀ {i : ℕ} (_ : i < l.length), f i < l'.length := by + have h : ∀ {i : ℕ}, i < l.length → f i < l'.length := by intro i hi specialize hf i rw [get?_eq_get hi, eq_comm, get?_eq_some] at hf diff --git a/Mathlib/Data/List/Sort.lean b/Mathlib/Data/List/Sort.lean index dea74006a8065..825171cbafc60 100644 --- a/Mathlib/Data/List/Sort.lean +++ b/Mathlib/Data/List/Sort.lean @@ -110,7 +110,7 @@ theorem eq_of_perm_of_sorted [IsAntisymm α r] {l₁ l₂ : List α} (p : l₁ ~ change a :: u₂ ++ v₂ = u₂ ++ ([a] ++ v₂) rw [← append_assoc] congr - have : ∀ (x : α) (_ : x ∈ u₂), x = a := fun x m => + have : ∀ x ∈ u₂, x = a := fun x m => antisymm ((pairwise_append.1 s₂).2.2 _ m a (mem_cons_self _ _)) (h₁ _ (by simp [m])) rw [(@eq_replicate _ a (length u₂ + 1) (a :: u₂)).2, (@eq_replicate _ a (length u₂ + 1) (u₂ ++ [a])).2] <;> @@ -268,7 +268,7 @@ variable {r} /-- If `l` is already `List.Sorted` with respect to `r`, then `insertionSort` does not change it. -/ -theorem Sorted.insertionSort_eq : ∀ {l : List α} (_ : Sorted r l), insertionSort r l = l +theorem Sorted.insertionSort_eq : ∀ {l : List α}, Sorted r l → insertionSort r l = l | [], _ => rfl | [a], _ => rfl | a :: b :: l, h => by @@ -432,7 +432,7 @@ theorem Sorted.merge : ∀ {l l' : List α}, Sorted r l → Sorted r l' → Sort | a :: l, [], h₁, _ => by simpa [List.merge] using h₁ | a :: l, b :: l', h₁, h₂ => by by_cases h : a ≼ b - · suffices ∀ (b' : α) (_ : b' ∈ List.merge r l (b :: l')), r a b' by + · suffices ∀ b' ∈ List.merge r l (b :: l'), r a b' by simpa [List.merge, h, h₁.of_cons.merge h₂] intro b' bm rcases show b' = b ∨ b' ∈ l ∨ b' ∈ l' by @@ -442,7 +442,7 @@ theorem Sorted.merge : ∀ {l l' : List α}, Sorted r l → Sorted r l' → Sort assumption · exact rel_of_sorted_cons h₁ _ bl · exact _root_.trans h (rel_of_sorted_cons h₂ _ bl') - · suffices ∀ (b' : α) (_ : b' ∈ List.merge r (a :: l) l'), r b b' by + · suffices ∀ b' ∈ List.merge r (a :: l) l', r b b' by simpa [List.merge, h, h₁.merge h₂.of_cons] intro b' bm have ba : b ≼ a := (total_of r _ _).resolve_left h diff --git a/Mathlib/Data/List/Zip.lean b/Mathlib/Data/List/Zip.lean index dba949738c56a..479c3092705e7 100644 --- a/Mathlib/Data/List/Zip.lean +++ b/Mathlib/Data/List/Zip.lean @@ -51,8 +51,8 @@ theorem zip_swap : ∀ (l₁ : List α) (l₂ : List β), (zip l₁ l₂).map Pr #align list.length_zip List.length_zip theorem forall_zipWith {f : α → β → γ} {p : γ → Prop} : - ∀ {l₁ : List α} {l₂ : List β} (_h : length l₁ = length l₂), - Forall p (zipWith f l₁ l₂) ↔ Forall₂ (fun x y => p (f x y)) l₁ l₂ + ∀ {l₁ : List α} {l₂ : List β}, length l₁ = length l₂ → + (Forall p (zipWith f l₁ l₂) ↔ Forall₂ (fun x y => p (f x y)) l₁ l₂) | [], [], _ => by simp | a :: l₁, b :: l₂, h => by simp only [length_cons, succ_inj'] at h diff --git a/Mathlib/Data/Matrix/Basic.lean b/Mathlib/Data/Matrix/Basic.lean index 1b92ad37c6dbd..766d39ef76c21 100644 --- a/Mathlib/Data/Matrix/Basic.lean +++ b/Mathlib/Data/Matrix/Basic.lean @@ -849,21 +849,21 @@ variable [DecidableEq m] [NonUnitalNonAssocSemiring α] (u v w : m → α) @[simp] theorem diagonal_dotProduct (i : m) : diagonal v i ⬝ᵥ w = v i * w i := by - have : ∀ (j) (_ : j ≠ i), diagonal v i j * w j = 0 := fun j hij => by + have : ∀ j ≠ i, diagonal v i j * w j = 0 := fun j hij => by simp [diagonal_apply_ne' _ hij] convert Finset.sum_eq_single i (fun j _ => this j) _ using 1 <;> simp #align matrix.diagonal_dot_product Matrix.diagonal_dotProduct @[simp] theorem dotProduct_diagonal (i : m) : v ⬝ᵥ diagonal w i = v i * w i := by - have : ∀ (j) (_ : j ≠ i), v j * diagonal w i j = 0 := fun j hij => by + have : ∀ j ≠ i, v j * diagonal w i j = 0 := fun j hij => by simp [diagonal_apply_ne' _ hij] convert Finset.sum_eq_single i (fun j _ => this j) _ using 1 <;> simp #align matrix.dot_product_diagonal Matrix.dotProduct_diagonal @[simp] theorem dotProduct_diagonal' (i : m) : (v ⬝ᵥ fun j => diagonal w j i) = v i * w i := by - have : ∀ (j) (_ : j ≠ i), v j * diagonal w j i = 0 := fun j hij => by + have : ∀ j ≠ i, v j * diagonal w j i = 0 := fun j hij => by simp [diagonal_apply_ne _ hij] convert Finset.sum_eq_single i (fun j _ => this j) _ using 1 <;> simp #align matrix.dot_product_diagonal' Matrix.dotProduct_diagonal' @@ -871,7 +871,7 @@ theorem dotProduct_diagonal' (i : m) : (v ⬝ᵥ fun j => diagonal w j i) = v i @[simp] theorem single_dotProduct (x : α) (i : m) : Pi.single i x ⬝ᵥ v = x * v i := by -- Porting note: (implicit arg) added `(f := fun _ => α)` - have : ∀ (j) (_ : j ≠ i), Pi.single (f := fun _ => α) i x j * v j = 0 := fun j hij => by + have : ∀ j ≠ i, Pi.single (f := fun _ => α) i x j * v j = 0 := fun j hij => by simp [Pi.single_eq_of_ne hij] convert Finset.sum_eq_single i (fun j _ => this j) _ using 1 <;> simp #align matrix.single_dot_product Matrix.single_dotProduct @@ -879,7 +879,7 @@ theorem single_dotProduct (x : α) (i : m) : Pi.single i x ⬝ᵥ v = x * v i := @[simp] theorem dotProduct_single (x : α) (i : m) : v ⬝ᵥ Pi.single i x = v i * x := by -- Porting note: (implicit arg) added `(f := fun _ => α)` - have : ∀ (j) (_ : j ≠ i), v j * Pi.single (f := fun _ => α) i x j = 0 := fun j hij => by + have : ∀ j ≠ i, v j * Pi.single (f := fun _ => α) i x j = 0 := fun j hij => by simp [Pi.single_eq_of_ne hij] convert Finset.sum_eq_single i (fun j _ => this j) _ using 1 <;> simp #align matrix.dot_product_single Matrix.dotProduct_single diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index c94f2c45bc695..9219b6d8dd63e 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -595,7 +595,7 @@ lemma cons_lt_cons (a : α) (h : s < t) : a ::ₘ s < a ::ₘ t := cons_lt_cons_ theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩ - suffices ∀ {t'} (_ : s ≤ t') (_ : a ∈ t'), a ::ₘ s ≤ t' by + suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _)) introv h revert m @@ -2869,7 +2869,7 @@ theorem card_eq_card_of_rel {r : α → β → Prop} {s : Multiset α} {t : Mult #align multiset.card_eq_card_of_rel Multiset.card_eq_card_of_rel theorem exists_mem_of_rel_of_mem {r : α → β → Prop} {s : Multiset α} {t : Multiset β} - (h : Rel r s t) : ∀ {a : α} (_ha : a ∈ s), ∃ b ∈ t, r a b := by + (h : Rel r s t) : ∀ {a : α}, a ∈ s → ∃ b ∈ t, r a b := by induction' h with x y s t hxy _hst ih · simp · intro a ha diff --git a/Mathlib/Data/MvPolynomial/Variables.lean b/Mathlib/Data/MvPolynomial/Variables.lean index e9dffc6e6b862..f6d5e9fda4ea4 100644 --- a/Mathlib/Data/MvPolynomial/Variables.lean +++ b/Mathlib/Data/MvPolynomial/Variables.lean @@ -303,7 +303,7 @@ theorem vars_X [Nontrivial R] : (X n : MvPolynomial σ R).vars = {n} := by set_option linter.uppercaseLean3 false in #align mv_polynomial.vars_X MvPolynomial.vars_X -theorem mem_vars (i : σ) : i ∈ p.vars ↔ ∃ (d : σ →₀ ℕ) (_ : d ∈ p.support), i ∈ d.support := by +theorem mem_vars (i : σ) : i ∈ p.vars ↔ ∃ d ∈ p.support, i ∈ d.support := by classical simp only [vars_def, Multiset.mem_toFinset, mem_degrees, mem_support_iff, exists_prop] #align mv_polynomial.mem_vars MvPolynomial.mem_vars @@ -469,7 +469,6 @@ theorem vars_eq_support_biUnion_support [DecidableEq σ] : p.vars = p.support.biUnion Finsupp.support := by ext i rw [mem_vars, Finset.mem_biUnion] - simp #align mv_polynomial.vars_eq_support_bUnion_support MvPolynomial.vars_eq_support_biUnion_support end Map diff --git a/Mathlib/Data/Polynomial/AlgebraMap.lean b/Mathlib/Data/Polynomial/AlgebraMap.lean index 300667f4620ca..faab8e9287bb4 100644 --- a/Mathlib/Data/Polynomial/AlgebraMap.lean +++ b/Mathlib/Data/Polynomial/AlgebraMap.lean @@ -469,7 +469,7 @@ section CommRing variable [CommRing S] {f : R →+* S} theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_eval : p ∣ f.eval z) - (dvd_terms : ∀ (j) (_ : j ≠ i), p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by + (dvd_terms : ∀ j ≠ i, p ∣ f.coeff j * z ^ j) : p ∣ f.coeff i * z ^ i := by by_cases hi : i ∈ f.support · rw [eval, eval₂_eq_sum, sum_def] at dvd_eval rw [← Finset.insert_erase hi, Finset.sum_insert (Finset.not_mem_erase _ _)] at dvd_eval @@ -483,7 +483,7 @@ theorem dvd_term_of_dvd_eval_of_dvd_terms {z p : S} {f : S[X]} (i : ℕ) (dvd_ev #align polynomial.dvd_term_of_dvd_eval_of_dvd_terms Polynomial.dvd_term_of_dvd_eval_of_dvd_terms theorem dvd_term_of_isRoot_of_dvd_terms {r p : S} {f : S[X]} (i : ℕ) (hr : f.IsRoot r) - (h : ∀ (j) (_ : j ≠ i), p ∣ f.coeff j * r ^ j) : p ∣ f.coeff i * r ^ i := + (h : ∀ j ≠ i, p ∣ f.coeff j * r ^ j) : p ∣ f.coeff i * r ^ i := dvd_term_of_dvd_eval_of_dvd_terms i (Eq.symm hr ▸ dvd_zero p) h #align polynomial.dvd_term_of_is_root_of_dvd_terms Polynomial.dvd_term_of_isRoot_of_dvd_terms diff --git a/Mathlib/Data/Real/CauSeq.lean b/Mathlib/Data/Real/CauSeq.lean index 1c4a8dafedb28..397b449613c0d 100644 --- a/Mathlib/Data/Real/CauSeq.lean +++ b/Mathlib/Data/Real/CauSeq.lean @@ -170,7 +170,7 @@ variable [IsAbsoluteValue abv] -- see Note [nolint_ge] -- @[nolint ge_or_gt] -- Porting note: restore attribute theorem cauchy₂ (f : CauSeq β abv) {ε} : - 0 < ε → ∃ i, ∀ (j) (_ : j ≥ i) (k) (_ : k ≥ i), abv (f j - f k) < ε := + 0 < ε → ∃ i, ∀ j ≥ i, ∀ k ≥ i, abv (f j - f k) < ε := f.2.cauchy₂ #align cau_seq.cauchy₂ CauSeq.cauchy₂ diff --git a/Mathlib/Data/Semiquot.lean b/Mathlib/Data/Semiquot.lean index 0060288c10d25..807762648d638 100644 --- a/Mathlib/Data/Semiquot.lean +++ b/Mathlib/Data/Semiquot.lean @@ -110,14 +110,14 @@ def toTrunc (q : Semiquot α) : Trunc α := warning: expanding binder collection (a b «expr ∈ » q) -/ /-- If `f` is a constant on `q.s`, then `q.liftOn f` is the value of `f` at any point of `q`. -/ -def liftOn (q : Semiquot α) (f : α → β) (h : ∀ (a) (_ : a ∈ q) (b) (_ : b ∈ q), f a = f b) : β := +def liftOn (q : Semiquot α) (f : α → β) (h : ∀ a ∈ q, ∀ b ∈ q, f a = f b) : β := Trunc.liftOn q.2 (fun x => f x.1) fun x y => h _ x.2 _ y.2 #align semiquot.lift_on Semiquot.liftOn /- ./././Mathport/Syntax/Translate/Basic.lean:632:2: warning: expanding binder collection (a b «expr ∈ » q) -/ theorem liftOn_ofMem (q : Semiquot α) (f : α → β) - (h : ∀ (a) (_ : a ∈ q) (b) (_ : b ∈ q), f a = f b) (a : α) (aq : a ∈ q) : liftOn q f h = f a := + (h : ∀ a ∈ q, ∀ b ∈ q, f a = f b) (a : α) (aq : a ∈ q) : liftOn q f h = f a := by revert h; rw [eq_mk_of_mem aq]; intro; rfl #align semiquot.lift_on_of_mem Semiquot.liftOn_ofMem @@ -205,7 +205,7 @@ theorem pure_le {a : α} {s : Semiquot α} : pure a ≤ s ↔ a ∈ s := warning: expanding binder collection (a b «expr ∈ » q) -/ /-- Assert that a `Semiquot` contains only one possible value. -/ def IsPure (q : Semiquot α) : Prop := - ∀ (a) (_ : a ∈ q) (b) (_ : b ∈ q), a = b + ∀ a ∈ q, ∀ b ∈ q, a = b #align semiquot.is_pure Semiquot.IsPure /-- Extract the value from an `IsPure` semiquotient. -/ diff --git a/Mathlib/Data/Set/Basic.lean b/Mathlib/Data/Set/Basic.lean index 6b7d935c34c0b..4a54da2144a88 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -2510,12 +2510,12 @@ theorem nontrivial_of_pair_subset {x y} (hxy : x ≠ y) (h : {x, y} ⊆ s) : s.N (nontrivial_pair hxy).mono h #align set.nontrivial_of_pair_subset Set.nontrivial_of_pair_subset -theorem Nontrivial.pair_subset (hs : s.Nontrivial) : ∃ (x y : _) (_ : x ≠ y), {x, y} ⊆ s := +theorem Nontrivial.pair_subset (hs : s.Nontrivial) : ∃ x y, x ≠ y ∧ {x, y} ⊆ s := let ⟨x, hx, y, hy, hxy⟩ := hs - ⟨x, y, hxy, insert_subset_iff.2 ⟨hx, singleton_subset_iff.2 hy⟩⟩ + ⟨x, y, hxy, insert_subset hx <| singleton_subset_iff.2 hy⟩ #align set.nontrivial.pair_subset Set.Nontrivial.pair_subset -theorem nontrivial_iff_pair_subset : s.Nontrivial ↔ ∃ (x y : _) (_ : x ≠ y), {x, y} ⊆ s := +theorem nontrivial_iff_pair_subset : s.Nontrivial ↔ ∃ x y, x ≠ y ∧ {x, y} ⊆ s := ⟨Nontrivial.pair_subset, fun H => let ⟨_, _, hxy, h⟩ := H nontrivial_of_pair_subset hxy h⟩ @@ -2543,19 +2543,18 @@ theorem nontrivial_of_lt [Preorder α] {x y} (hx : x ∈ s) (hy : y ∈ s) (hxy #align set.nontrivial_of_lt Set.nontrivial_of_lt theorem nontrivial_of_exists_lt [Preorder α] - (H : ∃ (x : α) (_ : x ∈ s) (y : α) (_ : y ∈ s), x < y) : s.Nontrivial := + (H : ∃ᵉ (x ∈ s) (y ∈ s), x < y) : s.Nontrivial := let ⟨_, hx, _, hy, hxy⟩ := H nontrivial_of_lt hx hy hxy #align set.nontrivial_of_exists_lt Set.nontrivial_of_exists_lt -theorem Nontrivial.exists_lt [LinearOrder α] (hs : s.Nontrivial) : - ∃ (x : α) (_ : x ∈ s) (y : α) (_ : y ∈ s), x < y := +theorem Nontrivial.exists_lt [LinearOrder α] (hs : s.Nontrivial) : ∃ᵉ (x ∈ s) (y ∈ s), x < y := let ⟨x, hx, y, hy, hxy⟩ := hs Or.elim (lt_or_gt_of_ne hxy) (fun H => ⟨x, hx, y, hy, H⟩) fun H => ⟨y, hy, x, hx, H⟩ #align set.nontrivial.exists_lt Set.Nontrivial.exists_lt theorem nontrivial_iff_exists_lt [LinearOrder α] : - s.Nontrivial ↔ ∃ (x : α) (_ : x ∈ s) (y : α) (_ : y ∈ s), x < y := + s.Nontrivial ↔ ∃ᵉ (x ∈ s) (y ∈ s), x < y := ⟨Nontrivial.exists_lt, nontrivial_of_exists_lt⟩ #align set.nontrivial_iff_exists_lt Set.nontrivial_iff_exists_lt @@ -2759,8 +2758,8 @@ variable [LinearOrder α] [LinearOrder β] {f : α → β} downright. -/ theorem not_monotoneOn_not_antitoneOn_iff_exists_le_le : ¬MonotoneOn f s ∧ ¬AntitoneOn f s ↔ - ∃ (a : α) (_ : a ∈ s) (b : α) (_ : b ∈ s) (c : α) (_ : c ∈ s), - a ≤ b ∧ b ≤ c ∧ (f a < f b ∧ f c < f b ∨ f b < f a ∧ f b < f c) := by + ∃ᵉ (a ∈ s) (b ∈ s) (c ∈ s), a ≤ b ∧ b ≤ c ∧ + (f a < f b ∧ f c < f b ∨ f b < f a ∧ f b < f c) := by simp [monotoneOn_iff_monotone, antitoneOn_iff_antitone, and_assoc, exists_and_left, not_monotone_not_antitone_iff_exists_le_le, @and_left_comm (_ ∈ s)] #align set.not_monotone_on_not_antitone_on_iff_exists_le_le Set.not_monotoneOn_not_antitoneOn_iff_exists_le_le @@ -2769,8 +2768,8 @@ theorem not_monotoneOn_not_antitoneOn_iff_exists_le_le : downright. -/ theorem not_monotoneOn_not_antitoneOn_iff_exists_lt_lt : ¬MonotoneOn f s ∧ ¬AntitoneOn f s ↔ - ∃ (a : α) (_ : a ∈ s) (b : α) (_ : b ∈ s) (c : α) (_ : c ∈ s), - a < b ∧ b < c ∧ (f a < f b ∧ f c < f b ∨ f b < f a ∧ f b < f c) := by + ∃ᵉ (a ∈ s) (b ∈ s) (c ∈ s), a < b ∧ b < c ∧ + (f a < f b ∧ f c < f b ∨ f b < f a ∧ f b < f c) := by simp [monotoneOn_iff_monotone, antitoneOn_iff_antitone, and_assoc, exists_and_left, not_monotone_not_antitone_iff_exists_lt_lt, @and_left_comm (_ ∈ s)] #align set.not_monotone_on_not_antitone_on_iff_exists_lt_lt Set.not_monotoneOn_not_antitoneOn_iff_exists_lt_lt diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index 9664197605460..dc3eb508ede59 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -1000,7 +1000,7 @@ theorem exists_subset_or_subset_of_two_mul_lt_ncard {n : ℕ} (hst : 2 * n < (s #align set.ncard_eq_one Set.ncard_eq_one theorem exists_eq_insert_iff_ncard (hs : s.Finite := by toFinite_tac) : - (∃ (a : α) (_ : a ∉ s), insert a s = t) ↔ s ⊆ t ∧ s.ncard + 1 = t.ncard := by + (∃ a ∉ s, insert a s = t) ↔ s ⊆ t ∧ s.ncard + 1 = t.ncard := by classical cases' t.finite_or_infinite with ht ht · rw [ncard_eq_toFinset_card _ hs, ncard_eq_toFinset_card _ ht, diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean index 344381d7f7b9b..3a3ba016b48b3 100644 --- a/Mathlib/Data/Set/Function.lean +++ b/Mathlib/Data/Set/Function.lean @@ -78,14 +78,14 @@ theorem image_restrict (f : α → β) (s t : Set α) : @[simp] theorem restrict_dite {s : Set α} [∀ x, Decidable (x ∈ s)] (f : ∀ a ∈ s, β) - (g : ∀ (a) (_ : a ∉ s), β) : + (g : ∀ a ∉ s, β) : (s.restrict fun a => if h : a ∈ s then f a h else g a h) = (fun a : s => f a a.2) := funext fun a => dif_pos a.2 #align set.restrict_dite Set.restrict_dite @[simp] theorem restrict_dite_compl {s : Set α} [∀ x, Decidable (x ∈ s)] (f : ∀ a ∈ s, β) - (g : ∀ (a) (_ : a ∉ s), β) : + (g : ∀ a ∉ s, β) : (sᶜ.restrict fun a => if h : a ∈ s then f a h else g a h) = (fun a : (sᶜ : Set α) => g a a.2) := funext fun a => dif_neg a.2 #align set.restrict_dite_compl Set.restrict_dite_compl @@ -1493,19 +1493,19 @@ theorem piecewise_eqOn_compl (f g : α → β) : EqOn (s.piecewise f g) g sᶜ : #align set.piecewise_eq_on_compl Set.piecewise_eqOn_compl theorem piecewise_le {δ : α → Type*} [∀ i, Preorder (δ i)] {s : Set α} [∀ j, Decidable (j ∈ s)] - {f₁ f₂ g : ∀ i, δ i} (h₁ : ∀ i ∈ s, f₁ i ≤ g i) (h₂ : ∀ (i) (_ : i ∉ s), f₂ i ≤ g i) : + {f₁ f₂ g : ∀ i, δ i} (h₁ : ∀ i ∈ s, f₁ i ≤ g i) (h₂ : ∀ i ∉ s, f₂ i ≤ g i) : s.piecewise f₁ f₂ ≤ g := fun i => if h : i ∈ s then by simp [*] else by simp [*] #align set.piecewise_le Set.piecewise_le theorem le_piecewise {δ : α → Type*} [∀ i, Preorder (δ i)] {s : Set α} [∀ j, Decidable (j ∈ s)] - {f₁ f₂ g : ∀ i, δ i} (h₁ : ∀ i ∈ s, g i ≤ f₁ i) (h₂ : ∀ (i) (_ : i ∉ s), g i ≤ f₂ i) : + {f₁ f₂ g : ∀ i, δ i} (h₁ : ∀ i ∈ s, g i ≤ f₁ i) (h₂ : ∀ i ∉ s, g i ≤ f₂ i) : g ≤ s.piecewise f₁ f₂ := @piecewise_le α (fun i => (δ i)ᵒᵈ) _ s _ _ _ _ h₁ h₂ #align set.le_piecewise Set.le_piecewise theorem piecewise_le_piecewise {δ : α → Type*} [∀ i, Preorder (δ i)] {s : Set α} [∀ j, Decidable (j ∈ s)] {f₁ f₂ g₁ g₂ : ∀ i, δ i} (h₁ : ∀ i ∈ s, f₁ i ≤ g₁ i) - (h₂ : ∀ (i) (_ : i ∉ s), f₂ i ≤ g₂ i) : s.piecewise f₁ f₂ ≤ s.piecewise g₁ g₂ := by + (h₂ : ∀ i ∉ s, f₂ i ≤ g₂ i) : s.piecewise f₁ f₂ ≤ s.piecewise g₁ g₂ := by apply piecewise_le <;> intros <;> simp [*] #align set.piecewise_le_piecewise Set.piecewise_le_piecewise @@ -1593,7 +1593,7 @@ theorem range_piecewise (f g : α → β) : range (s.piecewise f g) = f '' s ∪ theorem injective_piecewise_iff {f g : α → β} : Injective (s.piecewise f g) ↔ - InjOn f s ∧ InjOn g sᶜ ∧ ∀ x ∈ s, ∀ (y) (_ : y ∉ s), f x ≠ g y := by + InjOn f s ∧ InjOn g sᶜ ∧ ∀ x ∈ s, ∀ y ∉ s, f x ≠ g y := by rw [injective_iff_injOn_univ, ← union_compl_self s, injOn_union (@disjoint_compl_right _ _ s), (piecewise_eqOn s f g).injOn_iff, (piecewise_eqOn_compl s f g).injOn_iff] refine' and_congr Iff.rfl (and_congr Iff.rfl <| forall₄_congr fun x hx y hy => _) diff --git a/Mathlib/Data/Set/Image.lean b/Mathlib/Data/Set/Image.lean index dbdcfca9cbaf8..7c08f48308b2f 100644 --- a/Mathlib/Data/Set/Image.lean +++ b/Mathlib/Data/Set/Image.lean @@ -228,7 +228,7 @@ theorem mem_image_iff_bex {f : α → β} {s : Set α} {y : β} : #align set.mem_image_iff_bex Set.mem_image_iff_bex @[simp] -theorem mem_image (f : α → β) (s : Set α) (y : β) : y ∈ f '' s ↔ ∃ x, x ∈ s ∧ f x = y := +theorem mem_image (f : α → β) (s : Set α) (y : β) : y ∈ f '' s ↔ ∃ x ∈ s, f x = y := Iff.rfl #align set.mem_image Set.mem_image diff --git a/Mathlib/Data/Set/Intervals/OrdConnected.lean b/Mathlib/Data/Set/Intervals/OrdConnected.lean index 0f142c3b4a282..aa9a7196c9cd4 100644 --- a/Mathlib/Data/Set/Intervals/OrdConnected.lean +++ b/Mathlib/Data/Set/Intervals/OrdConnected.lean @@ -136,7 +136,7 @@ instance ordConnected_iInter' {ι : Sort*} {s : ι → Set α} [∀ i, OrdConnec #align set.ord_connected_Inter' Set.ordConnected_iInter' /- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i hi) -/ -theorem ordConnected_biInter {ι : Sort*} {p : ι → Prop} {s : ∀ (i : ι) (_ : p i), Set α} +theorem ordConnected_biInter {ι : Sort*} {p : ι → Prop} {s : ∀ i, p i → Set α} (hs : ∀ i hi, OrdConnected (s i hi)) : OrdConnected (⋂ (i) (hi), s i hi) := ordConnected_iInter fun i => ordConnected_iInter <| hs i #align set.ord_connected_bInter Set.ordConnected_biInter diff --git a/Mathlib/Data/Set/Intervals/Pi.lean b/Mathlib/Data/Set/Intervals/Pi.lean index 45a1ae6024d73..cbdb4b7aa6efd 100644 --- a/Mathlib/Data/Set/Intervals/Pi.lean +++ b/Mathlib/Data/Set/Intervals/Pi.lean @@ -45,7 +45,7 @@ theorem pi_univ_Icc : (pi univ fun i ↦ Icc (x i) (y i)) = Icc x y := #align set.pi_univ_Icc Set.pi_univ_Icc theorem piecewise_mem_Icc {s : Set ι} [∀ j, Decidable (j ∈ s)] {f₁ f₂ g₁ g₂ : ∀ i, α i} - (h₁ : ∀ i ∈ s, f₁ i ∈ Icc (g₁ i) (g₂ i)) (h₂ : ∀ (i) (_ : i ∉ s), f₂ i ∈ Icc (g₁ i) (g₂ i)) : + (h₁ : ∀ i ∈ s, f₁ i ∈ Icc (g₁ i) (g₂ i)) (h₂ : ∀ i ∉ s, f₂ i ∈ Icc (g₁ i) (g₂ i)) : s.piecewise f₁ f₂ ∈ Icc g₁ g₂ := ⟨le_piecewise (fun i hi ↦ (h₁ i hi).1) fun i hi ↦ (h₂ i hi).1, piecewise_le (fun i hi ↦ (h₁ i hi).2) fun i hi ↦ (h₂ i hi).2⟩ diff --git a/Mathlib/Data/Set/Intervals/UnorderedInterval.lean b/Mathlib/Data/Set/Intervals/UnorderedInterval.lean index eefdc07cef471..4d8710095008e 100644 --- a/Mathlib/Data/Set/Intervals/UnorderedInterval.lean +++ b/Mathlib/Data/Set/Intervals/UnorderedInterval.lean @@ -266,7 +266,7 @@ lemma monotone_or_antitone_iff_uIcc : -- Porting note: mathport expands the syntactic sugar `∀ a b c ∈ s` differently than Lean3 lemma monotoneOn_or_antitoneOn_iff_uIcc : MonotoneOn f s ∨ AntitoneOn f s ↔ - ∀ (a) (_ : a ∈ s) (b) (_ : b ∈ s) (c) (_ : c ∈ s), c ∈ [[a, b]] → f c ∈ [[f a, f b]] := + ∀ᵉ (a ∈ s) (b ∈ s) (c ∈ s), c ∈ [[a, b]] → f c ∈ [[f a, f b]] := by simp [monotoneOn_iff_monotone, antitoneOn_iff_antitone, monotone_or_antitone_iff_uIcc, mem_uIcc] #align set.monotone_on_or_antitone_on_iff_uIcc Set.monotoneOn_or_antitoneOn_iff_uIcc diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index 2e5f8e9ef25e4..972edef21ac7a 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -1683,7 +1683,7 @@ theorem InjOn.image_iInter_eq [Nonempty ι] {s : ι → Set α} {f : α → β} /- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i hi) -/ /- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i hi) -/ /- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i hi) -/ -theorem InjOn.image_biInter_eq {p : ι → Prop} {s : ∀ (i) (_ : p i), Set α} (hp : ∃ i, p i) +theorem InjOn.image_biInter_eq {p : ι → Prop} {s : ∀ i, p i → Set α} (hp : ∃ i, p i) {f : α → β} (h : InjOn f (⋃ (i) (hi), s i hi)) : (f '' ⋂ (i) (hi), s i hi) = ⋂ (i) (hi), f '' s i hi := by simp only [iInter, iInf_subtype'] diff --git a/Mathlib/Data/Set/Pairwise/Basic.lean b/Mathlib/Data/Set/Pairwise/Basic.lean index 7c130ae558583..4a8b83f99d44b 100644 --- a/Mathlib/Data/Set/Pairwise/Basic.lean +++ b/Mathlib/Data/Set/Pairwise/Basic.lean @@ -410,7 +410,7 @@ theorem pairwiseDisjoint_image_left_iff {f : α → β → γ} {s : Set α} {t : lemma exists_ne_mem_inter_of_not_pairwiseDisjoint {f : ι → Set α} (h : ¬ s.PairwiseDisjoint f) : - ∃ i ∈ s, ∃ j ∈ s, ∃ (_hij : i ≠ j) (x : α), x ∈ f i ∩ f j := by + ∃ i ∈ s, ∃ j ∈ s, i ≠ j ∧ ∃ x : α, x ∈ f i ∩ f j := by change ¬ ∀ i, i ∈ s → ∀ j, j ∈ s → i ≠ j → ∀ t, t ≤ f i → t ≤ f j → t ≤ ⊥ at h simp only [not_forall] at h obtain ⟨i, hi, j, hj, h_ne, t, hfi, hfj, ht⟩ := h @@ -421,7 +421,7 @@ lemma exists_ne_mem_inter_of_not_pairwiseDisjoint lemma exists_lt_mem_inter_of_not_pairwiseDisjoint [LinearOrder ι] {f : ι → Set α} (h : ¬ s.PairwiseDisjoint f) : - ∃ i ∈ s, ∃ j ∈ s, ∃ (_hij : i < j) (x : α), x ∈ f i ∩ f j := by + ∃ i ∈ s, ∃ j ∈ s, i < j ∧ ∃ x, x ∈ f i ∩ f j := by obtain ⟨i, hi, j, hj, hne, x, hx₁, hx₂⟩ := exists_ne_mem_inter_of_not_pairwiseDisjoint h cases' lt_or_lt_iff_ne.mpr hne with h_lt h_lt · exact ⟨i, hi, j, hj, h_lt, x, hx₁, hx₂⟩ @@ -431,14 +431,14 @@ end Set lemma exists_ne_mem_inter_of_not_pairwise_disjoint {f : ι → Set α} (h : ¬ Pairwise (Disjoint on f)) : - ∃ (i j : ι) (_hij : i ≠ j) (x : α), x ∈ f i ∩ f j := by + ∃ i j : ι, i ≠ j ∧ ∃ x, x ∈ f i ∩ f j := by rw [← pairwise_univ] at h obtain ⟨i, _hi, j, _hj, h⟩ := exists_ne_mem_inter_of_not_pairwiseDisjoint h exact ⟨i, j, h⟩ lemma exists_lt_mem_inter_of_not_pairwise_disjoint [LinearOrder ι] {f : ι → Set α} (h : ¬ Pairwise (Disjoint on f)) : - ∃ (i j : ι) (_ : i < j) (x : α), x ∈ f i ∩ f j := by + ∃ i j : ι, i < j ∧ ∃ x, x ∈ f i ∩ f j := by rw [← pairwise_univ] at h obtain ⟨i, _hi, j, _hj, h⟩ := exists_lt_mem_inter_of_not_pairwiseDisjoint h exact ⟨i, j, h⟩ diff --git a/Mathlib/Data/Set/Prod.lean b/Mathlib/Data/Set/Prod.lean index bb4dc9ab2c3af..36f4eef0986a8 100644 --- a/Mathlib/Data/Set/Prod.lean +++ b/Mathlib/Data/Set/Prod.lean @@ -906,7 +906,7 @@ theorem union_pi : (s₁ ∪ s₂).pi t = s₁.pi t ∩ s₂.pi t := by #align set.union_pi Set.union_pi theorem union_pi_inter - (ht₁ : ∀ (i) (_ : i ∉ s₁), t₁ i = univ) (ht₂ : ∀ (i) (_ : i ∉ s₂), t₂ i = univ) : + (ht₁ : ∀ i ∉ s₁, t₁ i = univ) (ht₂ : ∀ i ∉ s₂, t₂ i = univ) : (s₁ ∪ s₂).pi (fun i ↦ t₁ i ∩ t₂ i) = s₁.pi t₁ ∩ s₂.pi t₂ := by ext x simp only [mem_pi, mem_union, mem_inter_iff] @@ -1019,7 +1019,7 @@ theorem update_preimage_pi [DecidableEq ι] {f : ∀ i, α i} (hi : i ∈ s) exact hf j hj h #align set.update_preimage_pi Set.update_preimage_pi -theorem update_preimage_univ_pi [DecidableEq ι] {f : ∀ i, α i} (hf : ∀ (j) (_ : j ≠ i), f j ∈ t j) : +theorem update_preimage_univ_pi [DecidableEq ι] {f : ∀ i, α i} (hf : ∀ j ≠ i, f j ∈ t j) : update f i ⁻¹' pi univ t = t i := update_preimage_pi (mem_univ i) fun j _ => hf j #align set.update_preimage_univ_pi Set.update_preimage_univ_pi diff --git a/Mathlib/Data/Set/UnionLift.lean b/Mathlib/Data/Set/UnionLift.lean index 9a3cae7b2affe..9fe2581f26e7b 100644 --- a/Mathlib/Data/Set/UnionLift.lean +++ b/Mathlib/Data/Set/UnionLift.lean @@ -50,14 +50,14 @@ simplify terms involving `iUnionLift`. -/ /-- Given a union of sets `iUnion S`, define a function on the Union by defining it on each component, and proving that it agrees on the intersections. -/ @[nolint unusedArguments] -noncomputable def iUnionLift (S : ι → Set α) (f : ∀ (i) (_ : S i), β) +noncomputable def iUnionLift (S : ι → Set α) (f : ∀ i, S i → β) (_ : ∀ (i j) (x : α) (hxi : x ∈ S i) (hxj : x ∈ S j), f i ⟨x, hxi⟩ = f j ⟨x, hxj⟩) (T : Set α) (hT : T ⊆ iUnion S) (x : T) : β := let i := Classical.indefiniteDescription _ (mem_iUnion.1 (hT x.prop)) f i ⟨x, i.prop⟩ #align set.Union_lift Set.iUnionLift -variable {S : ι → Set α} {f : ∀ (i) (_ : S i), β} +variable {S : ι → Set α} {f : ∀ i, S i → β} {hf : ∀ (i j) (x : α) (hxi : x ∈ S i) (hxj : x ∈ S j), f i ⟨x, hxi⟩ = f j ⟨x, hxj⟩} {T : Set α} {hT : T ⊆ iUnion S} (hT' : T = iUnion S) @@ -151,13 +151,13 @@ theorem iUnionLift_binary (dir : Directed (· ≤ ·) S) (op : T → T → T) (o end UnionLift -variable {S : ι → Set α} {f : ∀ (i) (_ : S i), β} +variable {S : ι → Set α} {f : ∀ i, S i → β} {hf : ∀ (i j) (x : α) (hxi : x ∈ S i) (hxj : x ∈ S j), f i ⟨x, hxi⟩ = f j ⟨x, hxj⟩} {hS : iUnion S = univ} /-- Glue together functions defined on each of a collection `S` of sets that cover a type. See also `Set.iUnionLift`. -/ -noncomputable def liftCover (S : ι → Set α) (f : ∀ (i) (_ : S i), β) +noncomputable def liftCover (S : ι → Set α) (f : ∀ i, S i → β) (hf : ∀ (i j) (x : α) (hxi : x ∈ S i) (hxj : x ∈ S j), f i ⟨x, hxi⟩ = f j ⟨x, hxj⟩) (hS : iUnion S = univ) (a : α) : β := iUnionLift S f hf univ hS.symm.subset ⟨a, trivial⟩ diff --git a/Mathlib/FieldTheory/Subfield.lean b/Mathlib/FieldTheory/Subfield.lean index dd2fd753336da..8b2acc302e4ad 100644 --- a/Mathlib/FieldTheory/Subfield.lean +++ b/Mathlib/FieldTheory/Subfield.lean @@ -666,8 +666,7 @@ instance : CompleteLattice (Subfield K) := /-- The `Subfield` generated by a set. -/ def closure (s : Set K) : Subfield K where - carrier := {z : K | ∃ (x : K) (_ : x ∈ Subring.closure s) (y : K) - (_ : y ∈ Subring.closure s), x / y = z} + carrier := {z : K | ∃ x ∈ Subring.closure s, ∃ y ∈ Subring.closure s, x / y = z} zero_mem' := ⟨0, Subring.zero_mem _, 1, Subring.one_mem _, div_one _⟩ one_mem' := ⟨1, Subring.one_mem _, 1, Subring.one_mem _, div_one _⟩ neg_mem' {x} := by diff --git a/Mathlib/GroupTheory/MonoidLocalization.lean b/Mathlib/GroupTheory/MonoidLocalization.lean index f049741d878f4..bc1d2dc6f6eb0 100644 --- a/Mathlib/GroupTheory/MonoidLocalization.lean +++ b/Mathlib/GroupTheory/MonoidLocalization.lean @@ -355,13 +355,13 @@ then `f` is defined on the whole `Localization S`. -/ for all `a b`, such that `r S (a, b) (c, d)` implies `f a b = f c d`, then `f` is defined on the whole `Localization S`."] def liftOn {p : Sort u} (x : Localization S) (f : M → S → p) - (H : ∀ {a c : M} {b d : S} (_ : r S (a, b) (c, d)), f a b = f c d) : p := + (H : ∀ {a c : M} {b d : S}, r S (a, b) (c, d) → f a b = f c d) : p := rec f (fun h ↦ (by simpa only [eq_rec_constant] using H h)) x #align localization.lift_on Localization.liftOn #align add_localization.lift_on AddLocalization.liftOn @[to_additive] -theorem liftOn_mk {p : Sort u} (f : ∀ (_a : M) (_b : S), p) (H) (a : M) (b : S) : +theorem liftOn_mk {p : Sort u} (f : M → S → p) (H) (a : M) (b : S) : liftOn (mk a b) f H = f a b := rfl #align localization.lift_on_mk Localization.liftOn_mk #align add_localization.lift_on_mk AddLocalization.liftOn_mk @@ -388,7 +388,7 @@ then `f` is defined on the whole `Localization S`. -/ for all `x` and `y`, such that `r S x x'` and `r S y y'` implies `f x y = f x' y'`, then `f` is defined on the whole `Localization S`."] def liftOn₂ {p : Sort u} (x y : Localization S) (f : M → S → M → S → p) - (H : ∀ {a a' b b' c c' d d'} (_ : r S (a, b) (a', b')) (_ : r S (c, d) (c', d')), + (H : ∀ {a a' b b' c c' d d'}, r S (a, b) (a', b') → r S (c, d) (c', d') → f a b c d = f a' b' c' d') : p := liftOn x (fun a b ↦ liftOn y (f a b) fun hy ↦ H ((r S).refl _) hy) fun hx ↦ induction_on y fun ⟨_, _⟩ ↦ H hx ((r S).refl _) @@ -1660,7 +1660,7 @@ theorem mk_eq_monoidOf_mk' : mk = (monoidOf S).mk' := universe u @[to_additive (attr := simp)] -theorem liftOn_mk' {p : Sort u} (f : ∀ (_ : M) (_ : S), p) (H) (a : M) (b : S) : +theorem liftOn_mk' {p : Sort u} (f : M → S → p) (H) (a : M) (b : S) : liftOn ((monoidOf S).mk' a b) f H = f a b := by rw [← mk_eq_monoidOf_mk', liftOn_mk] #align localization.lift_on_mk' Localization.liftOn_mk' #align add_localization.lift_on_mk' AddLocalization.liftOn_mk' @@ -1841,7 +1841,7 @@ instance : CommMonoidWithZero (Localization S) where simp only [← Localization.mk_zero y.2, mk_mul, mk_eq_mk_iff, mul_zero, zero_mul, r_of_eq] #align localization.mk_zero Localization.mk_zero -theorem liftOn_zero {p : Type*} (f : ∀ (_ : M) (_ : S), p) (H) : liftOn 0 f H = f 0 1 := by +theorem liftOn_zero {p : Type*} (f : M → S → p) (H) : liftOn 0 f H = f 0 1 := by rw [← mk_zero 1, liftOn_mk] #align localization.lift_on_zero Localization.liftOn_zero diff --git a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean index 22e11a5064d69..cce1fca207d71 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean @@ -257,7 +257,7 @@ theorem SameCycle.exists_pow_eq' [Finite α] : SameCycle f x y → ∃ i < order #align equiv.perm.same_cycle.exists_pow_eq' Equiv.Perm.SameCycle.exists_pow_eq' theorem SameCycle.exists_pow_eq'' [Finite α] (h : SameCycle f x y) : - ∃ (i : ℕ) (_ : 0 < i) (_ : i ≤ orderOf f), (f ^ i) x = y := by + ∃ i : ℕ, 0 < i ∧ i ≤ orderOf f ∧ (f ^ i) x = y := by classical obtain ⟨_ | i, hi, rfl⟩ := h.exists_pow_eq' · refine' ⟨orderOf f, orderOf_pos f, le_rfl, _⟩ @@ -1187,16 +1187,14 @@ theorem isCycleOn_support_cycleOf (f : Perm α) (x : α) : f.IsCycleOn (f.cycleO #align equiv.perm.is_cycle_on_support_cycle_of Equiv.Perm.isCycleOn_support_cycleOf theorem SameCycle.exists_pow_eq_of_mem_support (h : SameCycle f x y) (hx : x ∈ f.support) : - ∃ (i : ℕ) (_ : i < (f.cycleOf x).support.card), (f ^ i) x = y := by + ∃ i < (f.cycleOf x).support.card, (f ^ i) x = y := by rw [mem_support] at hx - have := Equiv.Perm.IsCycleOn.exists_pow_eq (b := y) (f.isCycleOn_support_cycleOf x) + exact Equiv.Perm.IsCycleOn.exists_pow_eq (b := y) (f.isCycleOn_support_cycleOf x) (by rw [mem_support_cycleOf_iff' hx]) (by rwa [mem_support_cycleOf_iff' hx]) - simp_rw [← exists_prop] at this - exact this #align equiv.perm.same_cycle.exists_pow_eq_of_mem_support Equiv.Perm.SameCycle.exists_pow_eq_of_mem_support theorem SameCycle.exists_pow_eq (f : Perm α) (h : SameCycle f x y) : - ∃ (i : ℕ) (_ : 0 < i) (_ : i ≤ (f.cycleOf x).support.card + 1), (f ^ i) x = y := by + ∃ i : ℕ, 0 < i ∧ i ≤ (f.cycleOf x).support.card + 1 ∧ (f ^ i) x = y := by by_cases hx : x ∈ f.support · obtain ⟨k, hk, hk'⟩ := h.exists_pow_eq_of_mem_support hx cases' k with k @@ -1277,8 +1275,8 @@ def cycleFactorsAux [Fintype α] : theorem mem_list_cycles_iff {α : Type*} [Finite α] {l : List (Perm α)} (h1 : ∀ σ : Perm α, σ ∈ l → σ.IsCycle) (h2 : l.Pairwise Disjoint) {σ : Perm α} : - σ ∈ l ↔ σ.IsCycle ∧ ∀ (a : α) (_ : σ a ≠ a), σ a = l.prod a := by - suffices σ.IsCycle → (σ ∈ l ↔ ∀ (a : α) (_ : σ a ≠ a), σ a = l.prod a) by + σ ∈ l ↔ σ.IsCycle ∧ ∀ a, σ a ≠ a → σ a = l.prod a := by + suffices σ.IsCycle → (σ ∈ l ↔ ∀ a, σ a ≠ a → σ a = l.prod a) by exact ⟨fun hσ => ⟨h1 σ hσ, (this (h1 σ hσ)).mp hσ⟩, fun hσ => (this hσ.1).mpr hσ.2⟩ intro h3 classical diff --git a/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean b/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean index 7bdbd0643daf3..262d106fbf277 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean @@ -133,7 +133,7 @@ variable [DecidableEq α] (s s' : Cycle α) /-- A cycle `s : Cycle α`, given `Nodup s` can be interpreted as an `Equiv.Perm α` where each element in the list is permuted to the next one, defined as `formPerm`. -/ -def formPerm : ∀ (s : Cycle α) (_ : Nodup s), Equiv.Perm α := +def formPerm : ∀ s : Cycle α, Nodup s → Equiv.Perm α := fun s => Quotient.hrecOn s (fun l _ => List.formPerm l) fun l₁ l₂ (h : l₁ ~r l₂) => by apply Function.hfunext ext diff --git a/Mathlib/GroupTheory/Subgroup/Basic.lean b/Mathlib/GroupTheory/Subgroup/Basic.lean index b07dd12d3c50c..38f49c32bd077 100644 --- a/Mathlib/GroupTheory/Subgroup/Basic.lean +++ b/Mathlib/GroupTheory/Subgroup/Basic.lean @@ -645,7 +645,7 @@ protected theorem zpow_mem {x : G} (hx : x ∈ K) : ∀ n : ℤ, x ^ n ∈ K := /-- Construct a subgroup from a nonempty set that is closed under division. -/ @[to_additive "Construct a subgroup from a nonempty set that is closed under subtraction"] -def ofDiv (s : Set G) (hsn : s.Nonempty) (hs : ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), x * y⁻¹ ∈ s) : +def ofDiv (s : Set G) (hsn : s.Nonempty) (hs : ∀ᵉ (x ∈ s) (y ∈ s), x * y⁻¹ ∈ s) : Subgroup G := have one_mem : (1 : G) ∈ s := by let ⟨x, hx⟩ := hsn diff --git a/Mathlib/LinearAlgebra/FreeModule/PID.lean b/Mathlib/LinearAlgebra/FreeModule/PID.lean index 36e5a6333fcec..5cc56d4b87326 100644 --- a/Mathlib/LinearAlgebra/FreeModule/PID.lean +++ b/Mathlib/LinearAlgebra/FreeModule/PID.lean @@ -359,7 +359,7 @@ noncomputable def Module.basisOfFiniteTypeTorsionFree [Fintype ι] {s : ι → M let I : Set ι := this.choose obtain ⟨indepI : LinearIndependent R (s ∘ (fun x => x) : I → M), hI : - ∀ (i) (_ : i ∉ I), ∃ a : R, a ≠ 0 ∧ a • s i ∈ span R (s '' I)⟩ := + ∀ i ∉ I, ∃ a : R, a ≠ 0 ∧ a • s i ∈ span R (s '' I)⟩ := this.choose_spec let N := span R (range <| (s ∘ (fun x => x) : I → M)) -- same as `span R (s '' I)` but more convenient diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index 29fe26baa1bd8..5bc4c3d2c5aaf 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -152,7 +152,7 @@ theorem linearIndependent_iff' : theorem linearIndependent_iff'' : LinearIndependent R v ↔ - ∀ (s : Finset ι) (g : ι → R) (_hg : ∀ (i) (_ : i ∉ s), g i = 0), + ∀ (s : Finset ι) (g : ι → R), (∀ i ∉ s, g i = 0) → ∑ i in s, g i • v i = 0 → ∀ i, g i = 0 := by classical exact linearIndependent_iff'.trans @@ -470,7 +470,7 @@ theorem LinearIndependent.mono {t s : Set M} (h : t ⊆ s) : #align linear_independent.mono LinearIndependent.mono theorem linearIndependent_of_finite (s : Set M) - (H : ∀ (t) (_ : t ⊆ s), Set.Finite t → LinearIndependent R (fun x => x : t → M)) : + (H : ∀ t ⊆ s, Set.Finite t → LinearIndependent R (fun x => x : t → M)) : LinearIndependent R (fun x => x : s → M) := linearIndependent_subtype.2 fun l hl => linearIndependent_subtype.1 (H _ hl (Finset.finite_toSet _)) l (Subset.refl _) diff --git a/Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean b/Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean index 081ad262a017c..bebab512402ea 100644 --- a/Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean +++ b/Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean @@ -113,7 +113,7 @@ open Matrix /-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`), not just fields, but it's easier to prove it for the field of fractions first. -/ theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} : - (∃ (v : _) (_ : v ≠ 0), M.mulVec v = 0) ↔ M.det = 0 := by + (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by constructor · rintro ⟨v, hv, mul_eq⟩ contrapose! hv @@ -135,8 +135,8 @@ theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : theorem exists_mulVec_eq_zero_iff' {A : Type*} (K : Type*) [DecidableEq n] [CommRing A] [Nontrivial A] [Field K] [Algebra A K] [IsFractionRing A K] {M : Matrix n n A} : - (∃ (v : _) (_ : v ≠ 0), M.mulVec v = 0) ↔ M.det = 0 := by - have : (∃ (v : _) (_ : v ≠ 0), mulVec ((algebraMap A K).mapMatrix M) v = 0) ↔ _ := + (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by + have : (∃ v ≠ 0, mulVec ((algebraMap A K).mapMatrix M) v = 0) ↔ _ := exists_mulVec_eq_zero_iff_aux rw [← RingHom.map_det, IsFractionRing.to_map_eq_zero_iff] at this refine' Iff.trans _ this; constructor <;> rintro ⟨v, hv, mul_eq⟩ @@ -169,19 +169,19 @@ theorem exists_mulVec_eq_zero_iff' {A : Type*} (K : Type*) [DecidableEq n] [Comm #align matrix.exists_mul_vec_eq_zero_iff' Matrix.exists_mulVec_eq_zero_iff' theorem exists_mulVec_eq_zero_iff {A : Type*} [DecidableEq n] [CommRing A] [IsDomain A] - {M : Matrix n n A} : (∃ (v : _) (_ : v ≠ 0), M.mulVec v = 0) ↔ M.det = 0 := + {M : Matrix n n A} : (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := exists_mulVec_eq_zero_iff' (FractionRing A) #align matrix.exists_mul_vec_eq_zero_iff Matrix.exists_mulVec_eq_zero_iff theorem exists_vecMul_eq_zero_iff {A : Type*} [DecidableEq n] [CommRing A] [IsDomain A] - {M : Matrix n n A} : (∃ (v : _) (_ : v ≠ 0), M.vecMul v = 0) ↔ M.det = 0 := by + {M : Matrix n n A} : (∃ v ≠ 0, M.vecMul v = 0) ↔ M.det = 0 := by simpa only [← M.det_transpose, ← mulVec_transpose] using exists_mulVec_eq_zero_iff #align matrix.exists_vec_mul_eq_zero_iff Matrix.exists_vecMul_eq_zero_iff theorem nondegenerate_iff_det_ne_zero {A : Type*} [DecidableEq n] [CommRing A] [IsDomain A] {M : Matrix n n A} : Nondegenerate M ↔ M.det ≠ 0 := by - refine' Iff.trans _ (not_iff_not.mpr exists_vecMul_eq_zero_iff) - simp only [not_exists] + rw [ne_eq, ← exists_vecMul_eq_zero_iff] + push_neg constructor · intro hM v hv hMv obtain ⟨w, hwMv⟩ := hM.exists_not_ortho_of_ne_zero hv diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Metrizable.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Metrizable.lean index 4c5345d85f132..976efcb85a719 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Metrizable.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Metrizable.lean @@ -146,8 +146,7 @@ theorem measurable_of_tendsto_metrizable_ae {μ : Measure α} [μ.IsComplete] {f theorem measurable_limit_of_tendsto_metrizable_ae {ι} [Countable ι] [Nonempty ι] {μ : Measure α} {f : ι → α → β} {L : Filter ι} [L.IsCountablyGenerated] (hf : ∀ n, AEMeasurable (f n) μ) (h_ae_tendsto : ∀ᵐ x ∂μ, ∃ l : β, Tendsto (fun n => f n x) L (𝓝 l)) : - ∃ (f_lim : α → β) (hf_lim_meas : Measurable f_lim), - ∀ᵐ x ∂μ, Tendsto (fun n => f n x) L (𝓝 (f_lim x)) := by + ∃ f_lim : α → β, Measurable f_lim ∧ ∀ᵐ x ∂μ, Tendsto (fun n => f n x) L (𝓝 (f_lim x)) := by inhabit ι rcases eq_or_neBot L with (rfl | hL) · exact ⟨(hf default).mk _, (hf default).measurable_mk, eventually_of_forall fun x => tendsto_bot⟩ diff --git a/Mathlib/MeasureTheory/Constructions/Cylinders.lean b/Mathlib/MeasureTheory/Constructions/Cylinders.lean index 70c5c7342862f..861593ce0149f 100644 --- a/Mathlib/MeasureTheory/Constructions/Cylinders.lean +++ b/Mathlib/MeasureTheory/Constructions/Cylinders.lean @@ -66,11 +66,11 @@ theorem isPiSystem_squareCylinders {C : ∀ i, Set (Set (α i))} (hC : ∀ i, Is let t₂' := s₂.piecewise t₂ (fun i ↦ univ) have h1 : ∀ i ∈ (s₁ : Set ι), t₁ i = t₁' i := fun i hi ↦ (Finset.piecewise_eq_of_mem _ _ _ hi).symm - have h1' : ∀ (i) (_ : i ∉ (s₁ : Set ι)), t₁' i = univ := + have h1' : ∀ i ∉ (s₁ : Set ι), t₁' i = univ := fun i hi ↦ Finset.piecewise_eq_of_not_mem _ _ _ hi have h2 : ∀ i ∈ (s₂ : Set ι), t₂ i = t₂' i := fun i hi ↦ (Finset.piecewise_eq_of_mem _ _ _ hi).symm - have h2' : ∀ (i) (_ : i ∉ (s₂ : Set ι)), t₂' i = univ := + have h2' : ∀ i ∉ (s₂ : Set ι), t₂' i = univ := fun i hi ↦ Finset.piecewise_eq_of_not_mem _ _ _ hi rw [Set.pi_congr rfl h1, Set.pi_congr rfl h2, ← union_pi_inter h1' h2'] refine ⟨s₁ ∪ s₂, fun i ↦ t₁' i ∩ t₂' i, ?_, ?_⟩ @@ -270,8 +270,8 @@ variable [∀ i, MeasurableSpace (α i)] {s t : Set (∀ i, α i)} @[simp] theorem mem_measurableCylinders (t : Set (∀ i, α i)) : - t ∈ measurableCylinders α ↔ ∃ (s S : _) (_ : MeasurableSet S), t = cylinder s S := by - simp_rw [measurableCylinders, mem_iUnion, mem_singleton_iff] + t ∈ measurableCylinders α ↔ ∃ s S, MeasurableSet S ∧ t = cylinder s S := by + simp_rw [measurableCylinders, mem_iUnion, exists_prop, mem_singleton_iff] /-- A finset `s` such that `t = cylinder s S`. `S` is given by `measurableCylinders.set`. -/ noncomputable def measurableCylinders.finset (ht : t ∈ measurableCylinders α) : Finset ι := @@ -284,11 +284,11 @@ def measurableCylinders.set (ht : t ∈ measurableCylinders α) : theorem measurableCylinders.measurableSet (ht : t ∈ measurableCylinders α) : MeasurableSet (measurableCylinders.set ht) := - ((mem_measurableCylinders t).mp ht).choose_spec.choose_spec.choose + ((mem_measurableCylinders t).mp ht).choose_spec.choose_spec.left theorem measurableCylinders.eq_cylinder (ht : t ∈ measurableCylinders α) : t = cylinder (measurableCylinders.finset ht) (measurableCylinders.set ht) := - ((mem_measurableCylinders t).mp ht).choose_spec.choose_spec.choose_spec + ((mem_measurableCylinders t).mp ht).choose_spec.choose_spec.right theorem cylinder_mem_measurableCylinders (s : Finset ι) (S : Set (∀ i : s, α i)) (hS : MeasurableSet S) : diff --git a/Mathlib/MeasureTheory/Function/Egorov.lean b/Mathlib/MeasureTheory/Function/Egorov.lean index b1d2ef6868423..b45f6552a7992 100644 --- a/Mathlib/MeasureTheory/Function/Egorov.lean +++ b/Mathlib/MeasureTheory/Function/Egorov.lean @@ -47,9 +47,8 @@ def notConvergentSeq [Preorder ι] (f : ι → α → β) (g : α → β) (n : variable {n : ℕ} {i j : ι} {s : Set α} {ε : ℝ} {f : ι → α → β} {g : α → β} theorem mem_notConvergentSeq_iff [Preorder ι] {x : α} : - x ∈ notConvergentSeq f g n j ↔ ∃ (k : _) (_ : j ≤ k), 1 / (n + 1 : ℝ) < dist (f k x) (g x) := by - simp_rw [notConvergentSeq, Set.mem_iUnion] - rfl + x ∈ notConvergentSeq f g n j ↔ ∃ k ≥ j, 1 / (n + 1 : ℝ) < dist (f k x) (g x) := by + simp_rw [notConvergentSeq, Set.mem_iUnion, exists_prop]; rfl #align measure_theory.egorov.mem_not_convergent_seq_iff MeasureTheory.Egorov.mem_notConvergentSeq_iff theorem notConvergentSeq_antitone [Preorder ι] : Antitone (notConvergentSeq f g n) := @@ -200,8 +199,7 @@ an arbitrarily small set. -/ theorem tendstoUniformlyOn_of_ae_tendsto (hf : ∀ n, StronglyMeasurable (f n)) (hg : StronglyMeasurable g) (hsm : MeasurableSet s) (hs : μ s ≠ ∞) (hfg : ∀ᵐ x ∂μ, x ∈ s → Tendsto (fun n => f n x) atTop (𝓝 (g x))) {ε : ℝ} (hε : 0 < ε) : - ∃ (t : _) (_ : t ⊆ s), - MeasurableSet t ∧ μ t ≤ ENNReal.ofReal ε ∧ TendstoUniformlyOn f g atTop (s \ t) := + ∃ t ⊆ s, MeasurableSet t ∧ μ t ≤ ENNReal.ofReal ε ∧ TendstoUniformlyOn f g atTop (s \ t) := ⟨Egorov.iUnionNotConvergentSeq hε hf hg hsm hs hfg, Egorov.iUnionNotConvergentSeq_subset hε hf hg hsm hs hfg, Egorov.iUnionNotConvergentSeq_measurableSet hε hf hg hsm hs hfg, diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean index 767033402dcb6..462a63efeb4ad 100644 --- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean +++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean @@ -907,12 +907,12 @@ theorem stronglyMeasurable_in_set {m : MeasurableSpace α} [TopologicalSpace β] {f : α → β} (hs : MeasurableSet s) (hf : StronglyMeasurable f) (hf_zero : ∀ x, x ∉ s → f x = 0) : ∃ fs : ℕ → α →ₛ β, - (∀ x, Tendsto (fun n => fs n x) atTop (𝓝 (f x))) ∧ ∀ (x) (_ : x ∉ s) (n), fs n x = 0 := by + (∀ x, Tendsto (fun n => fs n x) atTop (𝓝 (f x))) ∧ ∀ x ∉ s, ∀ n, fs n x = 0 := by let g_seq_s : ℕ → @SimpleFunc α m β := fun n => (hf.approx n).restrict s have hg_eq : ∀ x ∈ s, ∀ n, g_seq_s n x = hf.approx n x := by intro x hx n rw [SimpleFunc.coe_restrict _ hs, Set.indicator_of_mem hx] - have hg_zero : ∀ (x) (_ : x ∉ s), ∀ n, g_seq_s n x = 0 := by + have hg_zero : ∀ x ∉ s, ∀ n, g_seq_s n x = 0 := by intro x hx n rw [SimpleFunc.coe_restrict _ hs, Set.indicator_of_not_mem hx] refine' ⟨g_seq_s, fun x => _, hg_zero⟩ @@ -929,7 +929,7 @@ on `s` is `m`-strongly-measurable, then `f` is also `m₂`-strongly-measurable. theorem stronglyMeasurable_of_measurableSpace_le_on {α E} {m m₂ : MeasurableSpace α} [TopologicalSpace E] [Zero E] {s : Set α} {f : α → E} (hs_m : MeasurableSet[m] s) (hs : ∀ t, MeasurableSet[m] (s ∩ t) → MeasurableSet[m₂] (s ∩ t)) - (hf : StronglyMeasurable[m] f) (hf_zero : ∀ (x) (_ : x ∉ s), f x = 0) : + (hf : StronglyMeasurable[m] f) (hf_zero : ∀ x ∉ s, f x = 0) : StronglyMeasurable[m₂] f := by have hs_m₂ : MeasurableSet[m₂] s := by rw [← Set.inter_univ s] @@ -1699,7 +1699,7 @@ theorem _root_.exists_stronglyMeasurable_limit_of_tendsto_ae [PseudoMetrizableSp ∀ᵐ x ∂μ, Tendsto (fun n => f n x) atTop (𝓝 (f_lim x)) := by borelize β obtain ⟨g, _, hg⟩ : - ∃ (g : α → β) (_ : Measurable g), ∀ᵐ x ∂μ, Tendsto (fun n => f n x) atTop (𝓝 (g x)) := + ∃ g : α → β, Measurable g ∧ ∀ᵐ x ∂μ, Tendsto (fun n => f n x) atTop (𝓝 (g x)) := measurable_limit_of_tendsto_metrizable_ae (fun n => (hf n).aemeasurable) h_ae_tendsto have Hg : AEStronglyMeasurable g μ := aestronglyMeasurable_of_tendsto_ae _ hf hg refine' ⟨Hg.mk g, Hg.stronglyMeasurable_mk, _⟩ diff --git a/Mathlib/MeasureTheory/Measure/Doubling.lean b/Mathlib/MeasureTheory/Measure/Doubling.lean index 8e059bccb4200..af2ab9da46818 100644 --- a/Mathlib/MeasureTheory/Measure/Doubling.lean +++ b/Mathlib/MeasureTheory/Measure/Doubling.lean @@ -114,7 +114,7 @@ theorem one_le_scalingConstantOf (K : ℝ) : 1 ≤ scalingConstantOf μ K := theorem eventually_measure_mul_le_scalingConstantOf_mul (K : ℝ) : ∃ R : ℝ, 0 < R ∧ - ∀ (x t r) (_ : t ∈ Ioc 0 K) (_ : r ≤ R), + ∀ x t r, t ∈ Ioc 0 K → r ≤ R → μ (closedBall x (t * r)) ≤ scalingConstantOf μ K * μ (closedBall x r) := by have h := Classical.choose_spec (exists_eventually_forall_measure_closedBall_le_mul μ K) rcases mem_nhdsWithin_Ioi_iff_exists_Ioc_subset.1 h with ⟨R, Rpos, hR⟩ diff --git a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean index df3842c6384b2..1d60a9f49d75a 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean @@ -46,7 +46,7 @@ def parallelepiped (v : ι → E) : Set E := #align parallelepiped parallelepiped theorem mem_parallelepiped_iff (v : ι → E) (x : E) : - x ∈ parallelepiped v ↔ ∃ (t : ι → ℝ) (_ht : t ∈ Icc (0 : ι → ℝ) 1), x = ∑ i, t i • v i := by + x ∈ parallelepiped v ↔ ∃ t ∈ Icc (0 : ι → ℝ) 1, x = ∑ i, t i • v i := by simp [parallelepiped, eq_comm] #align mem_parallelepiped_iff mem_parallelepiped_iff diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index 3bcad6db9513c..52424750ef4a7 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -414,7 +414,7 @@ theorem tsum_measure_le_measure_univ {s : ι → Set α} (hs : ∀ i, Measurable one of the intersections `s i ∩ s j` is not empty. -/ theorem exists_nonempty_inter_of_measure_univ_lt_tsum_measure {m : MeasurableSpace α} (μ : Measure α) {s : ι → Set α} (hs : ∀ i, MeasurableSet (s i)) - (H : μ (univ : Set α) < ∑' i, μ (s i)) : ∃ (i j : _) (_h : i ≠ j), (s i ∩ s j).Nonempty := by + (H : μ (univ : Set α) < ∑' i, μ (s i)) : ∃ i j, i ≠ j ∧ (s i ∩ s j).Nonempty := by contrapose! H apply tsum_measure_le_measure_univ hs intro i j hij @@ -504,7 +504,7 @@ sets is the infimum of the measures. -/ theorem measure_iInter_eq_iInf [Countable ι] {s : ι → Set α} (h : ∀ i, MeasurableSet (s i)) (hd : Directed (· ⊇ ·) s) (hfin : ∃ i, μ (s i) ≠ ∞) : μ (⋂ i, s i) = ⨅ i, μ (s i) := by rcases hfin with ⟨k, hk⟩ - have : ∀ (t) (_ : t ⊆ s k), μ t ≠ ∞ := fun t ht => ne_top_of_le_ne_top hk (measure_mono ht) + have : ∀ t ⊆ s k, μ t ≠ ∞ := fun t ht => ne_top_of_le_ne_top hk (measure_mono ht) rw [← ENNReal.sub_sub_cancel hk (iInf_le _ k), ENNReal.sub_iInf, ← ENNReal.sub_sub_cancel hk (measure_mono (iInter_subset _ k)), ← measure_diff (iInter_subset _ k) (MeasurableSet.iInter h) (this _ (iInter_subset _ k)), diff --git a/Mathlib/MeasureTheory/Measure/Restrict.lean b/Mathlib/MeasureTheory/Measure/Restrict.lean index 79e243edbdd94..ae91cfbedab67 100644 --- a/Mathlib/MeasureTheory/Measure/Restrict.lean +++ b/Mathlib/MeasureTheory/Measure/Restrict.lean @@ -348,7 +348,7 @@ theorem restrict_eq_self_of_ae_mem {_m0 : MeasurableSpace α} ⦃s : Set α⦄ #align measure_theory.measure.restrict_eq_self_of_ae_mem MeasureTheory.Measure.restrict_eq_self_of_ae_mem theorem restrict_congr_meas (hs : MeasurableSet s) : - μ.restrict s = ν.restrict s ↔ ∀ (t) (_ : t ⊆ s), MeasurableSet t → μ t = ν t := + μ.restrict s = ν.restrict s ↔ ∀ t ⊆ s, MeasurableSet t → μ t = ν t := ⟨fun H t hts ht => by rw [← inter_eq_self_of_subset_left hts, ← restrict_apply ht, H, restrict_apply ht], fun H => ext fun t ht => by diff --git a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean index 32477fa432965..e909e9fc83d97 100644 --- a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean @@ -1156,7 +1156,7 @@ to use. This is equivalent to the definition which requires measurability. To pr `MutuallySingular` with the measurability condition, use `MeasureTheory.VectorMeasure.MutuallySingular.mk`. -/ def MutuallySingular (v : VectorMeasure α M) (w : VectorMeasure α N) : Prop := - ∃ s : Set α, MeasurableSet s ∧ (∀ (t) (_ : t ⊆ s), v t = 0) ∧ ∀ (t) (_ : t ⊆ sᶜ), w t = 0 + ∃ s : Set α, MeasurableSet s ∧ (∀ t ⊆ s, v t = 0) ∧ ∀ (t) (_ : t ⊆ sᶜ), w t = 0 #align measure_theory.vector_measure.mutually_singular MeasureTheory.VectorMeasure.MutuallySingular @[inherit_doc VectorMeasure.MutuallySingular] @@ -1166,7 +1166,7 @@ namespace MutuallySingular variable {v v₁ v₂ : VectorMeasure α M} {w w₁ w₂ : VectorMeasure α N} -theorem mk (s : Set α) (hs : MeasurableSet s) (h₁ : ∀ (t) (_ : t ⊆ s), MeasurableSet t → v t = 0) +theorem mk (s : Set α) (hs : MeasurableSet s) (h₁ : ∀ t ⊆ s, MeasurableSet t → v t = 0) (h₂ : ∀ (t) (_ : t ⊆ sᶜ), MeasurableSet t → w t = 0) : v ⟂ᵥ w := by refine' ⟨s, hs, fun t hst => _, fun t hst => _⟩ <;> by_cases ht : MeasurableSet t · exact h₁ t hst ht diff --git a/Mathlib/MeasureTheory/PiSystem.lean b/Mathlib/MeasureTheory/PiSystem.lean index 334b51f730e8d..741376c9bfa6e 100644 --- a/Mathlib/MeasureTheory/PiSystem.lean +++ b/Mathlib/MeasureTheory/PiSystem.lean @@ -164,7 +164,6 @@ theorem isPiSystem_Ici : IsPiSystem (range Ici : Set (Set α)) := @image_univ α _ Ici ▸ isPiSystem_image_Ici univ #align is_pi_system_Ici isPiSystem_Ici --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Ixx_mem {Ixx : α → α → Set α} {p : α → α → Prop} (Hne : ∀ {a b}, (Ixx a b).Nonempty → p a b) (Hi : ∀ {a₁ b₁ a₂ b₂}, Ixx a₁ b₁ ∩ Ixx a₂ b₂ = Ixx (max a₁ a₂) (min b₁ b₂)) (s t : Set α) : @@ -174,7 +173,6 @@ theorem isPiSystem_Ixx_mem {Ixx : α → α → Set α} {p : α → α → Prop} exact fun H => ⟨l₁ ⊔ l₂, sup_ind l₁ l₂ hls₁ hls₂, u₁ ⊓ u₂, inf_ind u₁ u₂ hut₁ hut₂, Hne H, rfl⟩ #align is_pi_system_Ixx_mem isPiSystem_Ixx_mem --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Ixx {Ixx : α → α → Set α} {p : α → α → Prop} (Hne : ∀ {a b}, (Ixx a b).Nonempty → p a b) (Hi : ∀ {a₁ b₁ a₂ b₂}, Ixx a₁ b₁ ∩ Ixx a₂ b₂ = Ixx (max a₁ a₂) (min b₁ b₂)) (f : ι → α) @@ -182,49 +180,41 @@ theorem isPiSystem_Ixx {Ixx : α → α → Set α} {p : α → α → Prop} simpa only [exists_range_iff] using isPiSystem_Ixx_mem (@Hne) (@Hi) (range f) (range g) #align is_pi_system_Ixx isPiSystem_Ixx --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Ioo_mem (s t : Set α) : IsPiSystem { S | ∃ᵉ (l ∈ s) (u ∈ t), l < u ∧ Ioo l u = S } := isPiSystem_Ixx_mem (Ixx := Ioo) (fun ⟨_, hax, hxb⟩ => hax.trans hxb) Ioo_inter_Ioo s t #align is_pi_system_Ioo_mem isPiSystem_Ioo_mem --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Ioo (f : ι → α) (g : ι' → α) : @IsPiSystem α { S | ∃ l u, f l < g u ∧ Ioo (f l) (g u) = S } := isPiSystem_Ixx (Ixx := Ioo) (fun ⟨_, hax, hxb⟩ => hax.trans hxb) Ioo_inter_Ioo f g #align is_pi_system_Ioo isPiSystem_Ioo --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Ioc_mem (s t : Set α) : IsPiSystem { S | ∃ᵉ (l ∈ s) (u ∈ t), l < u ∧ Ioc l u = S } := isPiSystem_Ixx_mem (Ixx := Ioc) (fun ⟨_, hax, hxb⟩ => hax.trans_le hxb) Ioc_inter_Ioc s t #align is_pi_system_Ioc_mem isPiSystem_Ioc_mem --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Ioc (f : ι → α) (g : ι' → α) : @IsPiSystem α { S | ∃ i j, f i < g j ∧ Ioc (f i) (g j) = S } := isPiSystem_Ixx (Ixx := Ioc) (fun ⟨_, hax, hxb⟩ => hax.trans_le hxb) Ioc_inter_Ioc f g #align is_pi_system_Ioc isPiSystem_Ioc --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Ico_mem (s t : Set α) : IsPiSystem { S | ∃ᵉ (l ∈ s) (u ∈ t), l < u ∧ Ico l u = S } := isPiSystem_Ixx_mem (Ixx := Ico) (fun ⟨_, hax, hxb⟩ => hax.trans_lt hxb) Ico_inter_Ico s t #align is_pi_system_Ico_mem isPiSystem_Ico_mem --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Ico (f : ι → α) (g : ι' → α) : @IsPiSystem α { S | ∃ i j, f i < g j ∧ Ico (f i) (g j) = S } := isPiSystem_Ixx (Ixx := Ico) (fun ⟨_, hax, hxb⟩ => hax.trans_lt hxb) Ico_inter_Ico f g #align is_pi_system_Ico isPiSystem_Ico --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Icc_mem (s t : Set α) : IsPiSystem { S | ∃ᵉ (l ∈ s) (u ∈ t), l ≤ u ∧ Icc l u = S } := isPiSystem_Ixx_mem (Ixx := Icc) nonempty_Icc.1 (by exact Icc_inter_Icc) s t #align is_pi_system_Icc_mem isPiSystem_Icc_mem --- porting note: change `∃ (_ : p l u), _` to `_ ∧ _` theorem isPiSystem_Icc (f : ι → α) (g : ι' → α) : @IsPiSystem α { S | ∃ i j, f i ≤ g j ∧ Icc (f i) (g j) = S } := isPiSystem_Ixx (Ixx := Icc) nonempty_Icc.1 (by exact Icc_inter_Icc) f g diff --git a/Mathlib/Order/Filter/Interval.lean b/Mathlib/Order/Filter/Interval.lean index 454c24edecf66..7cf0714fb66ac 100644 --- a/Mathlib/Order/Filter/Interval.lean +++ b/Mathlib/Order/Filter/Interval.lean @@ -128,7 +128,7 @@ protected theorem Tendsto.Ioo {l₁ l₂ : Filter α} [TendstoIxxClass Ioo l₁ #align filter.tendsto.Ioo Filter.Tendsto.Ioo theorem tendstoIxxClass_principal {s t : Set α} {Ixx : α → α → Set α} : - TendstoIxxClass Ixx (𝓟 s) (𝓟 t) ↔ ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), Ixx x y ⊆ t := + TendstoIxxClass Ixx (𝓟 s) (𝓟 t) ↔ ∀ᵉ (x ∈ s) (y ∈ s), Ixx x y ⊆ t := Iff.trans ⟨fun h => h.1, fun h => ⟨h⟩⟩ <| by simp only [smallSets_principal, prod_principal_principal, tendsto_principal_principal, forall_prod_set, mem_powerset_iff, mem_principal] diff --git a/Mathlib/Order/Zorn.lean b/Mathlib/Order/Zorn.lean index b2cb056d5eb51..be3f40fb861e5 100644 --- a/Mathlib/Order/Zorn.lean +++ b/Mathlib/Order/Zorn.lean @@ -113,7 +113,7 @@ theorem zorn_nonempty_preorder [Nonempty α] #align zorn_nonempty_preorder zorn_nonempty_preorder theorem zorn_preorder₀ (s : Set α) - (ih : ∀ (c) (_ : c ⊆ s), IsChain (· ≤ ·) c → ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) : + (ih : ∀ c ⊆ s, IsChain (· ≤ ·) c → ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) : ∃ m ∈ s, ∀ z ∈ s, m ≤ z → z ≤ m := let ⟨⟨m, hms⟩, h⟩ := @zorn_preorder s _ fun c hc => @@ -127,7 +127,7 @@ theorem zorn_preorder₀ (s : Set α) #align zorn_preorder₀ zorn_preorder₀ theorem zorn_nonempty_preorder₀ (s : Set α) - (ih : ∀ (c) (_ : c ⊆ s), IsChain (· ≤ ·) c → ∀ y ∈ c, ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) (x : α) + (ih : ∀ c ⊆ s, IsChain (· ≤ ·) c → ∀ y ∈ c, ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) (x : α) (hxs : x ∈ s) : ∃ m ∈ s, x ≤ m ∧ ∀ z ∈ s, m ≤ z → z ≤ m := by -- Porting note: the first three lines replace the following two lines in mathlib3. -- The mathlib3 `rcases` supports holes for proof obligations, this is not yet implemented in 4. @@ -143,7 +143,7 @@ theorem zorn_nonempty_preorder₀ (s : Set α) #align zorn_nonempty_preorder₀ zorn_nonempty_preorder₀ theorem zorn_nonempty_Ici₀ (a : α) - (ih : ∀ (c) (_ : c ⊆ Ici a), IsChain (· ≤ ·) c → ∀ y ∈ c, ∃ ub, ∀ z ∈ c, z ≤ ub) + (ih : ∀ c ⊆ Ici a, IsChain (· ≤ ·) c → ∀ y ∈ c, ∃ ub, ∀ z ∈ c, z ≤ ub) (x : α) (hax : a ≤ x) : ∃ m, x ≤ m ∧ ∀ z, m ≤ z → z ≤ m := by let ⟨m, _, hxm, hm⟩ := zorn_nonempty_preorder₀ (Ici a) (fun c hca hc y hy ↦ ?_) x hax · exact ⟨m, hxm, fun z hmz => hm _ (hax.trans <| hxm.trans hmz) hmz⟩ @@ -169,14 +169,14 @@ theorem zorn_nonempty_partialOrder [Nonempty α] #align zorn_nonempty_partial_order zorn_nonempty_partialOrder theorem zorn_partialOrder₀ (s : Set α) - (ih : ∀ (c) (_ : c ⊆ s), IsChain (· ≤ ·) c → ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) : + (ih : ∀ c ⊆ s, IsChain (· ≤ ·) c → ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) : ∃ m ∈ s, ∀ z ∈ s, m ≤ z → z = m := let ⟨m, hms, hm⟩ := zorn_preorder₀ s ih ⟨m, hms, fun z hzs hmz => (hm z hzs hmz).antisymm hmz⟩ #align zorn_partial_order₀ zorn_partialOrder₀ theorem zorn_nonempty_partialOrder₀ (s : Set α) - (ih : ∀ (c) (_ : c ⊆ s), IsChain (· ≤ ·) c → ∀ y ∈ c, ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) (x : α) + (ih : ∀ c ⊆ s, IsChain (· ≤ ·) 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, hm⟩ := zorn_nonempty_preorder₀ s ih x hxs ⟨m, hms, hxm, fun z hzs hmz => (hm z hzs hmz).antisymm hmz⟩ @@ -185,25 +185,25 @@ theorem zorn_nonempty_partialOrder₀ (s : Set α) end PartialOrder theorem zorn_subset (S : Set (Set α)) - (h : ∀ (c) (_ : c ⊆ S), IsChain (· ⊆ ·) c → ∃ ub ∈ S, ∀ s ∈ c, s ⊆ ub) : + (h : ∀ c ⊆ S, IsChain (· ⊆ ·) c → ∃ ub ∈ S, ∀ s ∈ c, s ⊆ ub) : ∃ m ∈ S, ∀ a ∈ S, m ⊆ a → a = m := zorn_partialOrder₀ S h #align zorn_subset zorn_subset theorem zorn_subset_nonempty (S : Set (Set α)) - (H : ∀ (c) (_ : c ⊆ S), IsChain (· ⊆ ·) c → c.Nonempty → ∃ ub ∈ S, ∀ s ∈ c, s ⊆ ub) (x) + (H : ∀ c ⊆ S, IsChain (· ⊆ ·) c → c.Nonempty → ∃ ub ∈ S, ∀ s ∈ c, s ⊆ ub) (x) (hx : x ∈ S) : ∃ m ∈ S, x ⊆ m ∧ ∀ a ∈ S, m ⊆ a → a = m := zorn_nonempty_partialOrder₀ _ (fun _ cS hc y yc => H _ cS hc ⟨y, yc⟩) _ hx #align zorn_subset_nonempty zorn_subset_nonempty theorem zorn_superset (S : Set (Set α)) - (h : ∀ (c) (_ : c ⊆ S), IsChain (· ⊆ ·) c → ∃ lb ∈ S, ∀ s ∈ c, lb ⊆ s) : + (h : ∀ c ⊆ S, IsChain (· ⊆ ·) c → ∃ lb ∈ S, ∀ s ∈ c, lb ⊆ s) : ∃ m ∈ S, ∀ a ∈ S, a ⊆ m → a = m := (@zorn_partialOrder₀ (Set α)ᵒᵈ _ S) fun c cS hc => h c cS hc.symm #align zorn_superset zorn_superset theorem zorn_superset_nonempty (S : Set (Set α)) - (H : ∀ (c) (_ : c ⊆ S), IsChain (· ⊆ ·) c → c.Nonempty → ∃ lb ∈ S, ∀ s ∈ c, lb ⊆ s) (x) + (H : ∀ c ⊆ S, IsChain (· ⊆ ·) c → c.Nonempty → ∃ lb ∈ S, ∀ s ∈ c, lb ⊆ s) (x) (hx : x ∈ S) : ∃ m ∈ S, m ⊆ x ∧ ∀ a ∈ S, a ⊆ m → a = m := @zorn_nonempty_partialOrder₀ (Set α)ᵒᵈ _ S (fun _ cS hc y yc => H _ cS hc.symm ⟨y, yc⟩) _ hx #align zorn_superset_nonempty zorn_superset_nonempty diff --git a/Mathlib/RingTheory/AlgebraicIndependent.lean b/Mathlib/RingTheory/AlgebraicIndependent.lean index 98273de99d574..ebec50746402c 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent.lean @@ -302,7 +302,7 @@ theorem algebraicIndependent_subtype {s : Set A} : #align algebraic_independent_subtype algebraicIndependent_subtype theorem algebraicIndependent_of_finite (s : Set A) - (H : ∀ (t) (_ : t ⊆ s), t.Finite → AlgebraicIndependent R ((↑) : t → A)) : + (H : ∀ t ⊆ s, t.Finite → AlgebraicIndependent R ((↑) : t → A)) : AlgebraicIndependent R ((↑) : s → A) := algebraicIndependent_subtype.2 fun p hp => algebraicIndependent_subtype.1 (H _ (mem_supported.1 hp) (Finset.finite_toSet _)) _ (by simp) diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 9c16f152210c5..0735503cab567 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -1279,7 +1279,7 @@ theorem Ideal.prod_le_prime {ι : Type*} {s : Finset ι} {f : ι → Ideal R} {P prime powers. -/ theorem IsDedekindDomain.inf_prime_pow_eq_prod {ι : Type*} (s : Finset ι) (f : ι → Ideal R) (e : ι → ℕ) (prime : ∀ i ∈ s, Prime (f i)) - (coprime : ∀ (i) (_ : i ∈ s) (j) (_ : j ∈ s), i ≠ j → f i ≠ f j) : + (coprime : ∀ᵉ (i ∈ s) (j ∈ s), i ≠ j → f i ≠ f j) : (s.inf fun i => f i ^ e i) = ∏ i in s, f i ^ e i := by letI := Classical.decEq ι revert prime coprime @@ -1368,7 +1368,7 @@ the product to a finite subset `s` of a potentially infinite indexing type `ι`. -/ noncomputable def IsDedekindDomain.quotientEquivPiOfFinsetProdEq {ι : Type*} {s : Finset ι} (I : Ideal R) (P : ι → Ideal R) (e : ι → ℕ) (prime : ∀ i ∈ s, Prime (P i)) - (coprime : ∀ (i) (_ : i ∈ s) (j) (_ : j ∈ s), i ≠ j → P i ≠ P j) + (coprime : ∀ᵉ (i ∈ s) (j ∈ s), i ≠ j → P i ≠ P j) (prod_eq : ∏ i in s, P i ^ e i = I) : R ⧸ I ≃+* ∀ i : s, R ⧸ P i ^ e i := IsDedekindDomain.quotientEquivPiOfProdEq I (fun i : s => P i) (fun i : s => e i) (fun i => prime i i.2) (fun i j h => coprime i i.2 j j.2 (Subtype.coe_injective.ne h)) @@ -1379,7 +1379,7 @@ noncomputable def IsDedekindDomain.quotientEquivPiOfFinsetProdEq {ι : Type*} {s we can choose a representative `y : R` such that `y ≡ x i (mod P i ^ e i)`.-/ theorem IsDedekindDomain.exists_representative_mod_finset {ι : Type*} {s : Finset ι} (P : ι → Ideal R) (e : ι → ℕ) (prime : ∀ i ∈ s, Prime (P i)) - (coprime : ∀ (i) (_ : i ∈ s) (j) (_ : j ∈ s), i ≠ j → P i ≠ P j) (x : ∀ i : s, R ⧸ P i ^ e i) : + (coprime : ∀ᵉ (i ∈ s) (j ∈ s), i ≠ j → P i ≠ P j) (x : ∀ i : s, R ⧸ P i ^ e i) : ∃ y, ∀ (i) (hi : i ∈ s), Ideal.Quotient.mk (P i ^ e i) y = x ⟨i, hi⟩ := by let f := IsDedekindDomain.quotientEquivPiOfFinsetProdEq _ P e prime coprime rfl obtain ⟨y, rfl⟩ := f.surjective x @@ -1391,7 +1391,7 @@ theorem IsDedekindDomain.exists_representative_mod_finset {ι : Type*} {s : Fins we can choose a representative `y : R` such that `y - x i ∈ P i ^ e i`.-/ theorem IsDedekindDomain.exists_forall_sub_mem_ideal {ι : Type*} {s : Finset ι} (P : ι → Ideal R) (e : ι → ℕ) (prime : ∀ i ∈ s, Prime (P i)) - (coprime : ∀ (i) (_ : i ∈ s) (j) (_ : j ∈ s), i ≠ j → P i ≠ P j) (x : s → R) : + (coprime : ∀ᵉ (i ∈ s) (j ∈ s), i ≠ j → P i ≠ P j) (x : s → R) : ∃ y, ∀ (i) (hi : i ∈ s), y - x ⟨i, hi⟩ ∈ P i ^ e i := by obtain ⟨y, hy⟩ := IsDedekindDomain.exists_representative_mod_finset P e prime coprime fun i => diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain.lean b/Mathlib/RingTheory/UniqueFactorizationDomain.lean index 0e8c734985288..a68222607f007 100644 --- a/Mathlib/RingTheory/UniqueFactorizationDomain.lean +++ b/Mathlib/RingTheory/UniqueFactorizationDomain.lean @@ -611,7 +611,7 @@ theorem normalizedFactors_irreducible {a : α} (ha : Irreducible a) : #align unique_factorization_monoid.normalized_factors_irreducible UniqueFactorizationMonoid.normalizedFactors_irreducible theorem normalizedFactors_eq_of_dvd (a : α) : - ∀ (p) (_ : p ∈ normalizedFactors a) (q) (_ : q ∈ normalizedFactors a), p ∣ q → p = q := by + ∀ᵉ (p ∈ normalizedFactors a) (q ∈ normalizedFactors a), p ∣ q → p = q := by intro p hp q hq hdvd convert normalize_eq_normalize hdvd ((prime_of_normalized_factor _ hp).irreducible.dvd_symm @@ -919,7 +919,7 @@ theorem dvd_of_dvd_mul_right_of_no_prime_factors {a b c : R} (ha : a ≠ 0) /-- If `a ≠ 0, b` are elements of a unique factorization domain, then dividing out their common factor `c'` gives `a'` and `b'` with no factors in common. -/ theorem exists_reduced_factors : - ∀ (a) (_ : a ≠ (0 : R)) (b), + ∀ a ≠ (0 : R), ∀ b, ∃ a' b' c', (∀ {d}, d ∣ a' → d ∣ b' → IsUnit d) ∧ c' * a' = a ∧ c' * b' = b := by haveI := Classical.propDecidable intro a @@ -1075,7 +1075,7 @@ open BigOperators theorem prime_pow_coprime_prod_of_coprime_insert [DecidableEq α] {s : Finset α} (i : α → ℕ) (p : α) (hps : p ∉ s) (is_prime : ∀ q ∈ insert p s, Prime q) - (is_coprime : ∀ (q) (_ : q ∈ insert p s) (q') (_ : q' ∈ insert p s), q ∣ q' → q = q') : + (is_coprime : ∀ᵉ (q ∈ insert p s) (q' ∈ insert p s), q ∣ q' → q = q') : ∀ q : α, q ∣ p ^ i p → (q ∣ ∏ p' in s, p' ^ i p') → IsUnit q := by have hp := is_prime _ (Finset.mem_insert_self _ _) refine' fun _ => no_factors_of_no_prime_factors (pow_ne_zero _ hp.ne_zero) _ @@ -1096,7 +1096,7 @@ and `P x ∧ P y` for coprime `x, y` implies `P (x * y)`, then `P` holds on a product of powers of distinct primes. -/ -- @[elab_as_elim] Porting note: commented out theorem induction_on_prime_power {P : α → Prop} (s : Finset α) (i : α → ℕ) - (is_prime : ∀ p ∈ s, Prime p) (is_coprime : ∀ (p) (_ : p ∈ s) (q) (_ : q ∈ s), p ∣ q → p = q) + (is_prime : ∀ p ∈ s, Prime p) (is_coprime : ∀ᵉ (p ∈ s) (q ∈ s), p ∣ q → p = q) (h1 : ∀ {x}, IsUnit x → P x) (hpr : ∀ {p} (i : ℕ), Prime p → P (p ^ i)) (hcp : ∀ {x y}, (∀ p, p ∣ x → p ∣ y → IsUnit p) → P x → P y → P (x * y)) : P (∏ p in s, p ^ i p) := by @@ -1137,7 +1137,7 @@ theorem induction_on_coprime {P : α → Prop} (a : α) (h0 : P 0) (h1 : ∀ {x} is multiplicative on coprime elements, then `f` is multiplicative on all products of primes. -/ -- @[elab_as_elim] Porting note: commented out theorem multiplicative_prime_power {f : α → β} (s : Finset α) (i j : α → ℕ) - (is_prime : ∀ p ∈ s, Prime p) (is_coprime : ∀ (p) (_ : p ∈ s) (q) (_ : q ∈ s), p ∣ q → p = q) + (is_prime : ∀ p ∈ s, Prime p) (is_coprime : ∀ᵉ (p ∈ s) (q ∈ s), p ∣ q → p = q) (h1 : ∀ {x y}, IsUnit y → f (x * y) = f x * f y) (hpr : ∀ {p} (i : ℕ), Prime p → f (p ^ i) = f p ^ i) (hcp : ∀ {x y}, (∀ p, p ∣ x → p ∣ y → IsUnit p) → f (x * y) = f x * f y) : @@ -1148,7 +1148,7 @@ theorem multiplicative_prime_power {f : α → β} (s : Finset α) (i j : α → have hpr_p := is_prime _ (Finset.mem_insert_self _ _) have hpr_s : ∀ p ∈ s, Prime p := fun p hp => is_prime _ (Finset.mem_insert_of_mem hp) have hcp_p := fun i => prime_pow_coprime_prod_of_coprime_insert i p hps is_prime is_coprime - have hcp_s : ∀ (p) (_ : p ∈ s) (q) (_ : q ∈ s), p ∣ q → p = q := fun p hp q hq => + have hcp_s : ∀ᵉ (p ∈ s) (q ∈ s), p ∣ q → p = q := fun p hp q hq => is_coprime p (Finset.mem_insert_of_mem hp) q (Finset.mem_insert_of_mem hq) rw [Finset.prod_insert hps, Finset.prod_insert hps, Finset.prod_insert hps, hcp (hcp_p _), hpr _ hpr_p, hcp (hcp_p _), hpr _ hpr_p, hcp (hcp_p (fun p => i p + j p)), hpr _ hpr_p, @@ -1508,7 +1508,7 @@ theorem eq_of_prod_eq_prod [Nontrivial α] {a b : FactorSet α} (h : a.prod = b. #align associates.eq_of_prod_eq_prod Associates.eq_of_prod_eq_prod theorem eq_factors_of_eq_counts {a b : Associates α} (ha : a ≠ 0) (hb : b ≠ 0) - (h : ∀ (p : Associates α) (_ : Irreducible p), p.count a.factors = p.count b.factors) : + (h : ∀ p : Associates α, Irreducible p → p.count a.factors = p.count b.factors) : a.factors = b.factors := by obtain ⟨sa, h_sa⟩ := factors_eq_some_iff_ne_zero.mpr ha obtain ⟨sb, h_sb⟩ := factors_eq_some_iff_ne_zero.mpr hb @@ -1837,7 +1837,7 @@ theorem dvd_count_pow [Nontrivial α] {a : Associates α} (ha : a ≠ 0) {p : As #align associates.dvd_count_pow Associates.dvd_count_pow theorem is_pow_of_dvd_count [Nontrivial α] {a : Associates α} (ha : a ≠ 0) {k : ℕ} - (hk : ∀ (p : Associates α) (_ : Irreducible p), k ∣ count p a.factors) : + (hk : ∀ p : Associates α, Irreducible p → k ∣ count p a.factors) : ∃ b : Associates α, a = b ^ k := by obtain ⟨a0, hz, rfl⟩ := exists_non_zero_rep ha rw [factors_mk a0 hz] at hk diff --git a/Mathlib/Topology/Algebra/FilterBasis.lean b/Mathlib/Topology/Algebra/FilterBasis.lean index f928475bfbc05..980f3b1320aef 100644 --- a/Mathlib/Topology/Algebra/FilterBasis.lean +++ b/Mathlib/Topology/Algebra/FilterBasis.lean @@ -409,8 +409,8 @@ But it turns out it's just easier to get it as a byproduct of the proof, so this quality-of-life improvement. -/ theorem _root_.ContinuousSMul.of_basis_zero {ι : Type*} [TopologicalRing R] [TopologicalSpace M] [TopologicalAddGroup M] {p : ι → Prop} {b : ι → Set M} (h : HasBasis (𝓝 0) p b) - (hsmul : ∀ {i}, p i → ∃ V ∈ 𝓝 (0 : R), ∃ (j : _) (_ : p j), V • b j ⊆ b i) - (hsmul_left : ∀ (x₀ : R) {i}, p i → ∃ (j : _) (_ : p j), b j ⊆ (fun x ↦ x₀ • x) ⁻¹' b i) + (hsmul : ∀ {i}, p i → ∃ V ∈ 𝓝 (0 : R), ∃ j, p j ∧ V • b j ⊆ b i) + (hsmul_left : ∀ (x₀ : R) {i}, p i → ∃ j, p j ∧ MapsTo (x₀ • ·) (b j) (b i)) (hsmul_right : ∀ (m₀ : M) {i}, p i → ∀ᶠ x in 𝓝 (0 : R), x • m₀ ∈ b i) : ContinuousSMul R M := by apply ContinuousSMul.of_nhds_zero · rw [h.tendsto_right_iff] diff --git a/Mathlib/Topology/Algebra/Semigroup.lean b/Mathlib/Topology/Algebra/Semigroup.lean index 0d1f978cd890a..e09e5b0da4d25 100644 --- a/Mathlib/Topology/Algebra/Semigroup.lean +++ b/Mathlib/Topology/Algebra/Semigroup.lean @@ -84,7 +84,7 @@ in some specified nonempty compact subsemigroup. -/ some specified nonempty compact additive subsemigroup."] theorem exists_idempotent_in_compact_subsemigroup {M} [Semigroup M] [TopologicalSpace M] [T2Space M] (continuous_mul_left : ∀ r : M, Continuous (· * r)) (s : Set M) (snemp : s.Nonempty) - (s_compact : IsCompact s) (s_add : ∀ (x) (_ : x ∈ s) (y) (_ : y ∈ s), x * y ∈ s) : + (s_compact : IsCompact s) (s_add : ∀ᵉ (x ∈ s) (y ∈ s), x * y ∈ s) : ∃ m ∈ s, m * m = m := by let M' := { m // m ∈ s } letI : Semigroup M' := diff --git a/Mathlib/Topology/Algebra/UniformFilterBasis.lean b/Mathlib/Topology/Algebra/UniformFilterBasis.lean index e55908867f4f3..52c514a6440e5 100644 --- a/Mathlib/Topology/Algebra/UniformFilterBasis.lean +++ b/Mathlib/Topology/Algebra/UniformFilterBasis.lean @@ -41,10 +41,10 @@ protected theorem uniformAddGroup : @UniformAddGroup G B.uniformSpace _ := theorem cauchy_iff {F : Filter G} : @Cauchy G B.uniformSpace F ↔ - F.NeBot ∧ ∀ U ∈ B, ∃ M ∈ F, ∀ (x) (_ : x ∈ M) (y) (_ : y ∈ M), y - x ∈ U := by + F.NeBot ∧ ∀ U ∈ B, ∃ M ∈ F, ∀ᵉ (x ∈ M) (y ∈ M), y - x ∈ U := by letI := B.uniformSpace haveI := B.uniformAddGroup - suffices F ×ˢ F ≤ uniformity G ↔ ∀ U ∈ B, ∃ M ∈ F, ∀ (x) (_ : x ∈ M) (y) (_ : y ∈ M), y - x ∈ U by + suffices F ×ˢ F ≤ uniformity G ↔ ∀ U ∈ B, ∃ M ∈ F, ∀ᵉ (x ∈ M) (y ∈ M), y - x ∈ U by constructor <;> rintro ⟨h', h⟩ <;> refine' ⟨h', _⟩ <;> [rwa [← this]; rwa [this]] rw [uniformity_eq_comap_nhds_zero G, ← map_le_iff_le_comap] change Tendsto _ _ _ ↔ _ diff --git a/Mathlib/Topology/Algebra/Valuation.lean b/Mathlib/Topology/Algebra/Valuation.lean index 48fa4f1db1a40..2c9d5c685d1a0 100644 --- a/Mathlib/Topology/Algebra/Valuation.lean +++ b/Mathlib/Topology/Algebra/Valuation.lean @@ -157,7 +157,7 @@ instance (priority := 100) : TopologicalRing R := (toUniformSpace_eq R Γ₀).symm ▸ v.subgroups_basis.toRingFilterBasis.isTopologicalRing theorem cauchy_iff {F : Filter R} : Cauchy F ↔ - F.NeBot ∧ ∀ γ : Γ₀ˣ, ∃ M ∈ F, ∀ (x) (_ : x ∈ M) (y) (_ : y ∈ M), (v (y - x) : Γ₀) < γ := by + F.NeBot ∧ ∀ γ : Γ₀ˣ, ∃ M ∈ F, ∀ᵉ (x ∈ M) (y ∈ M), (v (y - x) : Γ₀) < γ := by rw [toUniformSpace_eq, AddGroupFilterBasis.cauchy_iff] apply and_congr Iff.rfl simp_rw [Valued.v.subgroups_basis.mem_addGroupFilterBasis_iff] diff --git a/Mathlib/Topology/Bornology/Basic.lean b/Mathlib/Topology/Bornology/Basic.lean index 3e7fd908f0218..c7d11d2ea4a4e 100644 --- a/Mathlib/Topology/Bornology/Basic.lean +++ b/Mathlib/Topology/Bornology/Basic.lean @@ -91,10 +91,9 @@ and showing that they satisfy the appropriate conditions. -/ @[simps] def Bornology.ofBounded {α : Type*} (B : Set (Set α)) (empty_mem : ∅ ∈ B) - (subset_mem : ∀ s₁ (_ : s₁ ∈ B) s₂, s₂ ⊆ s₁ → s₂ ∈ B) - (union_mem : ∀ s₁ (_ : s₁ ∈ B) s₂ (_ : s₂ ∈ B), s₁ ∪ s₂ ∈ B) - (singleton_mem : ∀ x, {x} ∈ B) : Bornology α - where + (subset_mem : ∀ s₁ ∈ B, ∀ s₂ ⊆ s₁, s₂ ∈ B) + (union_mem : ∀ s₁ ∈ B, ∀ s₂ ∈ B, s₁ ∪ s₂ ∈ B) + (singleton_mem : ∀ x, {x} ∈ B) : Bornology α where cobounded' := { sets := { s : Set α | sᶜ ∈ B } univ_sets := by rwa [← compl_univ] at empty_mem @@ -114,8 +113,8 @@ and showing that they satisfy the appropriate conditions. -/ @[simps!] def Bornology.ofBounded' {α : Type*} (B : Set (Set α)) (empty_mem : ∅ ∈ B) - (subset_mem : ∀ s₁ (_ : s₁ ∈ B) s₂, s₂ ⊆ s₁ → s₂ ∈ B) - (union_mem : ∀ s₁ (_ : s₁ ∈ B) s₂ (_ : s₂ ∈ B), s₁ ∪ s₂ ∈ B) + (subset_mem : ∀ s₁ ∈ B, ∀ s₂ ⊆ s₁, s₂ ∈ B) + (union_mem : ∀ s₁ ∈ B, ∀ s₂ ∈ B, s₁ ∪ s₂ ∈ B) (sUnion_univ : ⋃₀ B = univ) : Bornology α := Bornology.ofBounded B empty_mem subset_mem union_mem fun x => by diff --git a/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean b/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean index 25a281e841988..059599d20a7a2 100644 --- a/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean +++ b/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean @@ -48,7 +48,7 @@ instance preserves_smaller_limits_toTopCat : a clopen set in one of the terms in the limit. -/ theorem exists_isClopen_of_cofiltered {U : Set C.pt} (hC : IsLimit C) (hU : IsClopen U) : - ∃ (j : J) (V : Set (F.obj j)) (_ : IsClopen V), U = C.π.app j ⁻¹' V := by + ∃ (j : J) (V : Set (F.obj j)), IsClopen V ∧ U = C.π.app j ⁻¹' V := by have := preserves_smaller_limits_toTopCat.{u, v} -- First, we have the topological basis of the cofiltered limit obtained by pulling back -- clopen sets from the factors in the limit. By continuity, all such sets are again clopen. @@ -93,8 +93,7 @@ theorem exists_isClopen_of_cofiltered {U : Set C.pt} (hC : IsLimit C) (hU : IsCl -- Pulling back all of the sets from the previous step to `F.obj j0` and taking a union, -- we obtain a clopen set in `F.obj j0` which works. obtain ⟨j0, hj0⟩ := IsCofiltered.inf_objs_exists (G.image j) - let f : ∀ (s : S) (_ : s ∈ G), j0 ⟶ j s := fun s hs => - (hj0 (Finset.mem_image.mpr ⟨s, hs, rfl⟩)).some + let f : ∀ s ∈ G, j0 ⟶ j s := fun s hs => (hj0 (Finset.mem_image.mpr ⟨s, hs, rfl⟩)).some let W : S → Set (F.obj j0) := fun s => if hs : s ∈ G then F.map (f s hs) ⁻¹' V s else Set.univ -- Conclude, using the `j0` and the clopen set of `F.obj j0` obtained above. refine' ⟨j0, ⋃ (s : S) (_ : s ∈ G), W s, _, _⟩ diff --git a/Mathlib/Topology/Connected/PathConnected.lean b/Mathlib/Topology/Connected/PathConnected.lean index 8b64b781f4113..0385c423b6f71 100644 --- a/Mathlib/Topology/Connected/PathConnected.lean +++ b/Mathlib/Topology/Connected/PathConnected.lean @@ -960,13 +960,13 @@ theorem isPathConnected_iff_eq : IsPathConnected F ↔ ∃ x ∈ F, pathComponen #align is_path_connected_iff_eq isPathConnected_iff_eq theorem IsPathConnected.joinedIn (h : IsPathConnected F) : - ∀ (x) (_ : x ∈ F) (y) (_ : y ∈ F), JoinedIn F x y := fun _x x_in _y y_in => + ∀ᵉ (x ∈ F) (y ∈ F), JoinedIn F x y := fun _x x_in _y y_in => let ⟨_b, _b_in, hb⟩ := h (hb x_in).symm.trans (hb y_in) #align is_path_connected.joined_in IsPathConnected.joinedIn theorem isPathConnected_iff : - IsPathConnected F ↔ F.Nonempty ∧ ∀ (x) (_ : x ∈ F) (y) (_ : y ∈ F), JoinedIn F x y := + IsPathConnected F ↔ F.Nonempty ∧ ∀ᵉ (x ∈ F) (y ∈ F), JoinedIn F x y := ⟨fun h => ⟨let ⟨b, b_in, _hb⟩ := h; ⟨b, b_in⟩, h.joinedIn⟩, fun ⟨⟨b, b_in⟩, h⟩ => ⟨b, b_in, fun x_in => h _ b_in _ x_in⟩⟩ diff --git a/Mathlib/Topology/ContinuousFunction/Bounded.lean b/Mathlib/Topology/ContinuousFunction/Bounded.lean index 6899e6132703d..d9f5443c49c46 100644 --- a/Mathlib/Topology/ContinuousFunction/Bounded.lean +++ b/Mathlib/Topology/ContinuousFunction/Bounded.lean @@ -537,8 +537,7 @@ theorem arzela_ascoli₁ [CompactSpace β] (A : Set (α →ᵇ β)) (closed : Is continuity to extend the closeness on tα to closeness everywhere. -/ have ε₂0 : ε₂ > 0 := half_pos (half_pos ε₁0) have : ∀ x : α, ∃ U, x ∈ U ∧ IsOpen U ∧ - ∀ (y) (_ : y ∈ U) (z) (_ : z ∈ U) {f : α →ᵇ β}, f ∈ A → dist (f y) (f z) < ε₂ := - fun x => + ∀ y ∈ U, ∀ z ∈ U, ∀ {f : α →ᵇ β}, f ∈ A → dist (f y) (f z) < ε₂ := fun x => let ⟨U, nhdsU, hU⟩ := H x _ ε₂0 let ⟨V, VU, openV, xV⟩ := _root_.mem_nhds_iff.1 nhdsU ⟨V, xV, openV, fun y hy z hz f hf => hU y (VU hy) z (VU hz) ⟨f, hf⟩⟩ diff --git a/Mathlib/Topology/ContinuousFunction/Ideals.lean b/Mathlib/Topology/ContinuousFunction/Ideals.lean index 7340945618b49..6b3f8861a9fd5 100644 --- a/Mathlib/Topology/ContinuousFunction/Ideals.lean +++ b/Mathlib/Topology/ContinuousFunction/Ideals.lean @@ -291,7 +291,7 @@ theorem idealOfSet_ofIdeal_eq_closure (I : Ideal C(X, 𝕜)) : compactness of `t`, there is some `0 < c` such that `c ≤ g' x` for all `x ∈ t`. Then by `exists_mul_le_one_eqOn_ge` there is some `g` for which `g * g'` is the desired function. -/ obtain ⟨g', hI', hgt'⟩ := this - obtain ⟨c, hc, hgc'⟩ : ∃ (c : _) (_ : 0 < c), ∀ y : X, y ∈ t → c ≤ g' y := + obtain ⟨c, hc, hgc'⟩ : ∃ c > 0, ∀ y : X, y ∈ t → c ≤ g' y := t.eq_empty_or_nonempty.elim (fun ht' => ⟨1, zero_lt_one, fun y hy => False.elim (by rwa [ht'] at hy)⟩) fun ht' => let ⟨x, hx, hx'⟩ := ht.isCompact.exists_forall_le ht' (map_continuous g').continuousOn diff --git a/Mathlib/Topology/ContinuousFunction/StoneWeierstrass.lean b/Mathlib/Topology/ContinuousFunction/StoneWeierstrass.lean index 34bc7c8a14649..2dad55c4743d8 100644 --- a/Mathlib/Topology/ContinuousFunction/StoneWeierstrass.lean +++ b/Mathlib/Topology/ContinuousFunction/StoneWeierstrass.lean @@ -166,8 +166,8 @@ open scoped Topology -- Here's the fun part of Stone-Weierstrass! theorem sublattice_closure_eq_top (L : Set C(X, ℝ)) (nA : L.Nonempty) - (inf_mem : ∀ (f) (_ : f ∈ L) (g) (_ : g ∈ L), f ⊓ g ∈ L) - (sup_mem : ∀ (f) (_ : f ∈ L) (g) (_ : g ∈ L), f ⊔ g ∈ L) (sep : L.SeparatesPointsStrongly) : + (inf_mem : ∀ᵉ (f ∈ L) (g ∈ L), f ⊓ g ∈ L) + (sup_mem : ∀ᵉ (f ∈ L) (g ∈ L), f ⊔ g ∈ L) (sep : L.SeparatesPointsStrongly) : closure L = ⊤ := by -- We start by boiling down to a statement about close approximation. apply eq_top_iff.mpr diff --git a/Mathlib/Topology/UniformSpace/Equicontinuity.lean b/Mathlib/Topology/UniformSpace/Equicontinuity.lean index e859dd7340a30..286792e0404cb 100644 --- a/Mathlib/Topology/UniformSpace/Equicontinuity.lean +++ b/Mathlib/Topology/UniformSpace/Equicontinuity.lean @@ -353,8 +353,6 @@ theorem uniform_equicontinuous_infi_dom {β' : Type*} {u : κ → UniformSpace simp_rw [@uniformEquicontinuous_iff_uniformContinuous _ _ _ _ _] at hk ⊢ exact uniformContinuous_iInf_dom hk --- Porting note: changed from `∃ k (_ : p k), _` to `∃ k, p k ∧ _` since Lean 4 generates the --- second one when parsing expressions like `∃ δ > 0, _`. theorem Filter.HasBasis.equicontinuousAt_iff_left {κ : Type*} {p : κ → Prop} {s : κ → Set X} {F : ι → X → α} {x₀ : X} (hX : (𝓝 x₀).HasBasis p s) : EquicontinuousAt F x₀ ↔ ∀ U ∈ 𝓤 α, ∃ k, p k ∧ ∀ x ∈ s k, ∀ i, (F i x₀, F i x) ∈ U := by @@ -372,8 +370,6 @@ theorem Filter.HasBasis.equicontinuousAt_iff_right {κ : Type*} {p : κ → Prop rfl #align filter.has_basis.equicontinuous_at_iff_right Filter.HasBasis.equicontinuousAt_iff_right --- Porting note: changed from `∃ k (_ : p k), _` to `∃ k, p k ∧ _` since Lean 4 generates the --- second one when parsing expressions like `∃ δ > 0, _`. theorem Filter.HasBasis.equicontinuousAt_iff {κ₁ κ₂ : Type*} {p₁ : κ₁ → Prop} {s₁ : κ₁ → Set X} {p₂ : κ₂ → Prop} {s₂ : κ₂ → Set (α × α)} {F : ι → X → α} {x₀ : X} (hX : (𝓝 x₀).HasBasis p₁ s₁) (hα : (𝓤 α).HasBasis p₂ s₂) : @@ -385,8 +381,6 @@ theorem Filter.HasBasis.equicontinuousAt_iff {κ₁ κ₂ : Type*} {p₁ : κ₁ rfl #align filter.has_basis.equicontinuous_at_iff Filter.HasBasis.equicontinuousAt_iff --- Porting note: changed from `∃ k (_ : p k), _` to `∃ k, p k ∧ _` since Lean 4 generates the --- second one when parsing expressions like `∃ δ > 0, _`. theorem Filter.HasBasis.uniformEquicontinuous_iff_left {κ : Type*} {p : κ → Prop} {s : κ → Set (β × β)} {F : ι → β → α} (hβ : (𝓤 β).HasBasis p s) : UniformEquicontinuous F ↔ @@ -405,8 +399,6 @@ theorem Filter.HasBasis.uniformEquicontinuous_iff_right {κ : Type*} {p : κ → rfl #align filter.has_basis.uniform_equicontinuous_iff_right Filter.HasBasis.uniformEquicontinuous_iff_right --- Porting note: changed from `∃ k (_ : p k), _` to `∃ k, p k ∧ _` since Lean 4 generates the --- second one when parsing expressions like `∃ δ > 0, _`. theorem Filter.HasBasis.uniformEquicontinuous_iff {κ₁ κ₂ : Type*} {p₁ : κ₁ → Prop} {s₁ : κ₁ → Set (β × β)} {p₂ : κ₂ → Prop} {s₂ : κ₂ → Set (α × α)} {F : ι → β → α} (hβ : (𝓤 β).HasBasis p₁ s₁) (hα : (𝓤 α).HasBasis p₂ s₂) : From cf8e23a62939ed7cc530fbb68e83539730f32f86 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 21 Dec 2023 23:05:32 +0000 Subject: [PATCH 116/353] chore: move toolchain to v4.4.0 (#9186) Co-authored-by: Scott Morrison --- lake-manifest.json | 4 ++-- lean-toolchain | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index a50b5b4603b15..ed455b65a792f 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "5bf9172331fb4de21647a919c64d3569839b63c6", + "rev": "af7f36db6e7e9e395710a70635f915e8e3a0e69b", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -22,7 +22,7 @@ {"url": "https://github.com/leanprover-community/aesop", "type": "git", "subDir": null, - "rev": "3141402ba5a5f0372d2378fd75a481bc79a74ecf", + "rev": "646be3a3604d0f2a3c1800cb4279a36493474b18", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", diff --git a/lean-toolchain b/lean-toolchain index 91ccf6ac0908c..26638e09fa859 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.4.0-rc1 +leanprover/lean4:v4.4.0 From 58eef79b1520d17ff085f58b599690c112a47e6b Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 22 Dec 2023 00:30:57 +0000 Subject: [PATCH 117/353] chore: move to v4.5.0-rc1, and merge changes from `bump/v4.5.0` branch. (#9188) This PR: * bumps to lean-toolchain to `v4.5.0-rc1` * bumps the Std and Aesop dependencies to their versions using `v4.5.0-rc1` * merge the already reviewed changes from the `bump/v4.5.0` branch * adaptations for leanprover/lean4#2923 in #9011 * adaptations for leanprover/lean4#2973 in #9161 * adaptations for leanprover/lean4#2964 in #9176 Co-authored-by: Scott Morrison Co-authored-by: Eric Wieser --- .github/workflows/bors.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/build.yml.in | 2 +- .github/workflows/build_fork.yml | 2 +- .../IfNormalization/WithoutAesop.lean | 10 +++++----- .../CategoryTheory/Monoidal/Preadditive.lean | 11 +++++----- Mathlib/Data/Finset/NoncommProd.lean | 2 +- Mathlib/Data/List/Func.lean | 1 - Mathlib/Data/List/Join.lean | 3 +-- Mathlib/Data/List/Perm.lean | 2 +- Mathlib/Data/List/Sigma.lean | 5 +---- Mathlib/Data/Nat/Bits.lean | 4 +--- Mathlib/Data/PFun.lean | 2 +- Mathlib/Data/Seq/Parallel.lean | 2 +- Mathlib/Data/Set/Intervals/Basic.lean | 4 +--- Mathlib/Data/Stream/Init.lean | 1 - Mathlib/Init/Data/Nat/Bitwise.lean | 6 +++--- .../Covering/BesicovitchVectorSpace.lean | 3 +-- Mathlib/MeasureTheory/Measure/Stieltjes.lean | 2 +- Mathlib/NumberTheory/Dioph.lean | 2 +- Mathlib/NumberTheory/LucasLehmer.lean | 9 ++++----- Mathlib/NumberTheory/Padics/Hensel.lean | 2 +- Mathlib/Tactic/Clean.lean | 4 ++-- Mathlib/Tactic/Widget/Calc.lean | 2 +- Mathlib/Tactic/Widget/Congrm.lean | 3 ++- Mathlib/Tactic/Widget/Conv.lean | 3 ++- Mathlib/Tactic/Widget/Gcongr.lean | 3 ++- lake-manifest.json | 8 ++++---- lakefile.lean | 2 +- lean-toolchain | 2 +- test/abel.lean | 10 +++------- test/matrix.lean | 20 +++++++++---------- 32 files changed, 60 insertions(+), 76 deletions(-) diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index 02593d2b9cab5..089ab5a5fdbac 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -260,7 +260,7 @@ jobs: run: | git clone https://github.com/leanprover/lean4checker cd lean4checker - git checkout toolchain/v4.3.0 + git checkout toolchain/v4.5.0-rc1 # Now that the git hash is embedded in each olean, # we need to compile lean4checker on the same toolchain cp ../lean-toolchain . diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 651e0563e8956..73bff93a3971c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -267,7 +267,7 @@ jobs: run: | git clone https://github.com/leanprover/lean4checker cd lean4checker - git checkout toolchain/v4.3.0 + git checkout toolchain/v4.5.0-rc1 # Now that the git hash is embedded in each olean, # we need to compile lean4checker on the same toolchain cp ../lean-toolchain . diff --git a/.github/workflows/build.yml.in b/.github/workflows/build.yml.in index ddbff9b47d7f1..dc651c15afb33 100644 --- a/.github/workflows/build.yml.in +++ b/.github/workflows/build.yml.in @@ -246,7 +246,7 @@ jobs: run: | git clone https://github.com/leanprover/lean4checker cd lean4checker - git checkout toolchain/v4.3.0 + git checkout toolchain/v4.5.0-rc1 # Now that the git hash is embedded in each olean, # we need to compile lean4checker on the same toolchain cp ../lean-toolchain . diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index 313047422f1bb..df3944b78ba34 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -264,7 +264,7 @@ jobs: run: | git clone https://github.com/leanprover/lean4checker cd lean4checker - git checkout toolchain/v4.3.0 + git checkout toolchain/v4.5.0-rc1 # Now that the git hash is embedded in each olean, # we need to compile lean4checker on the same toolchain cp ../lean-toolchain . diff --git a/Archive/Examples/IfNormalization/WithoutAesop.lean b/Archive/Examples/IfNormalization/WithoutAesop.lean index 79cda7b878191..d497e0d6f32ac 100644 --- a/Archive/Examples/IfNormalization/WithoutAesop.lean +++ b/Archive/Examples/IfNormalization/WithoutAesop.lean @@ -92,21 +92,21 @@ def normalize' (l : AList (fun _ : ℕ => Bool)) : · simp_all · have := ht₃ v have := he₃ v - simp_all? says simp_all only [Option.elim, ne_eq, normalized, Bool.and_eq_true, + simp_all? says simp_all only [Option.elim, normalized, Bool.and_eq_true, Bool.not_eq_true', AList.lookup_insert, imp_false] obtain ⟨⟨⟨tn, tc⟩, tr⟩, td⟩ := ht₂ split <;> rename_i h' · subst h' simp_all - · simp_all? says simp_all only [ne_eq, hasNestedIf, Bool.or_self, hasConstantIf, - and_self, hasRedundantIf, Bool.or_false, beq_eq_false_iff_ne, not_false_eq_true, + · simp_all? says simp_all only [hasNestedIf, Bool.or_self, hasConstantIf, and_self, + hasRedundantIf, Bool.or_false, beq_eq_false_iff_ne, ne_eq, not_false_eq_true, disjoint, List.disjoint, decide_True, Bool.and_self] · have := ht₃ w have := he₃ w by_cases h : w = v · subst h; simp_all - · simp_all? says simp_all only [Option.elim, ne_eq, normalized, Bool.and_eq_true, - Bool.not_eq_true', not_false_eq_true, AList.lookup_insert_ne] + · simp_all? says simp_all only [Option.elim, normalized, Bool.and_eq_true, + Bool.not_eq_true', ne_eq, not_false_eq_true, AList.lookup_insert_ne] obtain ⟨⟨⟨en, ec⟩, er⟩, ed⟩ := he₂ split at b <;> rename_i h' · subst h'; simp_all diff --git a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean index 2cd3cb0892697..de09694784229 100644 --- a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean +++ b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean @@ -283,9 +283,8 @@ theorem leftDistributor_ext_left {J : Type} [Fintype J] {X Y : C} {f : J → C} apply (cancel_epi (leftDistributor X f).inv).mp ext simp? [leftDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp] says - simp only [leftDistributor_inv, Preadditive.comp_sum_assoc, ne_eq, biproduct.ι_π_assoc, - dite_comp, zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, - ite_true] + simp only [leftDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp, + zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, ite_true] apply w @[ext] @@ -295,7 +294,7 @@ theorem leftDistributor_ext_right {J : Type} [Fintype J] {X Y : C} {f : J → C} ext simp? [leftDistributor_hom, Preadditive.sum_comp, Preadditive.comp_sum_assoc, biproduct.ι_π, comp_dite] says - simp only [leftDistributor_hom, Category.assoc, Preadditive.sum_comp, ne_eq, biproduct.ι_π, + simp only [leftDistributor_hom, Category.assoc, Preadditive.sum_comp, biproduct.ι_π, comp_dite, comp_zero, Finset.sum_dite_eq', Finset.mem_univ, eqToHom_refl, Category.comp_id, ite_true] apply w @@ -327,7 +326,7 @@ theorem rightDistributor_ext_left {J : Type} [Fintype J] apply (cancel_epi (rightDistributor f X).inv).mp ext simp? [rightDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp] says - simp only [rightDistributor_inv, Preadditive.comp_sum_assoc, ne_eq, biproduct.ι_π_assoc, + simp only [rightDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp, zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, ite_true] apply w @@ -340,7 +339,7 @@ theorem rightDistributor_ext_right {J : Type} [Fintype J] ext simp? [rightDistributor_hom, Preadditive.sum_comp, Preadditive.comp_sum_assoc, biproduct.ι_π, comp_dite] says - simp only [rightDistributor_hom, Category.assoc, Preadditive.sum_comp, ne_eq, biproduct.ι_π, + simp only [rightDistributor_hom, Category.assoc, Preadditive.sum_comp, biproduct.ι_π, comp_dite, comp_zero, Finset.sum_dite_eq', Finset.mem_univ, eqToHom_refl, Category.comp_id, ite_true] apply w diff --git a/Mathlib/Data/Finset/NoncommProd.lean b/Mathlib/Data/Finset/NoncommProd.lean index 2c6a89119baa7..ab0133e010833 100644 --- a/Mathlib/Data/Finset/NoncommProd.lean +++ b/Mathlib/Data/Finset/NoncommProd.lean @@ -478,7 +478,7 @@ theorem noncommProd_mul_single [Fintype ι] [DecidableEq ι] (x : ∀ i, M i) : noncommProd_eq_pow_card (univ.erase i), one_pow, mul_one] simp only [MonoidHom.single_apply, ne_eq, Pi.mulSingle_eq_same] · intro j hj - simp? at hj says simp only [mem_univ, not_true_eq_false, mem_erase, ne_eq, and_true] at hj + simp? at hj says simp only [mem_erase, ne_eq, mem_univ, and_true] at hj simp only [MonoidHom.single_apply, Pi.mulSingle, Function.update, Eq.ndrec, Pi.one_apply, ne_eq, dite_eq_right_iff] intro h diff --git a/Mathlib/Data/List/Func.lean b/Mathlib/Data/List/Func.lean index 0c0ff33a59db9..5b078a11ff3e1 100644 --- a/Mathlib/Data/List/Func.lean +++ b/Mathlib/Data/List/Func.lean @@ -106,7 +106,6 @@ theorem length_set : ∀ {m : ℕ} {as : List α}, as {m ↦ a}.length = max as. · simp [Nat.le_add_right] exact Nat.succ_le_succ (Nat.zero_le _) | m + 1, [] => by - have := @length_set m [] simp [set, length, @length_set m, Nat.zero_max] | m + 1, _ :: as => by simp [set, length, @length_set m, Nat.succ_max_succ] diff --git a/Mathlib/Data/List/Join.lean b/Mathlib/Data/List/Join.lean index 945259133a395..4f1c1ffe1fb39 100644 --- a/Mathlib/Data/List/Join.lean +++ b/Mathlib/Data/List/Join.lean @@ -52,8 +52,7 @@ theorem join_filter_isEmpty_eq_false [DecidablePred fun l : List α => l.isEmpty | [] :: L => by simp [join_filter_isEmpty_eq_false (L := L), isEmpty_iff_eq_nil] | (a :: l) :: L => by - have cons_not_empty : isEmpty (a :: l) = false := rfl - simp [join_filter_isEmpty_eq_false (L := L), cons_not_empty] + simp [join_filter_isEmpty_eq_false (L := L)] #align list.join_filter_empty_eq_ff List.join_filter_isEmpty_eq_false @[simp] diff --git a/Mathlib/Data/List/Perm.lean b/Mathlib/Data/List/Perm.lean index 5e60493e1b8e7..7342462419e54 100644 --- a/Mathlib/Data/List/Perm.lean +++ b/Mathlib/Data/List/Perm.lean @@ -361,7 +361,7 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) ( induction s generalizing l₁ case slnil => cases h₂ case cons r₁ r₂ b s' ih => - simp? at h₂ says simp only [Bool.not_eq_true, mem_cons] at h₂ + simp? at h₂ says simp only [mem_cons] at h₂ cases' h₂ with e m · subst b exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩ diff --git a/Mathlib/Data/List/Sigma.lean b/Mathlib/Data/List/Sigma.lean index 9107230c747c2..0103a751df8d6 100644 --- a/Mathlib/Data/List/Sigma.lean +++ b/Mathlib/Data/List/Sigma.lean @@ -28,7 +28,6 @@ If `α : Type*` and `β : α → Type*`, then we regard `s : Sigma β` as having - `List.kextract` returns a value with a given key and the rest of the values. -/ - universe u v namespace List @@ -204,9 +203,7 @@ theorem of_mem_dlookup {a : α} {b : β a} : | ⟨a', b'⟩ :: l, H => by by_cases h : a = a' · subst a' - simp? at H says - simp only [ne_eq, not_true_eq_false, dlookup_cons_eq, Option.mem_def, - Option.some.injEq] at H + simp? at H says simp only [dlookup_cons_eq, Option.mem_def, Option.some.injEq] at H simp [H] · simp only [ne_eq, h, not_false_iff, dlookup_cons_ne] at H simp [of_mem_dlookup H] diff --git a/Mathlib/Data/Nat/Bits.lean b/Mathlib/Data/Nat/Bits.lean index d9bbf827e7dd5..e4ce421787d94 100644 --- a/Mathlib/Data/Nat/Bits.lean +++ b/Mathlib/Data/Nat/Bits.lean @@ -174,9 +174,7 @@ theorem binaryRec_eq' {C : ℕ → Sort*} {z : C 0} {f : ∀ b n, C n → C (bit simp only [imp_false, or_false_iff, eq_self_iff_true, not_true] at h exact h.symm · dsimp only [] - -- Porting note: this line was `generalize_proofs e`: - generalize @id (C (bit b n) = C (bit (bodd (bit b n)) (div2 (bit b n)))) - (Eq.symm (bit_decomp (bit b n)) ▸ Eq.refl (C (bit b n))) = e + generalize_proofs e revert e rw [bodd_bit, div2_bit] intros diff --git a/Mathlib/Data/PFun.lean b/Mathlib/Data/PFun.lean index 8fba62f35965d..da0cca946ca7e 100644 --- a/Mathlib/Data/PFun.lean +++ b/Mathlib/Data/PFun.lean @@ -342,7 +342,7 @@ theorem fixInduction_spec {C : α → Sort*} {f : α →. Sum β α} {b : β} {a @fixInduction _ _ C _ _ _ h H = H a h fun a' h' => fixInduction (fix_fwd h h') H := by unfold fixInduction -- Porting note: `generalize` required to address `generalize_proofs` bug - generalize (Part.mem_assert_iff.1 h).fst = ha + generalize @fixInduction.proof_1 α β f b a h = ha induction ha rfl #align pfun.fix_induction_spec PFun.fixInduction_spec diff --git a/Mathlib/Data/Seq/Parallel.lean b/Mathlib/Data/Seq/Parallel.lean index d45690861ef2a..e9196615fe148 100644 --- a/Mathlib/Data/Seq/Parallel.lean +++ b/Mathlib/Data/Seq/Parallel.lean @@ -237,7 +237,7 @@ theorem exists_of_mem_parallel {S : WSeq (Computation α)} {a} (h : a ∈ parall apply ret_mem · intro a' h rcases h with ⟨d, dm, ad⟩ - simp? at dm says simp only [Bool.not_eq_true, List.mem_cons] at dm + simp? at dm says simp only [List.mem_cons] at dm cases' dm with e dl · rw [e] at ad refine' ⟨c, List.mem_cons_self _ _, _⟩ diff --git a/Mathlib/Data/Set/Intervals/Basic.lean b/Mathlib/Data/Set/Intervals/Basic.lean index bab3be2e4805d..de1cb4a9fb2ca 100644 --- a/Mathlib/Data/Set/Intervals/Basic.lean +++ b/Mathlib/Data/Set/Intervals/Basic.lean @@ -28,7 +28,6 @@ for some statements it should be `LinearOrder` or `DenselyOrdered`). TODO: This is just the beginning; a lot of rules are missing -/ - open Function open OrderDual (toDual ofDual) @@ -1168,8 +1167,7 @@ theorem Ioo_subset_Ioo_iff [DenselyOrdered α] (h₁ : a₁ < b₁) : theorem Ico_eq_Ico_iff (h : a₁ < b₁ ∨ a₂ < b₂) : Ico a₁ b₁ = Ico a₂ b₂ ↔ a₁ = a₂ ∧ b₁ = b₂ := ⟨fun e => by - simp? [Subset.antisymm_iff] at e says - simp only [gt_iff_lt, not_lt, ge_iff_le, Subset.antisymm_iff] at e + simp only [Subset.antisymm_iff] at e simp only [le_antisymm_iff] cases' h with h h <;> simp only [gt_iff_lt, not_lt, ge_iff_le, Ico_subset_Ico_iff h] at e <;> diff --git a/Mathlib/Data/Stream/Init.lean b/Mathlib/Data/Stream/Init.lean index 2d9dd5119e29f..f49b1f28083b4 100644 --- a/Mathlib/Data/Stream/Init.lean +++ b/Mathlib/Data/Stream/Init.lean @@ -432,7 +432,6 @@ theorem get_interleave_left : ∀ (n : Nat) (s₁ s₂ : Stream' α), | n + 1, s₁, s₂ => by change get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n) rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons] - have : n < succ n := Nat.lt_succ_self n rw [get_interleave_left n (tail s₁) (tail s₂)] rfl #align stream.nth_interleave_left Stream'.get_interleave_left diff --git a/Mathlib/Init/Data/Nat/Bitwise.lean b/Mathlib/Init/Data/Nat/Bitwise.lean index cd1fe62357693..e275366c33b1e 100644 --- a/Mathlib/Init/Data/Nat/Bitwise.lean +++ b/Mathlib/Init/Data/Nat/Bitwise.lean @@ -10,6 +10,7 @@ import Mathlib.Init.Data.Bool.Lemmas import Mathlib.Init.ZeroOne import Mathlib.Tactic.Cases import Mathlib.Tactic.Says +import Mathlib.Tactic.GeneralizeProofs #align_import init.data.nat.bitwise from "leanprover-community/lean"@"53e8520d8964c7632989880372d91ba0cecbaf00" @@ -341,9 +342,8 @@ theorem binaryRec_eq {C : Nat → Sort u} {z : C 0} {f : ∀ b n, C n → C (bit rfl case neg h' => simp only [dif_neg h] - generalize @id (C (bit b n) = C (bit (bodd (bit b n)) (div2 (bit b n)))) - (Eq.symm (bit_decomp (bit b n)) ▸ Eq.refl (C (bit b n))) = e - revert e + generalize_proofs h + revert h rw [bodd_bit, div2_bit] intros; rfl #align nat.binary_rec_eq Nat.binaryRec_eq diff --git a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean index 9c29756ed1b05..7ddcdff18db69 100644 --- a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean +++ b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean @@ -177,8 +177,7 @@ theorem card_le_of_separated (s : Finset E) (hs : ∀ c ∈ s, ‖c‖ ≤ 2) have K : (s.card : ℝ) ≤ (5 : ℝ) ^ finrank ℝ E := by have := ENNReal.toReal_le_of_le_ofReal (pow_nonneg ρpos.le _) J simp? [ENNReal.toReal_mul] at this says - simp only [one_div, inv_pow, ENNReal.toReal_mul, ENNReal.toReal_nat, inv_nonneg, ge_iff_le, - div_pow] at this + simp only [one_div, inv_pow, ENNReal.toReal_mul, ENNReal.toReal_nat, div_pow] at this simpa [div_eq_mul_inv, zero_le_two] using this exact mod_cast K #align besicovitch.card_le_of_separated Besicovitch.card_le_of_separated diff --git a/Mathlib/MeasureTheory/Measure/Stieltjes.lean b/Mathlib/MeasureTheory/Measure/Stieltjes.lean index a509618dc0689..394400ae1a23b 100644 --- a/Mathlib/MeasureTheory/Measure/Stieltjes.lean +++ b/Mathlib/MeasureTheory/Measure/Stieltjes.lean @@ -361,7 +361,7 @@ theorem measure_singleton (a : ℝ) : f.measure {a} = ofReal (f a - leftLim f a) exists_seq_strictMono_tendsto a have A : {a} = ⋂ n, Ioc (u n) a := by refine' Subset.antisymm (fun x hx => by simp [mem_singleton_iff.1 hx, u_lt_a]) fun x hx => _ - simp? at hx says simp only [gt_iff_lt, not_lt, ge_iff_le, mem_iInter, mem_Ioc] at hx + simp? at hx says simp only [mem_iInter, mem_Ioc] at hx have : a ≤ x := le_of_tendsto' u_lim fun n => (hx n).1.le simp [le_antisymm this (hx 0).2] have L1 : Tendsto (fun n => f.measure (Ioc (u n) a)) atTop (𝓝 (f.measure {a})) := by diff --git a/Mathlib/NumberTheory/Dioph.lean b/Mathlib/NumberTheory/Dioph.lean index 955adcf842ad2..cf6e5336a7743 100644 --- a/Mathlib/NumberTheory/Dioph.lean +++ b/Mathlib/NumberTheory/Dioph.lean @@ -360,7 +360,7 @@ theorem DiophList.forall (l : List (Set <| α → ℕ)) (d : l.Forall Dioph) : ⟨β, Poly.sumsq pl, fun v => (h v).trans <| exists_congr fun t => (Poly.sumsq_eq_zero _ _).symm⟩ induction' l with S l IH exact ⟨ULift Empty, [], fun _ => by simp⟩ - simp? at d says simp only [imp_false, List.forall_cons] at d + simp? at d says simp only [List.forall_cons] at d exact let ⟨⟨β, p, pe⟩, dl⟩ := d let ⟨γ, pl, ple⟩ := IH dl diff --git a/Mathlib/NumberTheory/LucasLehmer.lean b/Mathlib/NumberTheory/LucasLehmer.lean index 23d293c6403cf..fc1c347c693ec 100644 --- a/Mathlib/NumberTheory/LucasLehmer.lean +++ b/Mathlib/NumberTheory/LucasLehmer.lean @@ -152,8 +152,8 @@ theorem residue_eq_zero_iff_sMod_eq_zero (p : ℕ) (w : 1 < p) : -- and `lucas_lehmer_residue p = 0 → 2^p - 1 ∣ s_mod p (p-2)`. intro h simp? [ZMod.int_cast_zmod_eq_zero_iff_dvd] at h says - simp only [ge_iff_le, ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, pow_pos, - cast_pred, cast_pow, cast_ofNat] at h + simp only [ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, pow_pos, cast_pred, + cast_pow, cast_ofNat] at h apply Int.eq_zero_of_dvd_of_nonneg_of_lt _ _ h <;> clear h · exact sMod_nonneg _ (by positivity) _ · exact sMod_lt _ (by positivity) _ @@ -425,9 +425,8 @@ theorem ω_pow_formula (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) : dsimp [lucasLehmerResidue] at h rw [sZMod_eq_s p'] at h simp? [ZMod.int_cast_zmod_eq_zero_iff_dvd] at h says - simp only [ge_iff_le, add_le_iff_nonpos_left, nonpos_iff_eq_zero, add_tsub_cancel_right, - ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, pow_pos, cast_pred, cast_pow, - cast_ofNat] at h + simp only [add_tsub_cancel_right, ZMod.int_cast_zmod_eq_zero_iff_dvd, gt_iff_lt, zero_lt_two, + pow_pos, cast_pred, cast_pow, cast_ofNat] at h cases' h with k h use k replace h := congr_arg (fun n : ℤ => (n : X (q (p' + 2)))) h diff --git a/Mathlib/NumberTheory/Padics/Hensel.lean b/Mathlib/NumberTheory/Padics/Hensel.lean index 7cb36d60c312d..669022ec9bed8 100644 --- a/Mathlib/NumberTheory/Padics/Hensel.lean +++ b/Mathlib/NumberTheory/Padics/Hensel.lean @@ -354,7 +354,7 @@ private theorem bound : ∀ {ε}, ε > 0 → ∃ N : ℕ, ∀ {n}, n ≥ N → ‖F.derivative.eval a‖ * T ^ 2 ^ n < ε := by have := bound' hnorm simp? [Tendsto, nhds] at this says - simp only [Tendsto, nhds_def, Set.mem_setOf_eq, not_and, le_iInf_iff, le_principal_iff, mem_map, + simp only [Tendsto, nhds_def, Set.mem_setOf_eq, le_iInf_iff, le_principal_iff, mem_map, mem_atTop_sets, ge_iff_le, Set.mem_preimage, and_imp] at this intro ε hε cases' this (ball 0 ε) (mem_ball_self hε) isOpen_ball with N hN diff --git a/Mathlib/Tactic/Clean.lean b/Mathlib/Tactic/Clean.lean index 2e04153ea5d0e..d1c1bb02bc2d4 100644 --- a/Mathlib/Tactic/Clean.lean +++ b/Mathlib/Tactic/Clean.lean @@ -29,8 +29,8 @@ def clean (e : Expr) : Expr := | .app (.app (.const n _) _) e' => if n ∈ cleanConsts then some e' else none | .app (.lam _ _ (.bvar 0) _) e' => some e' | e => - match letFunAnnotation? e with - | some (.app (.lam _ _ (.bvar 0) _) e') => some e' + match e.letFun? with + | some (_n, _t, v, .bvar 0) => some v | _ => none end Lean.Expr diff --git a/Mathlib/Tactic/Widget/Calc.lean b/Mathlib/Tactic/Widget/Calc.lean index 634be8df3c637..0e2a1c8d4b2cf 100644 --- a/Mathlib/Tactic/Widget/Calc.lean +++ b/Mathlib/Tactic/Widget/Calc.lean @@ -137,6 +137,6 @@ elab_rules : tactic let json := open scoped Std.Json in json% {"replaceRange": $(replaceRange), "isFirst": $(isFirst), "indent": $(indent)} - ProofWidgets.savePanelWidgetInfo proofTerm `CalcPanel (pure json) + Widget.savePanelWidgetInfo CalcPanel.javascriptHash (pure json) proofTerm isFirst := false evalCalc (← `(tactic|calc%$calcstx $stx)) diff --git a/Mathlib/Tactic/Widget/Congrm.lean b/Mathlib/Tactic/Widget/Congrm.lean index abf8365734b0f..9095c828b36ae 100644 --- a/Mathlib/Tactic/Widget/Congrm.lean +++ b/Mathlib/Tactic/Widget/Congrm.lean @@ -51,4 +51,5 @@ open scoped Json in subexpressions in the goal.-/ elab stx:"congrm?" : tactic => do let some replaceRange := (← getFileMap).rangeOfStx? stx | return - savePanelWidgetInfo stx ``CongrmSelectionPanel $ pure $ json% { replaceRange: $(replaceRange) } + Widget.savePanelWidgetInfo CongrmSelectionPanel.javascriptHash + (pure $ json% { replaceRange: $(replaceRange) }) stx diff --git a/Mathlib/Tactic/Widget/Conv.lean b/Mathlib/Tactic/Widget/Conv.lean index aa268c2bdcdf2..aabc847b6ac06 100644 --- a/Mathlib/Tactic/Widget/Conv.lean +++ b/Mathlib/Tactic/Widget/Conv.lean @@ -133,4 +133,5 @@ open scoped Json in in the goal.-/ elab stx:"conv?" : tactic => do let some replaceRange := (← getFileMap).rangeOfStx? stx | return - savePanelWidgetInfo stx ``ConvSelectionPanel $ pure $ json% { replaceRange: $(replaceRange) } + Widget.savePanelWidgetInfo ConvSelectionPanel.javascriptHash + (pure $ json% { replaceRange: $(replaceRange) }) stx diff --git a/Mathlib/Tactic/Widget/Gcongr.lean b/Mathlib/Tactic/Widget/Gcongr.lean index df7ce0c32a9c9..f4fb3cc4788f6 100644 --- a/Mathlib/Tactic/Widget/Gcongr.lean +++ b/Mathlib/Tactic/Widget/Gcongr.lean @@ -49,4 +49,5 @@ open scoped Json in subexpressions in the goal.-/ elab stx:"gcongr?" : tactic => do let some replaceRange := (← getFileMap).rangeOfStx? stx | return - savePanelWidgetInfo stx ``GCongrSelectionPanel $ pure $ json% { replaceRange: $(replaceRange) } + Widget.savePanelWidgetInfo GCongrSelectionPanel.javascriptHash + (pure $ json% { replaceRange: $(replaceRange) }) stx diff --git a/lake-manifest.json b/lake-manifest.json index ed455b65a792f..dad3935ad2c4d 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "af7f36db6e7e9e395710a70635f915e8e3a0e69b", + "rev": "ee49cf8fada1bf5a15592c399a925c401848227f", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -22,7 +22,7 @@ {"url": "https://github.com/leanprover-community/aesop", "type": "git", "subDir": null, - "rev": "646be3a3604d0f2a3c1800cb4279a36493474b18", + "rev": "69404390bdc1de946bf0a2e51b1a69f308e56d7a", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -31,10 +31,10 @@ {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, - "rev": "909febc72b4f64628f8d35cd0554f8a90b6e0749", + "rev": "bf61e90de075abfa27f638922e7aafafdce77c44", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.23", + "inputRev": "v0.0.24-pre2", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover/lean4-cli", diff --git a/lakefile.lean b/lakefile.lean index b9e06d5208004..ef167dc422cc6 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -29,7 +29,7 @@ require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" require std from git "https://github.com/leanprover/std4" @ "main" require Qq from git "https://github.com/leanprover-community/quote4" @ "master" require aesop from git "https://github.com/leanprover-community/aesop" @ "master" -require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.23" +require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.24-pre2" require Cli from git "https://github.com/leanprover/lean4-cli" @ "main" /-! diff --git a/lean-toolchain b/lean-toolchain index 26638e09fa859..3f21e50bd46eb 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.4.0 +leanprover/lean4:v4.5.0-rc1 diff --git a/test/abel.lean b/test/abel.lean index 873a6732ef674..3a191ef22e61f 100644 --- a/test/abel.lean +++ b/test/abel.lean @@ -98,13 +98,9 @@ error: abel_nf made no progress example [AddCommGroup α] (x y z : α) (_w : x = y + z) : False := by abel_nf at * -/-- -error: no goals to be solved --/ --- This error message is confusing: it is saying that it closed the main goal, --- and so then had nothing to do on the hypotheses. --- The user has to guess that they should remove the `at *`. -#guard_msgs in +-- Prior to https://github.com/leanprover/lean4/pull/2917 this would fail +-- (the `at *` would close the goal, +-- and then error when trying to work on the hypotheses because there was no goal.) example [AddCommGroup α] (x y z : α) (_w : x = y + z) : x - x = 0 := by abel_nf at * diff --git a/test/matrix.lean b/test/matrix.lean index deac900999aea..373088b059c88 100644 --- a/test/matrix.lean +++ b/test/matrix.lean @@ -10,8 +10,6 @@ import Std.Tactic.GuardExpr open Qq --- TODO: uncomment above imports when they are ported - variable {α β : Type} [Semiring α] [Ring β] namespace Matrix @@ -138,10 +136,10 @@ example {a b c d e f g h : α} : ![a, b, c, d, e, f, g, h] 99 = d := by simp example {α : Type _} [CommRing α] {a b c d : α} : Matrix.det !![a, b; c, d] = a * d - b * c := by simp? [Matrix.det_succ_row_zero, Fin.sum_univ_succ] says - simp only [det_succ_row_zero, Nat.odd_iff_not_even, of_apply, cons_val', empty_val', + simp only [det_succ_row_zero, of_apply, cons_val', empty_val', cons_val_fin_one, cons_val_zero, det_unique, Fin.default_eq_zero, submatrix_apply, - Fin.succ_zero_eq_one, ne_eq, cons_val_one, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, - pow_zero, one_mul, not_true_eq_false, Fin.zero_succAbove, head_cons, Finset.univ_unique, + Fin.succ_zero_eq_one, cons_val_one, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, + pow_zero, one_mul, Fin.zero_succAbove, head_cons, Finset.univ_unique, Fin.val_succ, Fin.coe_fin_one, zero_add, pow_one, cons_val_succ, neg_mul, Fin.succ_succAbove_zero, Finset.sum_const, Finset.card_singleton, smul_neg, one_smul] ring @@ -150,12 +148,12 @@ example {α : Type _} [CommRing α] {a b c d e f g h i : α} : Matrix.det !![a, b, c; d, e, f; g, h, i] = a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g := by simp? [Matrix.det_succ_row_zero, Fin.sum_univ_succ] says - simp only [det_succ_row_zero, Nat.odd_iff_not_even, of_apply, cons_val', empty_val', - cons_val_fin_one, cons_val_zero, submatrix_apply, Fin.succ_zero_eq_one, cons_val_one, head_cons, - submatrix_submatrix, det_unique, Fin.default_eq_zero, Function.comp_apply, Fin.succ_one_eq_two, - ne_eq, cons_val_two, tail_cons, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, pow_zero, - one_mul, not_true_eq_false, Fin.zero_succAbove, Finset.univ_unique, Fin.val_succ, - Fin.coe_fin_one, zero_add, pow_one, neg_mul, Fin.succ_succAbove_zero, Finset.sum_neg_distrib, + simp only [det_succ_row_zero, of_apply, cons_val', empty_val', + cons_val_fin_one, cons_val_zero, submatrix_apply, Fin.succ_zero_eq_one, cons_val_one, + head_cons, submatrix_submatrix, det_unique, Fin.default_eq_zero, Function.comp_apply, + Fin.succ_one_eq_two, cons_val_two, tail_cons, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, + pow_zero, one_mul, Fin.zero_succAbove, Finset.univ_unique, Fin.val_succ, Fin.coe_fin_one, + zero_add, pow_one, neg_mul, Fin.succ_succAbove_zero, Finset.sum_neg_distrib, Finset.sum_singleton, cons_val_succ, Fin.succ_succAbove_one, even_add_self, Even.neg_pow, one_pow, Finset.sum_const, Finset.card_singleton, one_smul] ring From 1be5db8befe8e11141567caec4864747adecb14e Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 22 Dec 2023 02:15:40 +0000 Subject: [PATCH 118/353] chore: bump ProofWidgets to v0.0.24 (#9191) Co-authored-by: Scott Morrison --- lake-manifest.json | 4 ++-- lakefile.lean | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index dad3935ad2c4d..e3edebe28c403 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -31,10 +31,10 @@ {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, - "rev": "bf61e90de075abfa27f638922e7aafafdce77c44", + "rev": "31d41415d5782a196999d4fd8eeaef3cae386a5f", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.24-pre2", + "inputRev": "v0.0.24", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover/lean4-cli", diff --git a/lakefile.lean b/lakefile.lean index ef167dc422cc6..8d631ed24d682 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -29,7 +29,7 @@ require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" require std from git "https://github.com/leanprover/std4" @ "main" require Qq from git "https://github.com/leanprover-community/quote4" @ "master" require aesop from git "https://github.com/leanprover-community/aesop" @ "master" -require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.24-pre2" +require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.24" require Cli from git "https://github.com/leanprover/lean4-cli" @ "main" /-! From d7fc2c57d205f65fda14073ee3c0cdebd87163c9 Mon Sep 17 00:00:00 2001 From: Siddharth Date: Fri, 22 Dec 2023 05:11:55 +0000 Subject: [PATCH 119/353] fix: remove `++` in `throwError` in favor of {""} (#8132) This correctly interpolates the error messages in the `cases'` tactic. Reported at: https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/uninterpolated.20error.20message.3A.20unecessary.20generalizing/near/400018518 --- Mathlib/Tactic/Cases.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Tactic/Cases.lean b/Mathlib/Tactic/Cases.lean index 42da5cf508638..c6a66c311a9ba 100644 --- a/Mathlib/Tactic/Cases.lean +++ b/Mathlib/Tactic/Cases.lean @@ -75,11 +75,11 @@ elab (name := induction') "induction' " tgts:(Parser.Tactic.casesTarget,+) let mut s ← getFVarSetToGeneralize targets forbidden for v in genArgs do if forbidden.contains v then - throwError ("variable cannot be generalized " ++ - "because target depends on it{indentExpr (mkFVar v)}") + throwError "variable cannot be generalized {"" + }because target depends on it{indentExpr (mkFVar v)}" if s.contains v then - throwError ("unnecessary 'generalizing' argument, " ++ - "variable '{mkFVar v}' is generalized automatically") + throwError "unnecessary 'generalizing' argument, {"" + }variable '{mkFVar v}' is generalized automatically" s := s.insert v let (fvarIds, g) ← g.revert (← sortFVarIds s.toArray) g.withContext do From 8f013c457aea2ea1b0156c0c98043c9ed018529f Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 06:58:39 +0000 Subject: [PATCH 120/353] chore(ContinuousMonoidHom): golf (#9189) --- .../Topology/Algebra/ContinuousMonoidHom.lean | 55 ++++++------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean index 7f599a421e8b9..e77d882d98db8 100644 --- a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean +++ b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean @@ -286,47 +286,24 @@ theorem embedding_toContinuousMap : #align continuous_monoid_hom.embedding_to_continuous_map ContinuousMonoidHom.embedding_toContinuousMap #align continuous_add_monoid_hom.embedding_to_continuous_map ContinuousAddMonoidHom.embedding_toContinuousMap +@[to_additive] +lemma range_toContinuousMap : + Set.range (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) = + {f : C(A, B) | f 1 = 1 ∧ ∀ x y, f (x * y) = f x * f y} := by + refine Set.Subset.antisymm (Set.range_subset_iff.2 fun f ↦ ⟨map_one f, map_mul f⟩) ?_ + rintro f ⟨h1, hmul⟩ + exact ⟨{ f with map_one' := h1, map_mul' := hmul }, rfl⟩ + @[to_additive] theorem closedEmbedding_toContinuousMap [ContinuousMul B] [T2Space B] : - ClosedEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := - ⟨embedding_toContinuousMap A B, - ⟨by - suffices - Set.range (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) = - ({ f | f '' {1} ⊆ {1}ᶜ } ∪ - ⋃ (x) (y) (U) (V) (W) (_ : IsOpen U) (_ : IsOpen V) (_ : IsOpen W) (_ : - Disjoint (U * V) W), - { f | f '' {x} ⊆ U } ∩ { f | f '' {y} ⊆ V } ∩ { f | f '' {x * y} ⊆ W } : - Set C(A , B))ᶜ by - rw [this, compl_compl] - refine' (ContinuousMap.isOpen_gen isCompact_singleton isOpen_compl_singleton).union _ - repeat' apply isOpen_iUnion; intro - repeat' apply IsOpen.inter - all_goals apply ContinuousMap.isOpen_gen isCompact_singleton; assumption - simp_rw [Set.compl_union, Set.compl_iUnion, Set.image_singleton, Set.singleton_subset_iff, - Set.ext_iff, Set.mem_inter_iff, Set.mem_iInter, Set.mem_compl_iff] - refine' fun f => ⟨_, _⟩ - · rintro ⟨f, rfl⟩ - exact - ⟨fun h => h (map_one f), fun x y U V W _hU _hV _hW h ⟨⟨hfU, hfV⟩, hfW⟩ => - h.le_bot ⟨Set.mul_mem_mul hfU hfV, (congr_arg (· ∈ W) (map_mul f x y)).mp hfW⟩⟩ - · rintro ⟨hf1, hf2⟩ - suffices ∀ x y, f (x * y) = f x * f y by - refine' - ⟨({ f with - map_one' := of_not_not hf1 - map_mul' := this } : - ContinuousMonoidHom A B), - ContinuousMap.ext fun _ => rfl⟩ - intro x y - contrapose! hf2 - obtain ⟨UV, W, hUV, hW, hfUV, hfW, h⟩ := t2_separation hf2.symm - have hB := @continuous_mul B _ _ _ - obtain ⟨U, V, hU, hV, hfU, hfV, h'⟩ := - isOpen_prod_iff.mp (hUV.preimage hB) (f x) (f y) hfUV - refine' ⟨x, y, U, V, W, hU, hV, hW, h.mono_left _, ⟨hfU, hfV⟩, hfW⟩ - rintro _ ⟨x, y, hx : (x, y).1 ∈ U, hy : (x, y).2 ∈ V, rfl⟩ - exact h' ⟨hx, hy⟩⟩⟩ + ClosedEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) where + toEmbedding := embedding_toContinuousMap A B + closed_range := by + simp only [range_toContinuousMap, Set.setOf_and, Set.setOf_forall] + refine .inter (isClosed_singleton.preimage (ContinuousMap.continuous_eval_const 1)) <| + isClosed_iInter fun x ↦ isClosed_iInter fun y ↦ ?_ + exact isClosed_eq (ContinuousMap.continuous_eval_const (x * y)) <| + .mul (ContinuousMap.continuous_eval_const x) (ContinuousMap.continuous_eval_const y) #align continuous_monoid_hom.closed_embedding_to_continuous_map ContinuousMonoidHom.closedEmbedding_toContinuousMap #align continuous_add_monoid_hom.closed_embedding_to_continuous_map ContinuousAddMonoidHom.closedEmbedding_toContinuousMap From a2edc39f07fd1fbbe284a8fd73628d8bfa35de07 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 08:43:20 +0000 Subject: [PATCH 121/353] =?UTF-8?q?chore(Order/Filter/NAry):=20drop=20`Fil?= =?UTF-8?q?ter.map=E2=82=83`=20(#9182)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was used only once to prove associativity of `Filter.map₂`. --- Mathlib/Order/Filter/NAry.lean | 53 ++++------------------------------ 1 file changed, 6 insertions(+), 47 deletions(-) diff --git a/Mathlib/Order/Filter/NAry.lean b/Mathlib/Order/Filter/NAry.lean index a8916ef2ecd52..15ed7f6b17526 100644 --- a/Mathlib/Order/Filter/NAry.lean +++ b/Mathlib/Order/Filter/NAry.lean @@ -16,7 +16,6 @@ operations on filters. ## Main declarations * `Filter.map₂`: Binary map of filters. -* `Filter.map₃`: Ternary map of filters. ## Notes @@ -173,50 +172,9 @@ theorem map₂_left [NeBot g] : map₂ (fun x _ => x) f g = f := by theorem map₂_right [NeBot f] : map₂ (fun _ y => y) f g = g := by rw [map₂_swap, map₂_left] #align filter.map₂_right Filter.map₂_right -/-- The image of a ternary function `m : α → β → γ → δ` as a function -`Filter α → Filter β → Filter γ → Filter δ`. Mathematically this should be thought of as the image -of the corresponding function `α × β × γ → δ`. -/ -def map₃ (m : α → β → γ → δ) (f : Filter α) (g : Filter β) (h : Filter γ) : Filter δ where - sets := { s | ∃ u v w, u ∈ f ∧ v ∈ g ∧ w ∈ h ∧ image3 m u v w ⊆ s } - univ_sets := ⟨univ, univ, univ, univ_sets _, univ_sets _, univ_sets _, subset_univ _⟩ - sets_of_superset hs hst := - Exists₃.imp - (fun u v w => And.imp_right <| And.imp_right <| And.imp_right fun h => Subset.trans h hst) hs - inter_sets := by - simp only [exists_prop, mem_setOf_eq, subset_inter_iff] - rintro _ _ ⟨s₁, s₂, s₃, hs₁, hs₂, hs₃, hs⟩ ⟨t₁, t₂, t₃, ht₁, ht₂, ht₃, ht⟩ - exact - ⟨s₁ ∩ t₁, s₂ ∩ t₂, s₃ ∩ t₃, inter_mem hs₁ ht₁, inter_mem hs₂ ht₂, inter_mem hs₃ ht₃, - (image3_mono (inter_subset_left _ _) (inter_subset_left _ _) <| inter_subset_left _ _).trans - hs, - (image3_mono (inter_subset_right _ _) (inter_subset_right _ _) <| - inter_subset_right _ _).trans - ht⟩ -#align filter.map₃ Filter.map₃ - -theorem map₂_map₂_left (m : δ → γ → ε) (n : α → β → δ) : - map₂ m (map₂ n f g) h = map₃ (fun a b c => m (n a b) c) f g h := by - ext w - constructor - · rintro ⟨s, t, ⟨u, v, hu, hv, hs⟩, ht, hw⟩ - refine' ⟨u, v, t, hu, hv, ht, _⟩ - rw [← image2_image2_left] - exact (image2_subset_right hs).trans hw - · rintro ⟨s, t, u, hs, ht, hu, hw⟩ - exact ⟨_, u, image2_mem_map₂ hs ht, hu, by rwa [image2_image2_left]⟩ -#align filter.map₂_map₂_left Filter.map₂_map₂_left - -theorem map₂_map₂_right (m : α → δ → ε) (n : β → γ → δ) : - map₂ m f (map₂ n g h) = map₃ (fun a b c => m a (n b c)) f g h := by - ext w - constructor - · rintro ⟨s, t, hs, ⟨u, v, hu, hv, ht⟩, hw⟩ - refine' ⟨s, u, v, hs, hu, hv, _⟩ - rw [← image2_image2_right] - exact (image2_subset_left ht).trans hw - · rintro ⟨s, t, u, hs, ht, hu, hw⟩ - exact ⟨s, _, hs, image2_mem_map₂ ht hu, by rwa [image2_image2_right]⟩ -#align filter.map₂_map₂_right Filter.map₂_map₂_right +#noalign filter.map₃ +#noalign filter.map₂_map₂_left +#noalign filter.map₂_map₂_right theorem map_map₂ (m : α → β → γ) (n : γ → δ) : (map₂ m f g).map n = map₂ (fun a b => n (m a b)) f g := by @@ -255,11 +213,12 @@ The proof pattern is `map₂_lemma operation_lemma`. For example, `map₂_comm m `map₂ (*) f g = map₂ (*) g f` in a `CommSemigroup`. -/ - theorem map₂_assoc {m : δ → γ → ε} {n : α → β → δ} {m' : α → ε' → ε} {n' : β → γ → ε'} {h : Filter γ} (h_assoc : ∀ a b c, m (n a b) c = m' a (n' b c)) : map₂ m (map₂ n f g) h = map₂ m' f (map₂ n' g h) := by - simp only [map₂_map₂_left, map₂_map₂_right, h_assoc] + rw [← map_prod_eq_map₂ n, ← map_prod_eq_map₂ n', map₂_map_left, map₂_map_right, + ← map_prod_eq_map₂, ← map_prod_eq_map₂, ← prod_assoc, map_map] + simp only [h_assoc]; rfl #align filter.map₂_assoc Filter.map₂_assoc theorem map₂_comm {n : β → α → γ} (h_comm : ∀ a b, m a b = n b a) : map₂ m f g = map₂ n g f := From ccbb556636ec6181efbf0c9ebc8940ec8f06d138 Mon Sep 17 00:00:00 2001 From: grunweg Date: Fri, 22 Dec 2023 09:27:59 +0000 Subject: [PATCH 122/353] feat: local diffeomorphisms (#8736) Define local diffeomorphisms between smooth manifolds. As an auxiliary definition, we add `PartialDiffeomorph`, the analogue of `PartialHomeomorph` for diffeomorphisms. In future PRs, we will - show that local diffeomorphisms have invertible differential - show the converse, using the inverse function theorem: if the differential of $f$ at $x$ is invertible, $f$ is a local diffeomorphism at $x$ --- Mathlib.lean | 1 + .../Geometry/Manifold/LocalDiffeomorph.lean | 271 ++++++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 Mathlib/Geometry/Manifold/LocalDiffeomorph.lean diff --git a/Mathlib.lean b/Mathlib.lean index 5c18650f47447..2891e7b5978eb 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2118,6 +2118,7 @@ import Mathlib.Geometry.Manifold.Instances.Real import Mathlib.Geometry.Manifold.Instances.Sphere import Mathlib.Geometry.Manifold.Instances.UnitsOfNormedAlgebra import Mathlib.Geometry.Manifold.InteriorBoundary +import Mathlib.Geometry.Manifold.LocalDiffeomorph import Mathlib.Geometry.Manifold.LocalInvariantProperties import Mathlib.Geometry.Manifold.MFDeriv import Mathlib.Geometry.Manifold.Metrizable diff --git a/Mathlib/Geometry/Manifold/LocalDiffeomorph.lean b/Mathlib/Geometry/Manifold/LocalDiffeomorph.lean new file mode 100644 index 0000000000000..ced40318c844c --- /dev/null +++ b/Mathlib/Geometry/Manifold/LocalDiffeomorph.lean @@ -0,0 +1,271 @@ +/- +Copyright (c) 2023 Michael Rothgang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Michael Rothgang +-/ + +import Mathlib.Geometry.Manifold.Diffeomorph +import Mathlib.Topology.IsLocalHomeomorph + +/-! +# Local diffeomorphisms between manifolds + +In this file, we define `C^n` local diffeomorphisms between manifolds. + +A `C^n` map `f : M → N` is a **local diffeomorphism at `x`** iff there are neighbourhoods `s` +and `t` of `x` and `f x`, respectively such that `f` restricts to a diffeomorphism +between `s` and `t`. `f` is called a **local diffeomorphism on s** iff it is a local diffeomorphism +at every `x ∈ s`, and a **local diffeomorphism** iff it is a local diffeomorphism on `univ`. + +## Main definitions +* `IsLocalDiffeomorphAt I J n f x`: `f` is a `C^n` local diffeomorphism at `x` +* `IsLocalDiffeomorphOn I J n f s`: `f` is a `C^n` local diffeomorphism on `s` +* `IsLocalDiffeomorph I J n f`: `f` is a `C^n` local diffeomorphism + +## Main results +* Each of `Diffeomorph`, `IsLocalDiffeomorph`, `IsLocalDiffeomorphOn` and `IsLocalDiffeomorphAt` + implies the next. +* `IsLocalDiffeomorph.isLocalHomeomorph`: a local diffeomorphisms is a local homeomorphism, + similarly for local diffeomorphism on `s` +* `IsLocalDiffeomorph.isOpen_range`: the image of a local diffeomorphism is open +* `IslocalDiffeomorph.diffeomorph_of_bijective`: + a bijective local diffeomorphism is a diffeomorphism + +## TODO +* an injective local diffeomorphism is a diffeomorphism to its image +* each differential of a `C^n` diffeomorphism (`n ≥ 1`) is a linear equivalence. +* if `f` is a local diffeomorphism at `x`, the differential `mfderiv I J n f x` +is a continuous linear isomorphism. +* conversely, if `f` is `C^n` at `x` and `mfderiv I J n f x` is a linear isomorphism, +`f` is a local diffeomorphism at `x`. +* if `f` is a local diffeomorphism, each differential `mfderiv I J n f x` +is a continuous linear isomorphism. +* Conversely, if `f` is `C^n` and each differential is a linear isomorphism, +`f` is a local diffeomorphism. + +## Implementation notes + +This notion of diffeomorphism is needed although there is already a notion of local structomorphism +because structomorphisms do not allow the model spaces `H` and `H'` of the two manifolds to be +different, i.e. for a structomorphism one has to impose `H = H'` which is often not the case in +practice. + +## Tags +local diffeomorphism, manifold + +-/ + +open Manifold Set TopologicalSpace + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] + {H : Type*} [TopologicalSpace H] + {G : Type*} [TopologicalSpace G] + (I : ModelWithCorners 𝕜 E H) (J : ModelWithCorners 𝕜 F G) + (M : Type*) [TopologicalSpace M] [ChartedSpace H M] + (N : Type*) [TopologicalSpace N] [ChartedSpace G N] (n : ℕ∞) + +section PartialDiffeomorph +/-- A partial diffeomorphism on `s` is a function `f : M → N` such that `f` restricts to a +diffeomorphism `s → t` between open subsets of `M` and `N`, respectively. +This is an auxiliary definition and should not be used outside of this file. -/ +structure PartialDiffeomorph extends PartialEquiv M N where + open_source : IsOpen source + open_target : IsOpen target + contMDiffOn_toFun : ContMDiffOn I J n toFun source + contMDiffOn_invFun : ContMDiffOn J I n invFun target + +/-- Coercion of a `PartialDiffeomorph` to function. +Note that a `PartialDiffeomorph` is not `FunLike` (like `PartialHomeomorph`), +as `toFun` doesn't determine `invFun` outside of `target`. -/ +instance : CoeFun (PartialDiffeomorph I J M N n) fun _ => M → N := + ⟨fun Φ => Φ.toFun⟩ + +variable {I J M N n} + +/-- A diffeomorphism is a partial diffeomorphism. -/ +def Diffeomorph.toPartialDiffeomorph (h : Diffeomorph I J M N n) : + PartialDiffeomorph I J M N n where + toPartialEquiv := h.toHomeomorph.toPartialEquiv + open_source := isOpen_univ + open_target := isOpen_univ + contMDiffOn_toFun x _ := h.contMDiff_toFun x + contMDiffOn_invFun _ _ := h.symm.contMDiffWithinAt + +-- Add the very basic API we need. +namespace PartialDiffeomorph +variable (Φ : PartialDiffeomorph I J M N n) (hn : 1 ≤ n) + +/-- A partial diffeomorphism is also a local homeomorphism. -/ +def toPartialHomeomorph : PartialHomeomorph M N where + toPartialEquiv := Φ.toPartialEquiv + open_source := Φ.open_source + open_target := Φ.open_target + continuousOn_toFun := Φ.contMDiffOn_toFun.continuousOn + continuousOn_invFun := Φ.contMDiffOn_invFun.continuousOn + +/-- The inverse of a local diffeomorphism. -/ +protected def symm : PartialDiffeomorph J I N M n where + toPartialEquiv := Φ.toPartialEquiv.symm + open_source := Φ.open_target + open_target := Φ.open_source + contMDiffOn_toFun := Φ.contMDiffOn_invFun + contMDiffOn_invFun := Φ.contMDiffOn_toFun + +protected theorem contMDiffOn : ContMDiffOn I J n Φ Φ.source := + Φ.contMDiffOn_toFun + +protected theorem mdifferentiableOn : MDifferentiableOn I J Φ Φ.source := + (Φ.contMDiffOn).mdifferentiableOn hn + +protected theorem mdifferentiableAt {x : M} (hx : x ∈ Φ.source) : MDifferentiableAt I J Φ x := + (Φ.mdifferentiableOn hn x hx).mdifferentiableAt (Φ.open_source.mem_nhds hx) + +/- We could add lots of additional API (following `Diffeomorph` and `PartialHomeomorph`), such as +* further continuity and differentiability lemmas +* refl and trans instances; lemmas between them. +As this declaration is meant for internal use only, we keep it simple. -/ +end PartialDiffeomorph +end PartialDiffeomorph + +variable {M N} + +/-- `f : M → N` is called a **`C^n` local diffeomorphism at *x*** iff there exist + open sets `U ∋ x` and `V ∋ f x` and a diffeomorphism `Φ : U → V` such that `f = Φ` on `U`. -/ +def IsLocalDiffeomorphAt (f : M → N) (x : M) : Prop := + ∃ Φ : PartialDiffeomorph I J M N n, x ∈ Φ.source ∧ EqOn f Φ Φ.source + +/-- `f : M → N` is called a **`C^n` local diffeomorphism on *s*** iff it is a local diffeomorphism + at each `x : s`. -/ +def IsLocalDiffeomorphOn (f : M → N) (s : Set M) : Prop := + ∀ x : s, IsLocalDiffeomorphAt I J n f x + +/-- `f : M → N` is a **`C^n` local diffeomorphism** iff it is a local diffeomorphism +at each `x ∈ M`. -/ +def IsLocalDiffeomorph (f : M → N) : Prop := + ∀ x : M, IsLocalDiffeomorphAt I J n f x + +variable {I J n} in +lemma isLocalDiffeomorphOn_iff {f : M → N} (s : Set M) : + IsLocalDiffeomorphOn I J n f s ↔ ∀ x : s, IsLocalDiffeomorphAt I J n f x := by rfl + +variable {I J n} in +lemma isLocalDiffeomorph_iff {f : M → N} : + IsLocalDiffeomorph I J n f ↔ ∀ x : M, IsLocalDiffeomorphAt I J n f x := by rfl + +variable {I J n} in +theorem isLocalDiffeomorph_iff_isLocalDiffeomorphOn_univ {f : M → N} : + IsLocalDiffeomorph I J n f ↔ IsLocalDiffeomorphOn I J n f Set.univ := + ⟨fun hf x ↦ hf x, fun hf x ↦ hf ⟨x, trivial⟩⟩ + +variable {I J n} in +lemma IsLocalDiffeomorph.isLocalDiffeomorphOn + {f : M → N} (hf : IsLocalDiffeomorph I J n f) (s : Set M) : IsLocalDiffeomorphOn I J n f s := + fun x ↦ hf x + +/-! # Basic properties of local diffeomorphisms -/ +section Basic +variable {f : M → N} {s : Set M} {x : M} +variable {I J n} + +/-- A `C^n` local diffeomorphism at `x` is `C^n` differentiable at `x`. -/ +lemma IsLocalDiffeomorphAt.contMDiffAt (hf : IsLocalDiffeomorphAt I J n f x) : + ContMDiffAt I J n f x := by + choose Φ hx heq using hf + -- In fact, even `ContMDiffOn I J n f Φ.source`. + exact ((Φ.contMDiffOn_toFun).congr heq).contMDiffAt (Φ.open_source.mem_nhds hx) + +/-- A local diffeomorphism at `x` is differentiable at `x`. -/ +lemma IsLocalDiffeomorphAt.mdifferentiableAt (hf : IsLocalDiffeomorphAt I J n f x) (hn : 1 ≤ n) : + MDifferentiableAt I J f x := + hf.contMDiffAt.mdifferentiableAt hn + +/-- A `C^n` local diffeomorphism on `s` is `C^n` on `s`. -/ +lemma IsLocalDiffeomorphOn.contMDiffOn (hf : IsLocalDiffeomorphOn I J n f s) : + ContMDiffOn I J n f s := + fun x hx ↦ (hf ⟨x, hx⟩).contMDiffAt.contMDiffWithinAt + +/-- A local diffeomorphism on `s` is differentiable on `s`. -/ +lemma IsLocalDiffeomorphOn.mdifferentiableOn (hf : IsLocalDiffeomorphOn I J n f s) (hn : 1 ≤ n) : + MDifferentiableOn I J f s := + hf.contMDiffOn.mdifferentiableOn hn + +/-- A `C^n` local diffeomorphism is `C^n`. -/ +lemma IsLocalDiffeomorph.contMDiff (hf : IsLocalDiffeomorph I J n f) : ContMDiff I J n f := + fun x ↦ (hf x).contMDiffAt + +/-- A `C^n` local diffeomorphism is differentiable. -/ +lemma IsLocalDiffeomorph.mdifferentiable (hf : IsLocalDiffeomorph I J n f) (hn : 1 ≤ n) : + MDifferentiable I J f := + fun x ↦ (hf x).mdifferentiableAt hn + +/-- A `C^n` diffeomorphism is a local diffeomorphism. -/ +lemma Diffeomorph.isLocalDiffeomorph (Φ : M ≃ₘ^n⟮I, J⟯ N) : IsLocalDiffeomorph I J n Φ := + fun _x ↦ ⟨Φ.toPartialDiffeomorph, by trivial, eqOn_refl Φ _⟩ + +-- FUTURE: if useful, also add "a `PartialDiffeomorph` is a local diffeomorphism on its source" + +/-- A local diffeomorphism on `s` is a local homeomorphism on `s`. -/ +theorem IsLocalDiffeomorphOn.isLocalHomeomorphOn {s : Set M} (hf : IsLocalDiffeomorphOn I J n f s): + IsLocalHomeomorphOn f s := by + apply IsLocalHomeomorphOn.mk + intro x hx + choose U hyp using hf ⟨x, hx⟩ + exact ⟨U.toPartialHomeomorph, hyp⟩ + +/-- A local diffeomorphism is a local homeomorphism. -/ +theorem IsLocalDiffeomorph.isLocalHomeomorph (hf : IsLocalDiffeomorph I J n f) : + IsLocalHomeomorph f := by + rw [isLocalHomeomorph_iff_isLocalHomeomorphOn_univ] + rw [isLocalDiffeomorph_iff_isLocalDiffeomorphOn_univ] at hf + exact hf.isLocalHomeomorphOn + +/-- A local diffeomorphism is an open map. -/ +lemma IsLocalDiffeomorph.isOpenMap (hf : IsLocalDiffeomorph I J n f) : IsOpenMap f := + (hf.isLocalHomeomorph).isOpenMap + +/-- A local diffeomorphism has open range. -/ +lemma IsLocalDiffeomorph.isOpen_range (hf : IsLocalDiffeomorph I J n f) : IsOpen (range f) := + (hf.isOpenMap).isOpen_range + +/-- The image of a local diffeomorphism is open. -/ +def IsLocalDiffeomorph.image (hf : IsLocalDiffeomorph I J n f) : Opens N := + ⟨range f, hf.isOpen_range⟩ + +lemma IsLocalDiffeomorph.image_coe (hf : IsLocalDiffeomorph I J n f) : hf.image.1 = range f := + rfl + +-- TODO: this result holds more generally for (local) structomorphisms +-- This argument implies a `LocalDiffeomorphOn f s` for `s` open is a `PartialDiffeomorph` + +/-- A bijective local diffeomorphism is a diffeomorphism. -/ +noncomputable def IslocalDiffeomorph.diffeomorph_of_bijective + (hf : IsLocalDiffeomorph I J n f) (hf' : Function.Bijective f) : Diffeomorph I J M N n := by + -- Choose a right inverse `g` of `f`. + choose g hgInverse using (Function.bijective_iff_has_inverse).mp hf' + -- Choose diffeomorphisms φ_x which coincide which `f` near `x`. + choose Φ hyp using (fun x ↦ hf x) + -- Two such diffeomorphisms (and their inverses!) coincide on their sources: + -- they're both inverses to g. In fact, the latter suffices for our proof. + -- have (x y) : EqOn (Φ x).symm (Φ y).symm ((Φ x).target ∩ (Φ y).target) := sorry + have aux (x) : EqOn g (Φ x).symm (Φ x).target := + eqOn_of_leftInvOn_of_rightInvOn (fun x' _ ↦ hgInverse.1 x') + (LeftInvOn.congr_left ((Φ x).toPartialHomeomorph).rightInvOn + ((Φ x).toPartialHomeomorph).symm_mapsTo (hyp x).2.symm) + (fun _y hy ↦ (Φ x).map_target hy) + exact { + toFun := f + invFun := g + left_inv := hgInverse.1 + right_inv := hgInverse.2 + contMDiff_toFun := hf.contMDiff + contMDiff_invFun := by + intro y + let x := g y + obtain ⟨hx, hfx⟩ := hyp x + apply ((Φ x).symm.contMDiffOn.congr (aux x)).contMDiffAt (((Φ x).open_target).mem_nhds ?_) + have : y = (Φ x) x := ((hgInverse.2 y).congr (hfx hx)).mp rfl + exact this ▸ (Φ x).map_source hx } + +end Basic From d0256633f15cd902aaf6fef5c11af0678988d2c4 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Fri, 22 Dec 2023 09:50:03 +0000 Subject: [PATCH 123/353] chore(LinearAlgebra): golf two proofs (#9192) Golf two old proofs from [mathlib3#3056](https://github.com/leanprover-community/mathlib/commit/cc16d35b642fc1bb838f6a2555b37a32a5465c32) Co-authored-by: Junyan Xu --- .../LinearAlgebra/FreeModule/Finite/Rank.lean | 126 +++--------------- 1 file changed, 22 insertions(+), 104 deletions(-) diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean index a05dfe14b478b..d58aa46fcdc0b 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean @@ -482,131 +482,49 @@ open BigOperators open Finset /-- If a finset has cardinality larger than the rank of a module, -then there is a nontrivial linear relation amongst its elements. --/ --- TODO: golf this +then there is a nontrivial linear relation amongst its elements. -/ theorem Module.exists_nontrivial_relation_of_finrank_lt_card [Module.Finite R V] {t : Finset V} (h : finrank R V < t.card) : ∃ f : V → R, ∑ e in t, f e • e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by - classical - have := mt FiniteDimensional.finset_card_le_finrank_of_linearIndependent (by simpa using h) - rw [_root_.not_linearIndependent_iff] at this - obtain ⟨s, g, sum, z, zm, nonzero⟩ := this - -- Now we have to extend `g` to all of `t`, then to all of `V`. - let f : V → R := fun x => if h : x ∈ t then if (⟨x, h⟩ : t) ∈ s then g ⟨x, h⟩ else 0 else 0 - -- and finally clean up the mess caused by the extension. - refine' ⟨f, _, _⟩ - · dsimp - rw [← (sum)] -- porting note: need parens to disambiguate - fapply sum_bij_ne_zero fun v hvt _ => (⟨v, hvt⟩ : { v // v ∈ t }) - · intro v hvt H - dsimp - rw [dif_pos hvt] at H - contrapose! H - rw [if_neg H, zero_smul] - · intro _ _ _ _ _ _ - exact Subtype.mk.inj - · intro b hbs hb - use b - simpa only [hbs, exists_prop, dif_pos, Finset.mk_coe, and_true_iff, if_true, Finset.coe_mem, - eq_self_iff_true, exists_prop_of_true, Ne.def] using hb - · intro a h₁ - dsimp - rw [dif_pos h₁] - intro h₂ - rw [if_pos] - contrapose! h₂ - rw [if_neg h₂, zero_smul] - · refine' ⟨z, z.2, _⟩ - dsimp only - erw [dif_pos z.2, if_pos] <;> rwa [Subtype.coe_eta] + obtain ⟨g, sum, z, nonzero⟩ := Fintype.not_linearIndependent_iff.mp + (mt FiniteDimensional.finset_card_le_finrank_of_linearIndependent h.not_le) + refine ⟨Subtype.val.extend g 0, ?_, z, z.2, by rwa [Subtype.val_injective.extend_apply]⟩ + rw [← Finset.sum_finset_coe]; convert sum; apply Subtype.val_injective.extend_apply #align finite_dimensional.exists_nontrivial_relation_of_rank_lt_card Module.exists_nontrivial_relation_of_finrank_lt_card /-- If a finset has cardinality larger than `finrank + 1`, then there is a nontrivial linear relation amongst its elements, -such that the coefficients of the relation sum to zero. --/ --- TODO: golf this +such that the coefficients of the relation sum to zero. -/ theorem Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card [Module.Finite R V] {t : Finset V} (h : finrank R V + 1 < t.card) : ∃ f : V → R, ∑ e in t, f e • e = 0 ∧ ∑ e in t, f e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by - classical -- Pick an element x₀ ∈ t, - have card_pos : 0 < t.card := lt_trans (Nat.succ_pos _) h - obtain ⟨x₀, m⟩ := (Finset.card_pos.1 card_pos).bex + obtain ⟨x₀, x₀_mem⟩ := card_pos.1 ((Nat.succ_pos _).trans h) -- and apply the previous lemma to the {xᵢ - x₀} - let shift : V ↪ V := ⟨fun x => x - x₀, sub_left_injective⟩ + let shift : V ↪ V := ⟨(· - x₀), sub_left_injective⟩ + classical let t' := (t.erase x₀).map shift have h' : finrank R V < t'.card := by - simp only [card_map, Finset.card_erase_of_mem m] + rw [card_map, card_erase_of_mem x₀_mem] exact Nat.lt_pred_iff.mpr h -- to obtain a function `g`. obtain ⟨g, gsum, x₁, x₁_mem, nz⟩ := exists_nontrivial_relation_of_finrank_lt_card h' -- Then obtain `f` by translating back by `x₀`, -- and setting the value of `f` at `x₀` to ensure `∑ e in t, f e = 0`. - let f : V → R := fun z => if z = x₀ then -∑ z in t.erase x₀, g (z - x₀) else g (z - x₀) - refine' ⟨f, _, _, _⟩ + let f : V → R := fun z ↦ if z = x₀ then -∑ z in t.erase x₀, g (z - x₀) else g (z - x₀) + refine ⟨f, ?_, ?_, ?_⟩ -- After this, it's a matter of verifying the properties, -- based on the corresponding properties for `g`. - · show (∑ e : V in t, f e • e) = 0 - -- We prove this by splitting off the `x₀` term of the sum, - -- which is itself a sum over `t.erase x₀`, - -- combining the two sums, and - -- observing that after reindexing we have exactly - -- ∑ (x : V) in t', g x • x = 0. - simp only - conv_lhs => - apply_congr - rfl - rw [ite_smul] - rw [Finset.sum_ite] - conv => - congr - congr - apply_congr - -- Porting note: the next two steps used to work by `simp [filter_eq', m]` - erw [filter_eq'] - simp [m] - conv => - congr - congr - rfl - apply_congr - simp [filter_ne'] - rw [sum_singleton, neg_smul, add_comm, ← sub_eq_add_neg, sum_smul, ← sum_sub_distrib] - simp only [← smul_sub] - -- At the end we have to reindex the sum, so we use `change` to - -- express the summand using `shift`. - change (∑ x : V in t.erase x₀, (fun e => g e • e) (shift x)) = 0 - -- porting note: last argument can't be inferred - rw [← sum_map _ shift (fun e => g e • e)] - exact gsum - · show (∑ e : V in t, f e) = 0 - -- Again we split off the `x₀` term, - -- observing that it exactly cancels the other terms. - rw [← insert_erase m, sum_insert (not_mem_erase x₀ t)] - dsimp - rw [if_pos rfl] - conv_lhs => - congr - rfl - apply_congr - rfl - rw [if_neg (show _ ≠ x₀ from (mem_erase.mp ‹_›).1)] - exact neg_add_self _ - · show ∃ (x : V), x ∈ t ∧ f x ≠ 0 - -- We can use x₁ + x₀. - refine' ⟨x₁ + x₀, _, _⟩ - · rw [Finset.mem_map] at x₁_mem - rcases x₁_mem with ⟨x₁, x₁_mem, rfl⟩ - rw [mem_erase] at x₁_mem - simp only [x₁_mem, sub_add_cancel, Function.Embedding.coeFn_mk] - · dsimp only - rwa [if_neg, add_sub_cancel] - rw [add_left_eq_self] - rintro rfl - simp only [sub_eq_zero, exists_prop, Finset.mem_map, Embedding.coeFn_mk, eq_self_iff_true, - mem_erase, not_true, exists_eq_right, Ne.def, false_and_iff] at x₁_mem + · rw [sum_map, Embedding.coeFn_mk] at gsum + simp_rw [← t.sum_erase_add _ x₀_mem, if_pos, neg_smul, sum_smul, + ← sub_eq_add_neg, ← sum_sub_distrib, ← gsum, smul_sub] + refine sum_congr rfl fun x x_mem ↦ ?_ + rw [if_neg (mem_erase.mp x_mem).1] + · simp_rw [← t.sum_erase_add _ x₀_mem, if_pos, add_neg_eq_zero] + exact sum_congr rfl fun x x_mem ↦ if_neg (mem_erase.mp x_mem).1 + · obtain ⟨x₁, x₁_mem', rfl⟩ := Finset.mem_map.mp x₁_mem + have := mem_erase.mp x₁_mem' + exact ⟨x₁, by simpa only [Embedding.coeFn_mk, sub_add_cancel, this.2, true_and, if_neg this.1]⟩ #align finite_dimensional.exists_nontrivial_relation_sum_zero_of_rank_succ_lt_card Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card end From 42f553b66d2943150db4de4215637a40c9726203 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 22 Dec 2023 10:02:38 +0000 Subject: [PATCH 124/353] chore: bump to nightly-2023-12-22 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index ab0fdcb8b0063..0a830983958ad 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-21 +leanprover/lean4:nightly-2023-12-22 From 98067b25fcb5c00c13b4ac74ab781e2ef6689812 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Fri, 22 Dec 2023 10:33:26 +0000 Subject: [PATCH 125/353] feat(LinearAlgebra/Dimension): add various `surjective_injective` results (#9156) Add various results concerning modules `M / R` and `M' / R'` with maps `i : R -> R'` and `j : M -> M'` which are compatible with scalar multiplications on `M` and `M'`. - if `i : R' -> R` is injective and `j` is injective, then: - `LinearIndependent.map_of_injective_injective`: `j` preserves linear independent subsets. - `[lift_]rank_le_of_injective_injective`: rank of `M / R` is smaller than or equal to the rank of `M' / R'`. - if `i` is surjective and `j` is injective, then: - `LinearIndependent.map_of_surjective_injective`: `j` preserves linear independent subsets. - `[lift_]rank_le_of_surjective_injective`: rank of `M / R` is smaller than or equal to the rank of `M' / R'`. - if `i` and `j` are both bijective, then `[lift_]rank_eq_of_equiv_equiv`: rank of `M / R` is equal to the rank of `M' / R'`. Also add the `Algebra` versions of these results. --- Mathlib/LinearAlgebra/Dimension.lean | 136 +++++++++++++++++++ Mathlib/LinearAlgebra/LinearIndependent.lean | 29 ++++ 2 files changed, 165 insertions(+) diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean index 498fb191118c6..ee60edb57308e 100644 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ b/Mathlib/LinearAlgebra/Dimension.lean @@ -547,6 +547,142 @@ theorem rank_pos_iff_nontrivial : 0 < Module.rank R M ↔ Nontrivial M := end RankZero +section SurjectiveInjective + +section Module + +variable {R : Type w} {M : Type v} [Ring R] [AddCommGroup M] [Module R M] + {R' : Type w'} {M' : Type v'} [Ring R'] [AddCommGroup M'] [Module R' M'] + +/-- If `M / R` and `M' / R'` are modules, `i : R' → R` is a map which sends non-zero elements to +non-zero elements, `j : M →+ M'` is an injective group homomorphism, such that the scalar +multiplications on `M` and `M'` are compatible, then the rank of `M / R` is smaller than or equal to +the rank of `M' / R'`. As a special case, taking `R = R'` it is +`LinearMap.lift_rank_le_of_injective`. -/ +theorem lift_rank_le_of_injective_injective (i : R' → R) (j : M →+ M') + (hi : ∀ r, i r = 0 → r = 0) (hj : Injective j) + (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : + lift.{v'} (Module.rank R M) ≤ lift.{v} (Module.rank R' M') := by + simp_rw [Module.rank, lift_iSup (bddAbove_range.{v', v'} _), lift_iSup (bddAbove_range.{v, v} _)] + exact ciSup_mono' (bddAbove_range.{v', v} _) fun ⟨s, h⟩ ↦ ⟨⟨j '' s, + (h.map_of_injective_injective i j hi (fun _ _ ↦ hj <| by rwa [j.map_zero]) hc).image⟩, + lift_mk_le'.mpr ⟨(Equiv.Set.image j s hj).toEmbedding⟩⟩ + +/-- If `M / R` and `M' / R'` are modules, `i : R → R'` is a surjective map which maps zero to zero, +`j : M →+ M'` is an injective group homomorphism, such that the scalar multiplications on `M` and +`M'` are compatible, then the rank of `M / R` is smaller than or equal to the rank of `M' / R'`. +As a special case, taking `R = R'` it is `LinearMap.lift_rank_le_of_injective`. -/ +theorem lift_rank_le_of_surjective_injective (i : ZeroHom R R') (j : M →+ M') + (hi : Surjective i) (hj : Injective j) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : + lift.{v'} (Module.rank R M) ≤ lift.{v} (Module.rank R' M') := by + obtain ⟨i', hi'⟩ := hi.hasRightInverse + refine lift_rank_le_of_injective_injective i' j (fun _ h ↦ ?_) hj fun r m ↦ ?_ + · apply_fun i at h + rwa [hi', i.map_zero] at h + rw [hc (i' r) m, hi'] + +/-- If `M / R` and `M' / R'` are modules, `i : R → R'` is a bijective map which maps zero to zero, +`j : M ≃+ M'` is a group isomorphism, such that the scalar multiplications on `M` and `M'` are +compatible, then the rank of `M / R` is equal to the rank of `M' / R'`. +As a special case, taking `R = R'` it is `LinearEquiv.lift_rank_eq`. -/ +theorem lift_rank_eq_of_equiv_equiv (i : ZeroHom R R') (j : M ≃+ M') + (hi : Bijective i) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : + lift.{v'} (Module.rank R M) = lift.{v} (Module.rank R' M') := + (lift_rank_le_of_surjective_injective i j hi.2 j.injective hc).antisymm <| + lift_rank_le_of_injective_injective i j.symm (fun _ _ ↦ hi.1 <| by rwa [i.map_zero]) + j.symm.injective fun _ _ ↦ j.symm_apply_eq.2 <| by erw [hc, j.apply_symm_apply] + +variable {M' : Type v} [Ring R'] [AddCommGroup M'] [Module R' M'] + +/-- The same-universe version of `lift_rank_le_of_injective_injective`. -/ +theorem rank_le_of_injective_injective (i : R' → R) (j : M →+ M') + (hi : ∀ r, i r = 0 → r = 0) (hj : Injective j) + (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : + Module.rank R M ≤ Module.rank R' M' := by + simpa only [lift_id] using lift_rank_le_of_injective_injective i j hi hj hc + +/-- The same-universe version of `lift_rank_le_of_surjective_injective`. -/ +theorem rank_le_of_surjective_injective (i : ZeroHom R R') (j : M →+ M') + (hi : Surjective i) (hj : Injective j) + (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : + Module.rank R M ≤ Module.rank R' M' := by + simpa only [lift_id] using lift_rank_le_of_surjective_injective i j hi hj hc + +/-- The same-universe version of `lift_rank_eq_of_equiv_equiv`. -/ +theorem rank_eq_of_equiv_equiv (i : ZeroHom R R') (j : M ≃+ M') + (hi : Bijective i) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : + Module.rank R M = Module.rank R' M' := by + simpa only [lift_id] using lift_rank_eq_of_equiv_equiv i j hi hc + +end Module + +namespace Algebra + +variable {R : Type w} {S : Type v} [CommRing R] [Ring S] [Algebra R S] + {R' : Type w'} {S' : Type v'} [CommRing R'] [Ring S'] [Algebra R' S'] + +/-- If `S / R` and `S' / R'` are algebras, `i : R' →+* R` and `j : S →+* S'` are injective ring +homorphisms, such that `R' → R → S → S'` and `R' → S'` commute, then the rank of `S / R` is +smaller than or equal to the rank of `S' / R'`. -/ +theorem lift_rank_le_of_injective_injective + (i : R' →+* R) (j : S →+* S') (hi : Injective i) (hj : Injective j) + (hc : (j.comp (algebraMap R S)).comp i = algebraMap R' S') : + lift.{v'} (Module.rank R S) ≤ lift.{v} (Module.rank R' S') := by + refine _root_.lift_rank_le_of_injective_injective i j + (fun _ _ ↦ hi <| by rwa [i.map_zero]) hj fun r _ ↦ ?_ + have := congr($hc r) + simp only [RingHom.coe_comp, comp_apply] at this + simp_rw [smul_def, AddMonoidHom.coe_coe, map_mul, this] + +/-- If `S / R` and `S' / R'` are algebras, `i : R →+* R'` is a surjective ring homomorphism, +`j : S →+* S'` is an injective ring homorphism, such that `R → R' → S'` and `R → S → S'` commute, +then the rank of `S / R` is smaller than or equal to the rank of `S' / R'`. -/ +theorem lift_rank_le_of_surjective_injective + (i : R →+* R') (j : S →+* S') (hi : Surjective i) (hj : Injective j) + (hc : (algebraMap R' S').comp i = j.comp (algebraMap R S)) : + lift.{v'} (Module.rank R S) ≤ lift.{v} (Module.rank R' S') := by + refine _root_.lift_rank_le_of_surjective_injective i j hi hj fun r _ ↦ ?_ + have := congr($hc r) + simp only [RingHom.coe_comp, comp_apply] at this + simp only [smul_def, AddMonoidHom.coe_coe, map_mul, ZeroHom.coe_coe, this] + +/-- If `S / R` and `S' / R'` are algebras, `i : R ≃+* R'` and `j : S ≃+* S'` are +ring isomorphisms, such that `R → R' → S'` and `R → S → S'` commute, +then the rank of `S / R` is equal to the rank of `S' / R'`. -/ +theorem lift_rank_eq_of_equiv_equiv (i : R ≃+* R') (j : S ≃+* S') + (hc : (algebraMap R' S').comp i.toRingHom = j.toRingHom.comp (algebraMap R S)) : + lift.{v'} (Module.rank R S) = lift.{v} (Module.rank R' S') := by + refine _root_.lift_rank_eq_of_equiv_equiv i j i.bijective fun r _ ↦ ?_ + have := congr($hc r) + simp only [RingEquiv.toRingHom_eq_coe, RingHom.coe_comp, RingHom.coe_coe, comp_apply] at this + simp only [smul_def, RingEquiv.coe_toAddEquiv, map_mul, ZeroHom.coe_coe, this] + +variable {S' : Type v} [CommRing R'] [Ring S'] [Algebra R' S'] + +/-- The same-universe version of `Algebra.lift_rank_le_of_injective_injective`. -/ +theorem rank_le_of_injective_injective + (i : R' →+* R) (j : S →+* S') (hi : Injective i) (hj : Injective j) + (hc : (j.comp (algebraMap R S)).comp i = algebraMap R' S') : + Module.rank R S ≤ Module.rank R' S' := by + simpa only [lift_id] using lift_rank_le_of_injective_injective i j hi hj hc + +/-- The same-universe version of `Algebra.lift_rank_le_of_surjective_injective`. -/ +theorem rank_le_of_surjective_injective + (i : R →+* R') (j : S →+* S') (hi : Surjective i) (hj : Injective j) + (hc : (algebraMap R' S').comp i = j.comp (algebraMap R S)) : + Module.rank R S ≤ Module.rank R' S' := by + simpa only [lift_id] using lift_rank_le_of_surjective_injective i j hi hj hc + +/-- The same-universe version of `Algebra.lift_rank_eq_of_equiv_equiv`. -/ +theorem rank_eq_of_equiv_equiv (i : R ≃+* R') (j : S ≃+* S') + (hc : (algebraMap R' S').comp i.toRingHom = j.toRingHom.comp (algebraMap R S)) : + Module.rank R S = Module.rank R' S' := by + simpa only [lift_id] using lift_rank_eq_of_equiv_equiv i j hc + +end Algebra + +end SurjectiveInjective + section InvariantBasisNumber variable {R : Type u} [Ring R] [InvariantBasisNumber R] diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index 5bc4c3d2c5aaf..ce6061878003c 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -275,6 +275,35 @@ theorem LinearIndependent.map' (hv : LinearIndependent R v) (f : M →ₗ[R] M') hv.map <| by simp [hf_inj] #align linear_independent.map' LinearIndependent.map' +/-- If `M / R` and `M' / R'` are modules, `i : R' → R` is a map, `j : M →+ M'` is a monoid map, +such that they send non-zero elements to non-zero elements, and compatible with the scalar +multiplications on `M` and `M'`, then `j` sends linearly independent families of vectors to +linearly independent families of vectors. As a special case, taking `R = R'` +it is `LinearIndependent.map'`. -/ +theorem LinearIndependent.map_of_injective_injective {R' : Type*} {M' : Type*} + [Semiring R'] [AddCommMonoid M'] [Module R' M'] (hv : LinearIndependent R v) + (i : R' → R) (j : M →+ M') (hi : ∀ r, i r = 0 → r = 0) (hj : ∀ m, j m = 0 → m = 0) + (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : LinearIndependent R' (j ∘ v) := by + rw [linearIndependent_iff'] at hv ⊢ + intro S r' H s hs + simp_rw [comp_apply, ← hc, ← map_sum] at H + exact hi _ <| hv _ _ (hj _ H) s hs + +/-- If `M / R` and `M' / R'` are modules, `i : R → R'` is a surjective map which maps zero to zero, +`j : M →+ M'` is a monoid map which sends non-zero elements to non-zero elements, such that the +scalar multiplications on `M` and `M'` are compatible, then `j` sends linearly independent families +of vectors to linearly independent families of vectors. As a special case, taking `R = R'` +it is `LinearIndependent.map'`. -/ +theorem LinearIndependent.map_of_surjective_injective {R' : Type*} {M' : Type*} + [Semiring R'] [AddCommMonoid M'] [Module R' M'] (hv : LinearIndependent R v) + (i : ZeroHom R R') (j : M →+ M') (hi : Surjective i) (hj : ∀ m, j m = 0 → m = 0) + (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : LinearIndependent R' (j ∘ v) := by + obtain ⟨i', hi'⟩ := hi.hasRightInverse + refine hv.map_of_injective_injective i' j (fun _ h ↦ ?_) hj fun r m ↦ ?_ + · apply_fun i at h + rwa [hi', i.map_zero] at h + rw [hc (i' r) m, hi'] + /-- If the image of a family of vectors under a linear map is linearly independent, then so is the original family. -/ theorem LinearIndependent.of_comp (f : M →ₗ[R] M') (hfv : LinearIndependent R (f ∘ v)) : From c54f3fb499e895cdb560e8a779efaec9b4b3c159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 22 Dec 2023 13:04:11 +0000 Subject: [PATCH 126/353] feat: `1` is the only positive element of finite order (#9110) and other simple lemmas about the order of elements in a group From LeanAPAP --- Mathlib/GroupTheory/OrderOfElement.lean | 47 +++++++++++++++++------ Mathlib/GroupTheory/Perm/Cycle/Basic.lean | 2 +- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/Mathlib/GroupTheory/OrderOfElement.lean b/Mathlib/GroupTheory/OrderOfElement.lean index 879df714a1bb2..65a0591141215 100644 --- a/Mathlib/GroupTheory/OrderOfElement.lean +++ b/Mathlib/GroupTheory/OrderOfElement.lean @@ -32,7 +32,7 @@ This file defines the order of an element of a finite group. For a finite group order of an element -/ -open Function Nat Pointwise Subgroup Submonoid +open Function Fintype Nat Pointwise Subgroup Submonoid variable {G H A α β : Type*} @@ -85,6 +85,11 @@ theorem not_isOfFinOrder_of_injective_pow {x : G} (h : Injective fun n : ℕ => #align not_is_of_fin_order_of_injective_pow not_isOfFinOrder_of_injective_pow #align not_is_of_fin_add_order_of_injective_nsmul not_isOfFinAddOrder_of_injective_nsmul +lemma IsOfFinOrder.pow {n : ℕ} : IsOfFinOrder a → IsOfFinOrder (a ^ n) := by + simp_rw [isOfFinOrder_iff_pow_eq_one] + rintro ⟨m, hm, ha⟩ + exact ⟨m, hm, by simp [pow_right_comm _ n, ha]⟩ + /-- Elements of finite order are of finite order in submonoids.-/ @[to_additive "Elements of finite order are of finite order in submonoids."] theorem Submonoid.isOfFinOrder_coe {H : Submonoid G} {x : H} : @@ -1040,18 +1045,19 @@ theorem Subgroup.pow_index_mem {G : Type*} [Group G] (H : Subgroup G) [Normal H] #align subgroup.pow_index_mem Subgroup.pow_index_mem #align add_subgroup.nsmul_index_mem AddSubgroup.nsmul_index_mem -@[to_additive] -theorem pow_eq_mod_card (n : ℕ) : x ^ n = x ^ (n % Fintype.card G) := by - rw [← pow_mod_orderOf, ← Nat.mod_mod_of_dvd n orderOf_dvd_card, pow_mod_orderOf] -#align pow_eq_mod_card pow_eq_mod_card -#align nsmul_eq_mod_card nsmul_eq_mod_card -@[to_additive] -theorem zpow_eq_mod_card (n : ℤ) : x ^ n = x ^ (n % Fintype.card G : ℤ) := by - rw [← zpow_mod_orderOf, ← Int.emod_emod_of_dvd n (Int.coe_nat_dvd.2 orderOf_dvd_card), +@[to_additive (attr := simp) mod_card_nsmul] +lemma pow_mod_card (a : G) (n : ℕ) : a ^ (n % card G) = a ^ n := by + rw [eq_comm, ← pow_mod_orderOf, ← Nat.mod_mod_of_dvd n orderOf_dvd_card, pow_mod_orderOf] +#align pow_eq_mod_card pow_mod_card +#align nsmul_eq_mod_card mod_card_nsmul + +@[to_additive (attr := simp) mod_card_zsmul] +theorem zpow_mod_card (n : ℤ) : x ^ (n % Fintype.card G : ℤ) = x ^ n := by + rw [eq_comm, ← zpow_mod_orderOf, ← Int.emod_emod_of_dvd n (Int.coe_nat_dvd.2 orderOf_dvd_card), zpow_mod_orderOf] -#align zpow_eq_mod_card zpow_eq_mod_card -#align zsmul_eq_mod_card zsmul_eq_mod_card +#align zpow_eq_mod_card zpow_mod_card +#align zsmul_eq_mod_card mod_card_zsmul /-- If `gcd(|G|,n)=1` then the `n`th power map is a bijection -/ @[to_additive (attr := simps) "If `gcd(|G|,n)=1` then the smul by `n` is a bijection"] @@ -1085,6 +1091,10 @@ theorem powCoprime_inv {G : Type*} [Group G] (h : (Nat.card G).Coprime n) {g : G #align pow_coprime_inv powCoprime_inv #align nsmul_coprime_neg nsmulCoprime_neg +@[to_additive Nat.Coprime.nsmul_right_bijective] +lemma Nat.Coprime.pow_left_bijective (hn : (Nat.card G).Coprime n) : Bijective (· ^ n : G → G) := + (powCoprime hn).bijective + @[to_additive add_inf_eq_bot_of_coprime] theorem inf_eq_bot_of_coprime {G : Type*} [Group G] {H K : Subgroup G} [Fintype H] [Fintype K] (h : Nat.Coprime (Fintype.card H) (Fintype.card K)) : H ⊓ K = ⊥ := by @@ -1164,9 +1174,22 @@ def powCardSubgroup {G : Type*} [Group G] [Fintype G] (S : Set G) (hS : S.Nonemp end PowIsSubgroup +section LinearOrderedSemiring +variable [LinearOrderedSemiring G] {a : G} + +protected lemma IsOfFinOrder.eq_one (ha₀ : 0 ≤ a) (ha : IsOfFinOrder a) : a = 1 := by + obtain ⟨n, hn, ha⟩ := ha.exists_pow_eq_one + exact (pow_eq_one_iff_of_nonneg ha₀ hn.ne').1 ha + +end LinearOrderedSemiring + section LinearOrderedRing -variable [LinearOrderedRing G] {x : G} +variable [LinearOrderedRing G] {a x : G} + +protected lemma IsOfFinOrder.eq_neg_one (ha₀ : a ≤ 0) (ha : IsOfFinOrder a) : a = -1 := + (sq_eq_one_iff.1 $ ha.pow.eq_one $ sq_nonneg a).resolve_left $ by + rintro rfl; exact one_pos.not_le ha₀ theorem orderOf_abs_ne_one (h : |x| ≠ 1) : orderOf x = 0 := by rw [orderOf_eq_zero_iff'] diff --git a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean index cce1fca207d71..aacb97ec2f79f 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean @@ -978,7 +978,7 @@ theorem cycleOf_pow_apply_self (f : Perm α) (x : α) : ∀ n : ℕ, (cycleOf f induction' n with n hn · rfl · rw [pow_succ, mul_apply, cycleOf_apply, hn, if_pos, pow_succ, mul_apply] - simpa [SameCycle] using ⟨n,rfl⟩ + exact ⟨n, rfl⟩ #align equiv.perm.cycle_of_pow_apply_self Equiv.Perm.cycleOf_pow_apply_self @[simp] From 9d20fb4abbdd53d7d7bb274c7ed11cd2aa906f85 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Fri, 22 Dec 2023 13:50:36 +0000 Subject: [PATCH 127/353] fix: use `--install` flag in `lake update` hook (#9197) Fixes an issue [reported on Zulip](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/post-update.20hook.20failure/near/409543553). Without the `--install` flag elan will not download the new toolchain if it doesn't already have it. Since this is in an update call which is already expected to download things I think this should be okay. Co-authored-by: Mario Carneiro --- lakefile.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lakefile.lean b/lakefile.lean index 8d631ed24d682..40c372bfec165 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -93,7 +93,7 @@ post_update pkg do -/ let exitCode ← IO.Process.spawn { cmd := "elan" - args := #["run", mathlibToolchain.trim, "lake", "exe", "cache", "get"] + args := #["run", "--install", mathlibToolchain.trim, "lake", "exe", "cache", "get"] } >>= (·.wait) if exitCode ≠ 0 then logError s!"{pkg.name}: failed to fetch cache" From 623cc31f4dd18f45cd1a9901104271f1ba6328c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Dvo=C5=99=C3=A1k?= Date: Fri, 22 Dec 2023 14:46:31 +0000 Subject: [PATCH 128/353] feat(Computability/ContextFreeGrammar): derivations with prefix or postfix (#8630) --- Mathlib/Computability/ContextFreeGrammar.lean | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/Mathlib/Computability/ContextFreeGrammar.lean b/Mathlib/Computability/ContextFreeGrammar.lean index 28a9b0c085135..2a162da4e6029 100644 --- a/Mathlib/Computability/ContextFreeGrammar.lean +++ b/Mathlib/Computability/ContextFreeGrammar.lean @@ -6,7 +6,7 @@ Authors: Martin Dvorak import Mathlib.Computability.Language /-! -# Context-Free Grammar +# Context-Free Grammars This file contains the definition of a context-free grammar, which is a grammar that has a single nonterminal symbol on the left-hand side of each rule. @@ -51,11 +51,11 @@ inductive Rewrites (r : ContextFreeRule T N) : List (Symbol T N) → List (Symbo lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)} (hyp : r.Rewrites u v) : - ∃ p : List (Symbol T N), ∃ q : List (Symbol T N), + ∃ p q : List (Symbol T N), u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by induction hyp with - | head xs => - use [], xs + | head s => + use [], s simp | cons x _ ih => rcases ih with ⟨p', q', rfl, rfl⟩ @@ -76,6 +76,22 @@ theorem rewrites_iff {r : ContextFreeRule T N} (u v : List (Symbol T N)) : u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := ⟨Rewrites.exists_parts, by rintro ⟨p, q, rfl, rfl⟩; apply rewrites_of_exists_parts⟩ +/-- Add extra prefix to context-free rewriting. -/ +lemma Rewrites.append_left {r : ContextFreeRule T N} {v w : List (Symbol T N)} + (hvw : r.Rewrites v w) (p : List (Symbol T N)) : r.Rewrites (p ++ v) (p ++ w) := by + rw [rewrites_iff] at * + rcases hvw with ⟨x, y, hxy⟩ + use p ++ x, y + simp_all + +/-- Add extra postfix to context-free rewriting. -/ +lemma Rewrites.append_right {r : ContextFreeRule T N} {v w : List (Symbol T N)} + (hvw : r.Rewrites v w) (p : List (Symbol T N)) : r.Rewrites (v ++ p) (w ++ p) := by + rw [rewrites_iff] at * + rcases hvw with ⟨x, y, hxy⟩ + use x, y ++ p + simp_all + end ContextFreeRule namespace ContextFreeGrammar @@ -142,4 +158,32 @@ lemma Derives.eq_or_tail {u w : List (Symbol T g.NT)} (huw : g.Derives u w) : u = w ∨ ∃ v : List (Symbol T g.NT), g.Derives u v ∧ g.Produces v w := (Relation.ReflTransGen.cases_tail huw).casesOn (Or.inl ∘ Eq.symm) Or.inr +/-- Add extra prefix to context-free producing. -/ +lemma Produces.append_left {v w : List (Symbol T g.NT)} + (hvw : g.Produces v w) (p : List (Symbol T g.NT)) : + g.Produces (p ++ v) (p ++ w) := + match hvw with | ⟨r, hrmem, hrvw⟩ => ⟨r, hrmem, hrvw.append_left p⟩ + +/-- Add extra postfix to context-free producing. -/ +lemma Produces.append_right {v w : List (Symbol T g.NT)} + (hvw : g.Produces v w) (p : List (Symbol T g.NT)) : + g.Produces (v ++ p) (w ++ p) := + match hvw with | ⟨r, hrmem, hrvw⟩ => ⟨r, hrmem, hrvw.append_right p⟩ + +/-- Add extra prefix to context-free deriving. -/ +lemma Derives.append_left {v w : List (Symbol T g.NT)} + (hvw : g.Derives v w) (p : List (Symbol T g.NT)) : + g.Derives (p ++ v) (p ++ w) := by + induction hvw with + | refl => rfl + | tail _ last ih => exact ih.trans_produces $ last.append_left p + +/-- Add extra prefix to context-free deriving. -/ +lemma Derives.append_right {v w : List (Symbol T g.NT)} + (hvw : g.Derives v w) (p : List (Symbol T g.NT)) : + g.Derives (v ++ p) (w ++ p) := by + induction hvw with + | refl => rfl + | tail _ last ih => exact ih.trans_produces $ last.append_right p + end ContextFreeGrammar From e8851014c9641763b821bd101af090668517fd25 Mon Sep 17 00:00:00 2001 From: "Filippo A. E. Nuccio" Date: Fri, 22 Dec 2023 16:32:20 +0000 Subject: [PATCH 129/353] doc(Analysis.Complex.CauchyIntegral): add missing word (#9211) Replace "continuous the closed annulus" with " continuous on the closed annulus" --- Mathlib/Analysis/Complex/CauchyIntegral.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Analysis/Complex/CauchyIntegral.lean b/Mathlib/Analysis/Complex/CauchyIntegral.lean index 2b769651f152f..8c3df46ac0a3d 100644 --- a/Mathlib/Analysis/Complex/CauchyIntegral.lean +++ b/Mathlib/Analysis/Complex/CauchyIntegral.lean @@ -293,10 +293,10 @@ theorem integral_boundary_rect_eq_zero_of_differentiableOn (f : ℂ → E) (z w inter_subset_inter (preimage_mono Ioo_subset_Icc_self) (preimage_mono Ioo_subset_Icc_self) #align complex.integral_boundary_rect_eq_zero_of_differentiable_on Complex.integral_boundary_rect_eq_zero_of_differentiableOn -/-- If `f : ℂ → E` is continuous the closed annulus `r ≤ ‖z - c‖ ≤ R`, `0 < r ≤ R`, and is complex -differentiable at all but countably many points of its interior, then the integrals of -`f z / (z - c)` (formally, `(z - c)⁻¹ • f z`) over the circles `‖z - c‖ = r` and `‖z - c‖ = R` are -equal to each other. -/ +/-- If `f : ℂ → E` is continuous on the closed annulus `r ≤ ‖z - c‖ ≤ R`, `0 < r ≤ R`, +and is complex differentiable at all but countably many points of its interior, +then the integrals of `f z / (z - c)` (formally, `(z - c)⁻¹ • f z`) +over the circles `‖z - c‖ = r` and `‖z - c‖ = R` are equal to each other. -/ theorem circleIntegral_sub_center_inv_smul_eq_of_differentiable_on_annulus_off_countable {c : ℂ} {r R : ℝ} (h0 : 0 < r) (hle : r ≤ R) {f : ℂ → E} {s : Set ℂ} (hs : s.Countable) (hc : ContinuousOn f (closedBall c R \ ball c r)) From 07756d1c93a4359598a8cb64e0dad5437852db3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 22 Dec 2023 20:03:33 +0000 Subject: [PATCH 130/353] feat: Stabilizers of sets/finsets (#8924) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prove a bunch of results about `stabilizer G s` where `Group G`, `MulAction G α`, `s : Set α`. --- Mathlib.lean | 1 + Mathlib/Algebra/Pointwise/Stabilizer.lean | 171 +++++++++++++++++++++ Mathlib/GroupTheory/GroupAction/Basic.lean | 44 +++++- Mathlib/GroupTheory/QuotientGroup.lean | 28 +++- 4 files changed, 235 insertions(+), 9 deletions(-) create mode 100644 Mathlib/Algebra/Pointwise/Stabilizer.lean diff --git a/Mathlib.lean b/Mathlib.lean index 2891e7b5978eb..f6c157c8d77e1 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -426,6 +426,7 @@ import Mathlib.Algebra.PEmptyInstances import Mathlib.Algebra.PUnitInstances import Mathlib.Algebra.Parity import Mathlib.Algebra.Periodic +import Mathlib.Algebra.Pointwise.Stabilizer import Mathlib.Algebra.Polynomial.BigOperators import Mathlib.Algebra.Polynomial.GroupRingAction import Mathlib.Algebra.QuadraticDiscriminant diff --git a/Mathlib/Algebra/Pointwise/Stabilizer.lean b/Mathlib/Algebra/Pointwise/Stabilizer.lean new file mode 100644 index 0000000000000..e1208f005f674 --- /dev/null +++ b/Mathlib/Algebra/Pointwise/Stabilizer.lean @@ -0,0 +1,171 @@ +/- +Copyright (c) 2023 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +import Mathlib.Data.Finset.Pointwise +import Mathlib.GroupTheory.QuotientGroup + +/-! +# Stabilizer of a set under a pointwise action + +This file characterises the stabilizer of a set/finset under the pointwise action of a group. +-/ + +open Function MulOpposite Set +open scoped Pointwise + +namespace MulAction +variable {G H α : Type*} [Group G] [Group H] [MulAction G α] {a : G} + +/-! ### Stabilizer of a set -/ + +section Set + +@[to_additive (attr := simp)] +lemma stabilizer_empty : stabilizer G (∅ : Set α) = ⊤ := + Subgroup.coe_eq_univ.1 $ eq_univ_of_forall fun _a ↦ smul_set_empty + +@[to_additive (attr := simp)] +lemma stabilizer_singleton (b : α) : stabilizer G ({b} : Set α) = stabilizer G b := by ext; simp + +@[to_additive] +lemma mem_stabilizer_set {s : Set α} : a ∈ stabilizer G s ↔ ∀ b, a • b ∈ s ↔ b ∈ s := by + refine mem_stabilizer_iff.trans ⟨fun h b ↦ ?_, fun h ↦ ?_⟩ + · rw [← (smul_mem_smul_set_iff : a • b ∈ _ ↔ _), h] + simp_rw [Set.ext_iff, mem_smul_set_iff_inv_smul_mem] + exact ((MulAction.toPerm a).forall_congr' $ by simp [Iff.comm]).1 h + +@[to_additive] +lemma map_stabilizer_le (f : G →* H) (s : Set G) : + (stabilizer G s).map f ≤ stabilizer H (f '' s) := by + rintro a + simp only [Subgroup.mem_map, mem_stabilizer_iff, exists_prop, forall_exists_index, and_imp] + rintro a ha rfl + rw [← image_smul_distrib, ha] + +@[to_additive (attr := simp)] +lemma stabilizer_mul_self (s : Set G) : (stabilizer G s : Set G) * s = s := by + ext + refine ⟨?_, fun h ↦ ⟨_, _, (stabilizer G s).one_mem, h, one_mul _⟩⟩ + rintro ⟨a, b, ha, hb, rfl⟩ + rw [← mem_stabilizer_iff.1 ha] + exact smul_mem_smul_set hb + +end Set + +/-! ### Stabilizer of a subgroup -/ + +section Subgroup + +-- TODO: Is there a lemma that could unify the following three very similar lemmas? + +@[to_additive (attr := simp)] +lemma stabilizer_subgroup (s : Subgroup G) : stabilizer G (s : Set G) = s := by + simp_rw [SetLike.ext_iff, mem_stabilizer_set] + refine fun a ↦ ⟨fun h ↦ ?_, fun ha b ↦ s.mul_mem_cancel_left ha⟩ + simpa only [smul_eq_mul, SetLike.mem_coe, mul_one] using (h 1).2 s.one_mem + +@[to_additive (attr := simp)] +lemma stabilizer_op_subgroup (s : Subgroup G) : stabilizer Gᵐᵒᵖ (s : Set G) = s.op := by + simp_rw [SetLike.ext_iff, mem_stabilizer_set] + simp + refine fun a ↦ ⟨fun h ↦ ?_, fun ha b ↦ s.mul_mem_cancel_right ha⟩ + simpa only [op_smul_eq_mul, SetLike.mem_coe, one_mul] using (h 1).2 s.one_mem + +@[to_additive (attr := simp)] +lemma stabilizer_subgroup_op (s : Subgroup Gᵐᵒᵖ) : stabilizer G (s : Set Gᵐᵒᵖ) = s.unop := by + simp_rw [SetLike.ext_iff, mem_stabilizer_set] + refine fun a ↦ ⟨fun h ↦ ?_, fun ha b ↦ s.mul_mem_cancel_right ha⟩ + have : 1 * MulOpposite.op a ∈ s := (h 1).2 s.one_mem + simpa only [op_smul_eq_mul, SetLike.mem_coe, one_mul] using this + +end Subgroup + +/-! ### Stabilizer of a finset -/ + +section Finset +variable [DecidableEq α] + +@[to_additive (attr := simp)] +lemma stabilizer_coe_finset (s : Finset α) : stabilizer G (s : Set α) = stabilizer G s := by + ext; simp [← Finset.coe_inj] + +@[to_additive (attr := simp)] +lemma stabilizer_finset_empty : stabilizer G (∅ : Finset α) = ⊤ := + Subgroup.coe_eq_univ.1 $ eq_univ_of_forall Finset.smul_finset_empty + +@[to_additive (attr := simp)] +lemma stabilizer_finset_singleton (b : α) : stabilizer G ({b} : Finset α) = stabilizer G b := by + ext; simp + +@[to_additive] +lemma mem_stabilizer_finset {s : Finset α} : a ∈ stabilizer G s ↔ ∀ b, a • b ∈ s ↔ b ∈ s := by + simp_rw [← stabilizer_coe_finset, mem_stabilizer_set, Finset.mem_coe] + +@[to_additive] +lemma mem_stabilizer_finset_iff_subset_smul_finset {s : Finset α} : + a ∈ stabilizer G s ↔ s ⊆ a • s := by + rw [mem_stabilizer_iff, Finset.subset_iff_eq_of_card_le (Finset.card_smul_finset _ _).le, eq_comm] + +@[to_additive] +lemma mem_stabilizer_finset_iff_smul_finset_subset {s : Finset α} : + a ∈ stabilizer G s ↔ a • s ⊆ s := by + rw [mem_stabilizer_iff, Finset.subset_iff_eq_of_card_le (Finset.card_smul_finset _ _).ge] + +@[to_additive] +lemma mem_stabilizer_finset' {s : Finset α} : a ∈ stabilizer G s ↔ ∀ ⦃b⦄, b ∈ s → a • b ∈ s := by + rw [← Subgroup.inv_mem_iff, mem_stabilizer_finset_iff_subset_smul_finset] + simp_rw [← Finset.mem_inv_smul_finset_iff, Finset.subset_iff] + +end Finset + +/-! ### Stabilizer of a finite set -/ + +@[to_additive] +lemma mem_stabilizer_set_iff_subset_smul_set {s : Set α} (hs : s.Finite) : + a ∈ stabilizer G s ↔ s ⊆ a • s := by + lift s to Finset α using hs + classical + rw [stabilizer_coe_finset, mem_stabilizer_finset_iff_subset_smul_finset, ← Finset.coe_smul_finset, + Finset.coe_subset] + +@[to_additive] +lemma mem_stabilizer_set_iff_smul_set_subset {s : Set α} (hs : s.Finite) : + a ∈ stabilizer G s ↔ a • s ⊆ s := by + lift s to Finset α using hs + classical + rw [stabilizer_coe_finset, mem_stabilizer_finset_iff_smul_finset_subset, ← Finset.coe_smul_finset, + Finset.coe_subset] + +@[to_additive] +lemma mem_stabilizer_set' {s : Set α} (hs : s.Finite) : + a ∈ stabilizer G s ↔ ∀ ⦃b⦄, b ∈ s → a • b ∈ s := by + lift s to Finset α using hs + classical simp [-mem_stabilizer_iff, mem_stabilizer_finset'] + +end MulAction + +/-! ### Stabilizer in a commutative group -/ + +namespace MulAction +variable {G : Type*} [CommGroup G] (s : Set G) + +@[to_additive (attr := simp)] +lemma mul_stabilizer_self : s * stabilizer G s = s := by rw [mul_comm, stabilizer_mul_self] + +local notation " Q " => G ⧸ stabilizer G s +local notation " q " => ((↑) : G → Q) + +@[to_additive] +lemma stabilizer_image_coe_quotient : stabilizer Q (q '' s) = ⊥ := by + ext a + induction' a using QuotientGroup.induction_on' with a + simp only [mem_stabilizer_iff, Subgroup.mem_bot, QuotientGroup.eq_one_iff] + have : q a • q '' s = q '' (a • s) := + (image_smul_distrib (QuotientGroup.mk' $ stabilizer G s) _ _).symm + rw [this] + refine ⟨fun h ↦ ?_, fun h ↦ by rw [h]⟩ + rwa [QuotientGroup.image_coe_inj, mul_smul_comm, stabilizer_mul_self] at h + +end MulAction diff --git a/Mathlib/GroupTheory/GroupAction/Basic.lean b/Mathlib/GroupTheory/GroupAction/Basic.lean index f2e4bd4108e71..7e0ea96048ec1 100644 --- a/Mathlib/GroupTheory/GroupAction/Basic.lean +++ b/Mathlib/GroupTheory/GroupAction/Basic.lean @@ -224,13 +224,10 @@ theorem smul_cancel_of_non_zero_divisor {M R : Type*} [Monoid M] [NonUnitalNonAs #align smul_cancel_of_non_zero_divisor smul_cancel_of_non_zero_divisor namespace MulAction - -variable (G : Type u) [Group G] (α : Type v) [MulAction G α] +variable {G α β : Type*} [Group G] [MulAction G α] [MulAction G β] section Orbit -variable {G α} - @[to_additive (attr := simp)] theorem smul_orbit (g : G) (a : α) : g • orbit G a = orbit G a := (smul_orbit_subset g a).antisymm <| @@ -431,8 +428,7 @@ def selfEquivSigmaOrbits : α ≃ Σω : Ω, orbit G ω.out' := end Orbit section Stabilizer - -variable {α} +variable (G) /-- The stabilizer of an element under an action, i.e. what sends the element to itself. A subgroup. -/ @@ -457,6 +453,36 @@ theorem mem_stabilizer_iff {a : α} {g : G} : g ∈ stabilizer G a ↔ g • a = #align mul_action.mem_stabilizer_iff MulAction.mem_stabilizer_iff #align add_action.mem_stabilizer_iff AddAction.mem_stabilizer_iff +@[to_additive] +lemma le_stabilizer_smul_left [SMul α β] [IsScalarTower G α β] (a : α) (b : β) : + stabilizer G a ≤ stabilizer G (a • b) := by + simp_rw [SetLike.le_def, mem_stabilizer_iff, ← smul_assoc]; rintro a h; rw [h] + +@[to_additive] +lemma le_stabilizer_smul_right [SMul α β] [SMulCommClass G α β] (a : α) (b : β) : + stabilizer G b ≤ stabilizer G (a • b) := by + simp_rw [SetLike.le_def, mem_stabilizer_iff, smul_comm]; rintro a h; rw [h] + +@[to_additive (attr := simp)] +lemma stabilizer_smul_eq_left [SMul α β] [IsScalarTower G α β] (a : α) (b : β) + (h : Injective (· • b : α → β)) : stabilizer G (a • b) = stabilizer G a := by + refine' (le_stabilizer_smul_left _ _).antisymm' fun a ha ↦ _ + simpa only [mem_stabilizer_iff, ← smul_assoc, h.eq_iff] using ha + +@[to_additive (attr := simp)] +lemma stabilizer_smul_eq_right [Group α] [MulAction α β] [SMulCommClass G α β] (a : α) (b : β) : + stabilizer G (a • b) = stabilizer G b := + (le_stabilizer_smul_right _ _).antisymm' $ (le_stabilizer_smul_right a⁻¹ _).trans_eq $ by + rw [inv_smul_smul] + +@[to_additive (attr := simp)] +lemma stabilizer_mul_eq_left [Group α] [IsScalarTower G α α] (a b : α) : + stabilizer G (a * b) = stabilizer G a := stabilizer_smul_eq_left a _ $ mul_left_injective _ + +@[to_additive (attr := simp)] +lemma stabilizer_mul_eq_right [Group α] [SMulCommClass G α α] (a b : α) : + stabilizer G (a * b) = stabilizer G b := stabilizer_smul_eq_right a _ + /-- If the stabilizer of `a` is `S`, then the stabilizer of `g • a` is `gSg⁻¹`. -/ theorem stabilizer_smul_eq_stabilizer_map_conj (g : G) (a : α) : stabilizer G (g • a) = (stabilizer G a).map (MulAut.conj g).toMonoidHom := by @@ -480,8 +506,7 @@ end Stabilizer end MulAction namespace AddAction - -variable (G : Type u) [AddGroup G] (α : Type v) [AddAction G α] +variable {G α : Type*} [AddGroup G] [AddAction G α] /-- If the stabilizer of `x` is `S`, then the stabilizer of `g +ᵥ x` is `g + S + (-g)`. -/ theorem stabilizer_vadd_eq_stabilizer_map_conj (g : G) (a : α) : @@ -503,3 +528,6 @@ noncomputable def stabilizerEquivStabilizerOfOrbitRel {a b : α} (h : (orbitRel #align add_action.stabilizer_equiv_stabilizer_of_orbit_rel AddAction.stabilizerEquivStabilizerOfOrbitRel end AddAction + +attribute [to_additive existing] MulAction.stabilizer_smul_eq_stabilizer_map_conj +attribute [to_additive existing] MulAction.stabilizerEquivStabilizerOfOrbitRel diff --git a/Mathlib/GroupTheory/QuotientGroup.lean b/Mathlib/GroupTheory/QuotientGroup.lean index 4deb45abdf1ba..378904b0d9f61 100644 --- a/Mathlib/GroupTheory/QuotientGroup.lean +++ b/Mathlib/GroupTheory/QuotientGroup.lean @@ -41,8 +41,8 @@ proves Noether's first and second isomorphism theorems. isomorphism theorems, quotient groups -/ - open Function +open scoped Pointwise universe u v w x @@ -196,6 +196,8 @@ theorem mk_prod {G ι : Type*} [CommGroup G] (N : Subgroup G) (s : Finset ι) {f ((Finset.prod s f : G) : G ⧸ N) = Finset.prod s (fun i => (f i : G ⧸ N)) := map_prod (QuotientGroup.mk' N) _ _ +@[to_additive (attr := simp)] lemma map_mk'_self : N.map (mk' N) = ⊥ := by aesop + /-- A group homomorphism `φ : G →* M` with `N ⊆ ker(φ)` descends (i.e. `lift`s) to a group homomorphism `G/N →* M`. -/ @[to_additive "An `AddGroup` homomorphism `φ : G →+ M` with `N ⊆ ker(φ)` descends (i.e. `lift`s) @@ -291,6 +293,30 @@ theorem map_comp_map {I : Type*} [Group I] (M : Subgroup H) (O : Subgroup I) [M. #align quotient_group.map_comp_map QuotientGroup.map_comp_map #align quotient_add_group.map_comp_map QuotientAddGroup.map_comp_map +section Pointwise +open Set + +@[to_additive (attr := simp)] lemma image_coe : ((↑) : G → Q) '' N = 1 := + congr_arg ((↑) : Subgroup Q → Set Q) $ map_mk'_self N + +@[to_additive] +lemma preimage_image_coe (s : Set G) : ((↑) : G → Q) ⁻¹' ((↑) '' s) = N * s := by + ext a + constructor + · rintro ⟨b, hb, h⟩ + refine ⟨a / b, b, (QuotientGroup.eq_one_iff _).1 ?_, hb, div_mul_cancel' _ _⟩ + simp only [h, QuotientGroup.mk_div, div_self'] + · rintro ⟨a, b, ha, hb, rfl⟩ + refine ⟨b, hb, ?_⟩ + simpa only [QuotientGroup.mk_mul, self_eq_mul_left, QuotientGroup.eq_one_iff] + +@[to_additive] +lemma image_coe_inj {s t : Set G} : ((↑) : G → Q) '' s = ((↑) : G → Q) '' t ↔ ↑N * s = N * t := by + simp_rw [← preimage_image_coe] + exact QuotientGroup.mk_surjective.preimage_injective.eq_iff.symm + +end Pointwise + section congr variable (G' : Subgroup G) (H' : Subgroup H) [Subgroup.Normal G'] [Subgroup.Normal H'] From 763e4db0d9b64b9462d1e1ff24a84952442b9eef Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 20:59:50 +0000 Subject: [PATCH 131/353] chore(*): use `Set.image2_subset_iff` (#9206) Use `Set.image2_subset_iff`, `Set.mul_subset_iff`, and `Set.add_subset_iff` instead of `rintro`s. Also protect some `*.image2` lemmas. --- Mathlib/Analysis/LocallyConvex/Bounded.lean | 7 +-- Mathlib/GroupTheory/Submonoid/Pointwise.lean | 10 ++-- Mathlib/Order/Bounds/Basic.lean | 56 ++++++++++---------- Mathlib/RingTheory/Adjoin/FG.lean | 4 +- 4 files changed, 35 insertions(+), 42 deletions(-) diff --git a/Mathlib/Analysis/LocallyConvex/Bounded.lean b/Mathlib/Analysis/LocallyConvex/Bounded.lean index 30d5f00d87141..eaf0b967764dd 100644 --- a/Mathlib/Analysis/LocallyConvex/Bounded.lean +++ b/Mathlib/Analysis/LocallyConvex/Bounded.lean @@ -253,11 +253,8 @@ theorem TotallyBounded.isVonNBounded {s : Set E} (hs : TotallyBounded s) : rcases hs x.snd hx.2.1 with ⟨t, ht, hs⟩ refine' Absorbs.mono_right _ hs rw [ht.absorbs_iUnion] - have hx_fstsnd : x.fst + x.snd ⊆ U := by - intro z hz - rcases Set.mem_add.mp hz with ⟨z1, z2, hz1, hz2, hz⟩ - have hz' : (z1, z2) ∈ x.fst ×ˢ x.snd := ⟨hz1, hz2⟩ - simpa only [hz] using h'' hz' + have hx_fstsnd : x.fst + x.snd ⊆ U := add_subset_iff.mpr fun z1 hz1 z2 hz2 ↦ + h'' <| mk_mem_prod hz1 hz2 refine' fun y _ => Absorbs.mono_left _ hx_fstsnd rw [← Set.singleton_vadd, vadd_eq_add] exact (absorbent_nhds_zero hx.1.1).absorbs.add hx.2.2.absorbs_self diff --git a/Mathlib/GroupTheory/Submonoid/Pointwise.lean b/Mathlib/GroupTheory/Submonoid/Pointwise.lean index 405619340ac5a..9097eb3cbed15 100644 --- a/Mathlib/GroupTheory/Submonoid/Pointwise.lean +++ b/Mathlib/GroupTheory/Submonoid/Pointwise.lean @@ -57,9 +57,8 @@ namespace Submonoid variable {s t u : Set M} @[to_additive] -theorem mul_subset {S : Submonoid M} (hs : s ⊆ S) (ht : t ⊆ S) : s * t ⊆ S := by - rintro _ ⟨p, q, hp, hq, rfl⟩ - exact Submonoid.mul_mem _ (hs hp) (ht hq) +theorem mul_subset {S : Submonoid M} (hs : s ⊆ S) (ht : t ⊆ S) : s * t ⊆ S := + mul_subset_iff.2 fun _x hx _y hy ↦ mul_mem (hs hx) (ht hy) #align submonoid.mul_subset Submonoid.mul_subset #align add_submonoid.add_subset AddSubmonoid.add_subset @@ -593,9 +592,8 @@ theorem mul_le_mul_right {M N P : AddSubmonoid R} (h : N ≤ P) : M * N ≤ M * #align add_submonoid.mul_le_mul_right AddSubmonoid.mul_le_mul_right theorem mul_subset_mul {M N : AddSubmonoid R} : - (↑M : Set R) * (↑N : Set R) ⊆ (↑(M * N) : Set R) := by - rintro _ ⟨i, j, hi, hj, rfl⟩ - exact mul_mem_mul hi hj + (↑M : Set R) * (↑N : Set R) ⊆ (↑(M * N) : Set R) := + mul_subset_iff.2 fun _i hi _j hj ↦ mul_mem_mul hi hj #align add_submonoid.mul_subset_mul AddSubmonoid.mul_subset_mul end NonUnitalNonAssocSemiring diff --git a/Mathlib/Order/Bounds/Basic.lean b/Mathlib/Order/Bounds/Basic.lean index 540c92239ca5c..efd60bd90b38d 100644 --- a/Mathlib/Order/Bounds/Basic.lean +++ b/Mathlib/Order/Bounds/Basic.lean @@ -1374,35 +1374,34 @@ theorem mem_lowerBounds_image2 (ha : a ∈ lowerBounds s) (hb : b ∈ lowerBound #align mem_lower_bounds_image2 mem_lowerBounds_image2 theorem image2_upperBounds_upperBounds_subset : - image2 f (upperBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := by - rintro _ ⟨a, b, ha, hb, rfl⟩ - exact mem_upperBounds_image2 h₀ h₁ ha hb + image2 f (upperBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ mem_upperBounds_image2 h₀ h₁ ha hb #align image2_upper_bounds_upper_bounds_subset image2_upperBounds_upperBounds_subset theorem image2_lowerBounds_lowerBounds_subset : - image2 f (lowerBounds s) (lowerBounds t) ⊆ lowerBounds (image2 f s t) := by - rintro _ ⟨a, b, ha, hb, rfl⟩ - exact mem_lowerBounds_image2 h₀ h₁ ha hb + image2 f (lowerBounds s) (lowerBounds t) ⊆ lowerBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ mem_lowerBounds_image2 h₀ h₁ ha hb #align image2_lower_bounds_lower_bounds_subset image2_lowerBounds_lowerBounds_subset /-- See also `Monotone.map_bddAbove`. -/ -theorem BddAbove.image2 : BddAbove s → BddAbove t → BddAbove (image2 f s t) := by +protected theorem BddAbove.image2 : BddAbove s → BddAbove t → BddAbove (image2 f s t) := by rintro ⟨a, ha⟩ ⟨b, hb⟩ exact ⟨f a b, mem_upperBounds_image2 h₀ h₁ ha hb⟩ #align bdd_above.image2 BddAbove.image2 /-- See also `Monotone.map_bddBelow`. -/ -theorem BddBelow.image2 : BddBelow s → BddBelow t → BddBelow (image2 f s t) := by +protected theorem BddBelow.image2 : BddBelow s → BddBelow t → BddBelow (image2 f s t) := by rintro ⟨a, ha⟩ ⟨b, hb⟩ exact ⟨f a b, mem_lowerBounds_image2 h₀ h₁ ha hb⟩ #align bdd_below.image2 BddBelow.image2 -theorem IsGreatest.image2 (ha : IsGreatest s a) (hb : IsGreatest t b) : +protected theorem IsGreatest.image2 (ha : IsGreatest s a) (hb : IsGreatest t b) : IsGreatest (image2 f s t) (f a b) := ⟨mem_image2_of_mem ha.1 hb.1, mem_upperBounds_image2 h₀ h₁ ha.2 hb.2⟩ #align is_greatest.image2 IsGreatest.image2 -theorem IsLeast.image2 (ha : IsLeast s a) (hb : IsLeast t b) : IsLeast (image2 f s t) (f a b) := +protected theorem IsLeast.image2 (ha : IsLeast s a) (hb : IsLeast t b) : + IsLeast (image2 f s t) (f a b) := ⟨mem_image2_of_mem ha.1 hb.1, mem_lowerBounds_image2 h₀ h₁ ha.2 hb.2⟩ #align is_least.image2 IsLeast.image2 @@ -1423,15 +1422,15 @@ theorem mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds (ha : a ∈ #align mem_lower_bounds_image2_of_mem_lower_bounds_of_mem_upper_bounds mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds theorem image2_upperBounds_lowerBounds_subset_upperBounds_image2 : - image2 f (upperBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := by - rintro _ ⟨a, b, ha, hb, rfl⟩ - exact mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds h₀ h₁ ha hb + image2 f (upperBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds h₀ h₁ ha hb #align image2_upper_bounds_lower_bounds_subset_upper_bounds_image2 image2_upperBounds_lowerBounds_subset_upperBounds_image2 theorem image2_lowerBounds_upperBounds_subset_lowerBounds_image2 : - image2 f (lowerBounds s) (upperBounds t) ⊆ lowerBounds (image2 f s t) := by - rintro _ ⟨a, b, ha, hb, rfl⟩ - exact mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds h₀ h₁ ha hb + image2 f (lowerBounds s) (upperBounds t) ⊆ lowerBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds h₀ h₁ ha hb #align image2_lower_bounds_upper_bounds_subset_lower_bounds_image2 image2_lowerBounds_upperBounds_subset_lowerBounds_image2 theorem BddAbove.bddAbove_image2_of_bddBelow : @@ -1475,15 +1474,15 @@ theorem mem_lowerBounds_image2_of_mem_upperBounds (ha : a ∈ upperBounds s) #align mem_lower_bounds_image2_of_mem_upper_bounds mem_lowerBounds_image2_of_mem_upperBounds theorem image2_upperBounds_upperBounds_subset_upperBounds_image2 : - image2 f (lowerBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := by - rintro _ ⟨a, b, ha, hb, rfl⟩ - exact mem_upperBounds_image2_of_mem_lowerBounds h₀ h₁ ha hb + image2 f (lowerBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_upperBounds_image2_of_mem_lowerBounds h₀ h₁ ha hb #align image2_upper_bounds_upper_bounds_subset_upper_bounds_image2 image2_upperBounds_upperBounds_subset_upperBounds_image2 theorem image2_lowerBounds_lowerBounds_subset_lowerBounds_image2 : - image2 f (upperBounds s) (upperBounds t) ⊆ lowerBounds (image2 f s t) := by - rintro _ ⟨a, b, ha, hb, rfl⟩ - exact mem_lowerBounds_image2_of_mem_upperBounds h₀ h₁ ha hb + image2 f (upperBounds s) (upperBounds t) ⊆ lowerBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_lowerBounds_image2_of_mem_upperBounds h₀ h₁ ha hb #align image2_lower_bounds_lower_bounds_subset_lower_bounds_image2 image2_lowerBounds_lowerBounds_subset_lowerBounds_image2 theorem BddBelow.image2_bddAbove : BddBelow s → BddBelow t → BddAbove (Set.image2 f s t) := by @@ -1523,15 +1522,15 @@ theorem mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds (ha : a ∈ #align mem_lower_bounds_image2_of_mem_lower_bounds_of_mem_lower_bounds mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds theorem image2_lowerBounds_upperBounds_subset_upperBounds_image2 : - image2 f (lowerBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := by - rintro _ ⟨a, b, ha, hb, rfl⟩ - exact mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds h₀ h₁ ha hb + image2 f (lowerBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds h₀ h₁ ha hb #align image2_lower_bounds_upper_bounds_subset_upper_bounds_image2 image2_lowerBounds_upperBounds_subset_upperBounds_image2 theorem image2_upperBounds_lowerBounds_subset_lowerBounds_image2 : - image2 f (upperBounds s) (lowerBounds t) ⊆ lowerBounds (image2 f s t) := by - rintro _ ⟨a, b, ha, hb, rfl⟩ - exact mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds h₀ h₁ ha hb + image2 f (upperBounds s) (lowerBounds t) ⊆ lowerBounds (image2 f s t) := + image2_subset_iff.2 fun _ ha _ hb ↦ + mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds h₀ h₁ ha hb #align image2_upper_bounds_lower_bounds_subset_lower_bounds_image2 image2_upperBounds_lowerBounds_subset_lowerBounds_image2 theorem BddBelow.bddAbove_image2_of_bddAbove : @@ -1665,5 +1664,4 @@ protected theorem ScottContinuous.monotone (h : ScottContinuous f) : Monotone f exact isLeast_Ici #align scott_continuous.monotone ScottContinuous.monotone - end ScottContinuous diff --git a/Mathlib/RingTheory/Adjoin/FG.lean b/Mathlib/RingTheory/Adjoin/FG.lean index 466224222beb8..02ad6b3cc20b3 100644 --- a/Mathlib/RingTheory/Adjoin/FG.lean +++ b/Mathlib/RingTheory/Adjoin/FG.lean @@ -42,8 +42,8 @@ theorem fg_trans (h1 : (adjoin R s).toSubmodule.FG) (h2 : (adjoin (adjoin R s) t rcases fg_def.1 h1 with ⟨p, hp, hp'⟩ rcases fg_def.1 h2 with ⟨q, hq, hq'⟩ refine' fg_def.2 ⟨p * q, hp.mul hq, le_antisymm _ _⟩ - · rw [span_le] - rintro _ ⟨x, y, hx, hy, rfl⟩ + · rw [span_le, Set.mul_subset_iff] + intro x hx y hy change x * y ∈ adjoin R (s ∪ t) refine' Subalgebra.mul_mem _ _ _ · have : x ∈ Subalgebra.toSubmodule (adjoin R s) := by From 83012aa2231c7cea213101cf2ca2a99ab1e7ddcd Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 20:59:51 +0000 Subject: [PATCH 132/353] chore(Topology/../MulAction): golf (#9212) --- Mathlib/Topology/Algebra/MulAction.lean | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Mathlib/Topology/Algebra/MulAction.lean b/Mathlib/Topology/Algebra/MulAction.lean index c7f813cf9d6b1..bf4a50f84f0d5 100644 --- a/Mathlib/Topology/Algebra/MulAction.lean +++ b/Mathlib/Topology/Algebra/MulAction.lean @@ -148,17 +148,9 @@ lemma IsCompact.smul_set {k : Set M} {u : Set X} (hk : IsCompact k) (hu : IsComp @[to_additive] lemma smul_set_closure_subset (K : Set M) (L : Set X) : - closure K • closure L ⊆ closure (K • L) := by - rintro - ⟨x, y, hx, hy, rfl⟩ - apply mem_closure_iff_nhds.2 (fun u hu ↦ ?_) - have A : (fun p ↦ p.fst • p.snd) ⁻¹' u ∈ 𝓝 (x, y) := - (continuous_smul.continuousAt (x := (x, y))).preimage_mem_nhds hu - obtain ⟨a, ha, b, hb, hab⟩ : - ∃ a, a ∈ 𝓝 x ∧ ∃ b, b ∈ 𝓝 y ∧ a ×ˢ b ⊆ (fun p ↦ p.fst • p.snd) ⁻¹' u := - mem_nhds_prod_iff.1 A - obtain ⟨x', ⟨x'a, x'K⟩⟩ : Set.Nonempty (a ∩ K) := mem_closure_iff_nhds.1 hx a ha - obtain ⟨y', ⟨y'b, y'L⟩⟩ : Set.Nonempty (b ∩ L) := mem_closure_iff_nhds.1 hy b hb - exact ⟨x' • y', hab (Set.mk_mem_prod x'a y'b), Set.smul_mem_smul x'K y'L⟩ + closure K • closure L ⊆ closure (K • L) := + Set.smul_subset_iff.2 fun _x hx _y hy ↦ map_mem_closure₂ continuous_smul hx hy fun _a ha _b hb ↦ + Set.smul_mem_smul ha hb end SMul From 1462ef73241f5758f11cdac7763f2ceb9ab82a7f Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 20:59:52 +0000 Subject: [PATCH 133/353] chore(Normed/../AddTorsor): improve readability (#9213) Pass more arguments to `choose!` to avoid using projections later in the proof. --- Mathlib/Analysis/Normed/Group/AddTorsor.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Analysis/Normed/Group/AddTorsor.lean b/Mathlib/Analysis/Normed/Group/AddTorsor.lean index 5169edbdbe15c..3ce4aa579472c 100644 --- a/Mathlib/Analysis/Normed/Group/AddTorsor.lean +++ b/Mathlib/Analysis/Normed/Group/AddTorsor.lean @@ -326,11 +326,11 @@ theorem IsClosed.vadd_right_of_isCompact {s : Set V} {t : Set P} (hs : IsClosed -- This result is still true for any `AddTorsor` where `-ᵥ` is continuous, -- but we don't yet have a nice way to state it. refine IsSeqClosed.isClosed (fun u p husv hup ↦ ?_) - choose! a v hav using husv - rcases ht.isSeqCompact fun n ↦ (hav n).2.1 with ⟨q, hqt, φ, φ_mono, hφq⟩ + choose! a v ha hv hav using husv + rcases ht.isSeqCompact hv with ⟨q, hqt, φ, φ_mono, hφq⟩ refine ⟨p -ᵥ q, q, hs.mem_of_tendsto ((hup.comp φ_mono.tendsto_atTop).vsub hφq) (eventually_of_forall fun n ↦ ?_), hqt, vsub_vadd _ _⟩ - convert (hav (φ n)).1 using 1 - exact (eq_vadd_iff_vsub_eq _ _ _).mp (hav (φ n)).2.2.symm + convert ha (φ n) using 1 + exact (eq_vadd_iff_vsub_eq _ _ _).mp (hav (φ n)).symm end Pointwise From eb17faa563b436797bb84be190443cbb06ff5ef2 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 20:59:53 +0000 Subject: [PATCH 134/353] chore(Set/Pointwise/Finite): golf (#9214) --- Mathlib/Data/Set/Pointwise/Finite.lean | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Mathlib/Data/Set/Pointwise/Finite.lean b/Mathlib/Data/Set/Pointwise/Finite.lean index f65d3b16657bb..83e0089f05e21 100644 --- a/Mathlib/Data/Set/Pointwise/Finite.lean +++ b/Mathlib/Data/Set/Pointwise/Finite.lean @@ -179,11 +179,10 @@ variable {G : Type*} [Group G] [Fintype G] (S : Set G) @[to_additive] theorem card_pow_eq_card_pow_card_univ [∀ k : ℕ, DecidablePred (· ∈ S ^ k)] : ∀ k, Fintype.card G ≤ k → Fintype.card (↥(S ^ k)) = Fintype.card (↥(S ^ Fintype.card G)) := by - have hG : 0 < Fintype.card G := Fintype.card_pos_iff.mpr ⟨1⟩ - by_cases hS : S = ∅ + have hG : 0 < Fintype.card G := Fintype.card_pos + rcases S.eq_empty_or_nonempty with (rfl | ⟨a, ha⟩) · refine' fun k hk ↦ Fintype.card_congr _ - rw [hS, empty_pow (ne_of_gt (lt_of_lt_of_le hG hk)), empty_pow (ne_of_gt hG)] - obtain ⟨a, ha⟩ := Set.nonempty_iff_ne_empty.2 hS + rw [empty_pow (hG.trans_le hk).ne', empty_pow (ne_of_gt hG)] have key : ∀ (a) (s t : Set G) [Fintype s] [Fintype t], (∀ b : G, b ∈ s → a * b ∈ t) → Fintype.card s ≤ Fintype.card t := by refine' fun a s t _ _ h ↦ Fintype.card_le_of_injective (fun ⟨b, hb⟩ ↦ ⟨a * b, h b hb⟩) _ @@ -200,9 +199,9 @@ theorem card_pow_eq_card_pow_card_univ [∀ k : ℕ, DecidablePred (· ∈ S ^ k refine' Set.eq_of_subset_of_card_le _ (le_trans (ge_of_eq h) _) · exact mul_subset_mul (Set.singleton_subset_iff.mpr ha) Set.Subset.rfl · convert key a (S ^ n) ({a} * S ^ n) fun b hb ↦ Set.mul_mem_mul (Set.mem_singleton a) hb - rw [pow_succ', ← h₂, mul_assoc, ← pow_succ', h₂] - rintro _ ⟨b, c, hb, hc, rfl⟩ - rwa [Set.mem_singleton_iff.mp hb, inv_mul_cancel_left] + rw [pow_succ', ← h₂, mul_assoc, ← pow_succ', h₂, singleton_mul, ball_image_iff] + intro x hx + rwa [inv_mul_cancel_left] #align group.card_pow_eq_card_pow_card_univ Group.card_pow_eq_card_pow_card_univ #align add_group.card_nsmul_eq_card_nsmul_card_univ AddGroup.card_nsmul_eq_card_nsmul_card_univ From 03289344716225f680d691309eb28e215f52f731 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 20:59:54 +0000 Subject: [PATCH 135/353] chore(Algebra/FilterBasis): use `mul_mem_mul` to improve readability (#9216) --- Mathlib/Topology/Algebra/FilterBasis.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Algebra/FilterBasis.lean b/Mathlib/Topology/Algebra/FilterBasis.lean index 980f3b1320aef..8f42d54665f3f 100644 --- a/Mathlib/Topology/Algebra/FilterBasis.lean +++ b/Mathlib/Topology/Algebra/FilterBasis.lean @@ -251,7 +251,7 @@ instance (priority := 100) isTopologicalGroup (B : GroupFilterBasis G) : rcases mul U_in with ⟨V, V_in, hV⟩ refine' ⟨V, V, ⟨V_in, V_in⟩, _⟩ intro a b a_in b_in - exact hV ⟨a, b, a_in, b_in, rfl⟩ + exact hV <| mul_mem_mul a_in b_in · rw [basis.tendsto_iff basis] intro U U_in simpa using inv U_in @@ -318,7 +318,7 @@ instance (priority := 100) isTopologicalRing {R : Type u} [Ring R] (B : RingFilt rcases B.mul U_in with ⟨V, V_in, hV⟩ refine' ⟨V, V, ⟨V_in, V_in⟩, _⟩ intro a b a_in b_in - exact hV ⟨a, b, a_in, b_in, rfl⟩ + exact hV <| mul_mem_mul a_in b_in · intro x₀ rw [basis.tendsto_iff basis] intro U From 090f9f77052de2983217e53b284a14f1cb0b13b6 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 20:59:55 +0000 Subject: [PATCH 136/353] chore(Computability/RegularExpressions): golf (#9218) Golf a proof. Also add `Language.mem_kstar_iff_exists_nonempty`. --- Mathlib/Computability/Language.lean | 9 ++-- Mathlib/Computability/RegularExpressions.lean | 42 ++++--------------- 2 files changed, 14 insertions(+), 37 deletions(-) diff --git a/Mathlib/Computability/Language.lean b/Mathlib/Computability/Language.lean index d61641681a51a..41378c7724bf4 100644 --- a/Mathlib/Computability/Language.lean +++ b/Mathlib/Computability/Language.lean @@ -173,9 +173,8 @@ theorem map_map (g : β → γ) (f : α → β) (l : Language α) : map g (map f simp [map, image_image] #align language.map_map Language.map_map -theorem kstar_def_nonempty (l : Language α) : - l∗ = { x | ∃ S : List (List α), x = S.join ∧ ∀ y ∈ S, y ∈ l ∧ y ≠ [] } := by - ext x +lemma mem_kstar_iff_exists_nonempty {x : List α} : + x ∈ l∗ ↔ ∃ S : List (List α), x = S.join ∧ ∀ y ∈ S, y ∈ l ∧ y ≠ [] := by constructor · rintro ⟨S, rfl, h⟩ refine' ⟨S.filter fun l ↦ ¬List.isEmpty l, by simp, fun y hy ↦ _⟩ @@ -186,6 +185,10 @@ theorem kstar_def_nonempty (l : Language α) : exact ⟨h y hy.1, hy.2⟩ · rintro ⟨S, hx, h⟩ exact ⟨S, hx, fun y hy ↦ (h y hy).1⟩ + +theorem kstar_def_nonempty (l : Language α) : + l∗ = { x | ∃ S : List (List α), x = S.join ∧ ∀ y ∈ S, y ∈ l ∧ y ≠ [] } := by + ext x; apply mem_kstar_iff_exists_nonempty #align language.kstar_def_nonempty Language.kstar_def_nonempty theorem le_iff (l m : Language α) : l ≤ m ↔ l + m = m := diff --git a/Mathlib/Computability/RegularExpressions.lean b/Mathlib/Computability/RegularExpressions.lean index ad8c5d8c4cb1b..0571a9bac91ed 100644 --- a/Mathlib/Computability/RegularExpressions.lean +++ b/Mathlib/Computability/RegularExpressions.lean @@ -347,52 +347,26 @@ theorem star_rmatch_iff (P : RegularExpression α) : #align regular_expression.star_rmatch_iff RegularExpression.star_rmatch_iff @[simp] -theorem rmatch_iff_matches' (P : RegularExpression α) : - ∀ x : List α, P.rmatch x ↔ x ∈ P.matches' := by - intro x +theorem rmatch_iff_matches' (P : RegularExpression α) (x : List α) : + P.rmatch x ↔ x ∈ P.matches' := by induction P generalizing x - all_goals - try rw [zero_def] - try rw [one_def] - try rw [plus_def] - try rw [comp_def] case zero => - rw [zero_rmatch] + rw [zero_def, zero_rmatch] tauto case epsilon => - rw [one_rmatch_iff] + rw [one_def, one_rmatch_iff] rfl case char => rw [char_rmatch_iff] rfl case plus _ _ ih₁ ih₂ => - rw [add_rmatch_iff, ih₁, ih₂] + rw [plus_def, add_rmatch_iff, ih₁, ih₂] rfl case comp P Q ih₁ ih₂ => - simp only [mul_rmatch_iff, comp_def, Language.mul_def, exists_and_left, Set.mem_image2, - Set.image_prod] - constructor - · rintro ⟨x, y, hsum, hmatch₁, hmatch₂⟩ - rw [ih₁] at hmatch₁ - rw [ih₂] at hmatch₂ - exact ⟨x, y, hmatch₁, hmatch₂, hsum.symm⟩ - · rintro ⟨x, y, hmatch₁, hmatch₂, hsum⟩ - rw [← ih₁] at hmatch₁ - rw [← ih₂] at hmatch₂ - exact ⟨x, y, hsum.symm, hmatch₁, hmatch₂⟩ + simp only [comp_def, mul_rmatch_iff, matches'_mul, Language.mem_mul, *] + tauto case star _ ih => - rw [star_rmatch_iff] - simp only [ne_eq, matches', Language.kstar_def_nonempty, mem_setOf_eq] - constructor - all_goals - rintro ⟨S, hx, hS⟩ - refine' ⟨S, hx, _⟩ - intro y - specialize hS y - · rw [← ih y] - tauto - · rw [ih y] - tauto + simp only [star_rmatch_iff, matches'_star, ih, Language.mem_kstar_iff_exists_nonempty, and_comm] #align regular_expression.rmatch_iff_matches RegularExpression.rmatch_iff_matches' instance (P : RegularExpression α) : DecidablePred (· ∈ P.matches') := fun _ ↦ From 21e45c8b00b52c102e804b9df4bca053a6e80bcd Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 20:59:56 +0000 Subject: [PATCH 137/353] chore(Set/NAry): drop `Set.image3` (#9221) `Set.image3` was only used to prove associativity of `Set.image2`. It had basically no API and had exactly one (easily replaced) use outside `Data.Set.NAry`). There is no specific function as a replacement, but it can be obtained by combining `Set.image2` twice. --- Mathlib/Data/Set/Lattice.lean | 3 +- Mathlib/Data/Set/NAry.lean | 69 ++++++----------------------------- 2 files changed, 13 insertions(+), 59 deletions(-) diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index 972edef21ac7a..c0677fbdf79ec 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -2117,7 +2117,8 @@ theorem seq_singleton {s : Set (α → β)} {a : α} : Set.seq s {a} = (fun f : theorem seq_seq {s : Set (β → γ)} {t : Set (α → β)} {u : Set α} : seq s (seq t u) = seq (seq ((· ∘ ·) '' s) t) u := by - simp only [seq_eq_image2, image2_image_left, image2_image2_left, image2_image2_right, comp_apply] + simp only [seq_eq_image2, image2_image_left] + exact .symm <| image2_assoc fun _ _ _ ↦ rfl #align set.seq_seq Set.seq_seq theorem image_seq {f : β → γ} {s : Set (α → β)} {t : Set α} : diff --git a/Mathlib/Data/Set/NAry.lean b/Mathlib/Data/Set/NAry.lean index e162a2aa89e33..c149dfbacb515 100644 --- a/Mathlib/Data/Set/NAry.lean +++ b/Mathlib/Data/Set/NAry.lean @@ -17,10 +17,6 @@ This is mostly useful to define pointwise operations and `Set.seq`. This file is very similar to `Data.Finset.NAry`, to `Order.Filter.NAry`, and to `Data.Option.NAry`. Please keep them in sync. - -We also define `Set.image3`. -Its only purpose is to prove properties of `Set.image2`, -and it should be rarely used outside of this file. -/ open Function @@ -219,62 +215,17 @@ theorem image2_congr' (h : ∀ a b, f a b = f' a b) : image2 f s t = image2 f' s image2_congr fun a _ b _ => h a b #align set.image2_congr' Set.image2_congr' -/-- The image of a ternary function `f : α → β → γ → δ` as a function - `Set α → Set β → Set γ → Set δ`. Mathematically this should be thought of as the image of the - corresponding function `α × β × γ → δ`. --/ -def image3 (g : α → β → γ → δ) (s : Set α) (t : Set β) (u : Set γ) : Set δ := - { d | ∃ a b c, a ∈ s ∧ b ∈ t ∧ c ∈ u ∧ g a b c = d } -#align set.image3 Set.image3 - -@[simp] -theorem mem_image3 : d ∈ image3 g s t u ↔ ∃ a b c, a ∈ s ∧ b ∈ t ∧ c ∈ u ∧ g a b c = d := - Iff.rfl -#align set.mem_image3 Set.mem_image3 - -theorem image3_mono (hs : s ⊆ s') (ht : t ⊆ t') (hu : u ⊆ u') : - image3 g s t u ⊆ image3 g s' t' u' := fun _ => - Exists₃.imp fun _ _ _ ⟨ha, hb, hc, hx⟩ => ⟨hs ha, ht hb, hu hc, hx⟩ -#align set.image3_mono Set.image3_mono - -@[congr] -theorem image3_congr (h : ∀ a ∈ s, ∀ b ∈ t, ∀ c ∈ u, g a b c = g' a b c) : - image3 g s t u = image3 g' s t u := by - ext x - constructor <;> rintro ⟨a, b, c, ha, hb, hc, rfl⟩ <;> - exact ⟨a, b, c, ha, hb, hc, by rw [h a ha b hb c hc]⟩ -#align set.image3_congr Set.image3_congr - -/-- A common special case of `image3_congr` -/ -theorem image3_congr' (h : ∀ a b c, g a b c = g' a b c) : image3 g s t u = image3 g' s t u := - image3_congr fun a _ b _ c _ => h a b c -#align set.image3_congr' Set.image3_congr' - -theorem image2_image2_left (f : δ → γ → ε) (g : α → β → δ) : - image2 f (image2 g s t) u = image3 (fun a b c => f (g a b) c) s t u := by - ext; constructor - · rintro ⟨_, c, ⟨a, b, ha, hb, rfl⟩, hc, rfl⟩ - refine' ⟨a, b, c, ha, hb, hc, rfl⟩ - · rintro ⟨a, b, c, ha, hb, hc, rfl⟩ - refine' ⟨_, c, ⟨a, b, ha, hb, rfl⟩, hc, rfl⟩ -#align set.image2_image2_left Set.image2_image2_left - -theorem image2_image2_right (f : α → δ → ε) (g : β → γ → δ) : - image2 f s (image2 g t u) = image3 (fun a b c => f a (g b c)) s t u := by - ext; constructor - · rintro ⟨a, _, ha, ⟨b, c, hb, hc, rfl⟩, rfl⟩ - refine' ⟨a, b, c, ha, hb, hc, rfl⟩ - · rintro ⟨a, b, c, ha, hb, hc, rfl⟩ - refine' ⟨a, _, ha, ⟨b, c, hb, hc, rfl⟩, rfl⟩ -#align set.image2_image2_right Set.image2_image2_right +#noalign set.image3 +#noalign set.mem_image3 +#noalign set.image3_mono +#noalign set.image3_congr +#noalign set.image3_congr' +#noalign set.image2_image2_left +#noalign set.image2_image2_right theorem image_image2 (f : α → β → γ) (g : γ → δ) : g '' image2 f s t = image2 (fun a b => g (f a b)) s t := by - ext; constructor - · rintro ⟨_, ⟨a, b, ha, hb, rfl⟩, rfl⟩ - refine' ⟨a, b, ha, hb, rfl⟩ - · rintro ⟨a, b, ha, hb, rfl⟩ - refine' ⟨_, ⟨a, b, ha, hb, rfl⟩, rfl⟩ + simp only [← image_prod, image_image] #align set.image_image2 Set.image_image2 theorem image2_image_left (f : γ → β → δ) (g : α → γ) : @@ -300,7 +251,9 @@ theorem image2_right (h : s.Nonempty) : image2 (fun _ y => y) s t = t := by theorem image2_assoc {f : δ → γ → ε} {g : α → β → δ} {f' : α → ε' → ε} {g' : β → γ → ε'} (h_assoc : ∀ a b c, f (g a b) c = f' a (g' b c)) : image2 f (image2 g s t) u = image2 f' s (image2 g' t u) := by - simp only [image2_image2_left, image2_image2_right, h_assoc] + rw [← image_prod g, ← image_prod g', image2_image_left, image2_image_right] + ext + simp only [mem_image2, Prod.exists, h_assoc, prod_mk_mem_set_prod_eq, and_assoc] #align set.image2_assoc Set.image2_assoc theorem image2_comm {g : β → α → γ} (h_comm : ∀ a b, f a b = g b a) : image2 f s t = image2 g t s := From 7eda28cd2baf049bdaca746d66ffbee1c0f74d4b Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Fri, 22 Dec 2023 16:37:46 -0500 Subject: [PATCH 138/353] chore: bump lean to lean4#3084 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 2dfbd8295af30..447d6134b3dff 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-19 +leanprover/lean4-pr-releases:pr-release-3084 From 3b841d12b5b046bbe24b055b4331f6ca501c6bd0 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 22:10:08 +0000 Subject: [PATCH 139/353] doc(Filter/Pointwise): fix comments (#9202) --- Mathlib/Order/Filter/Pointwise.lean | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Mathlib/Order/Filter/Pointwise.lean b/Mathlib/Order/Filter/Pointwise.lean index 69a10231cf860..928159c1d38e5 100644 --- a/Mathlib/Order/Filter/Pointwise.lean +++ b/Mathlib/Order/Filter/Pointwise.lean @@ -290,8 +290,8 @@ variable [Mul α] [Mul β] {f f₁ f₂ g g₁ g₂ h : Filter α} {s t : Set α /-- The filter `f * g` is generated by `{s * t | s ∈ f, t ∈ g}` in locale `Pointwise`. -/ @[to_additive "The filter `f + g` is generated by `{s + t | s ∈ f, t ∈ g}` in locale `Pointwise`."] protected def instMul : Mul (Filter α) := - ⟨/- This is defeq to `map₂ (*) f g`, but the hypothesis unfolds to `t₁ * t₂ ⊆ s` rather - than all the way to `Set.image2 (*) t₁ t₂ ⊆ s`. -/ + ⟨/- This is defeq to `map₂ (· * ·) f g`, but the hypothesis unfolds to `t₁ * t₂ ⊆ s` rather + than all the way to `Set.image2 (· * ·) t₁ t₂ ⊆ s`. -/ fun f g => { map₂ (· * ·) f g with sets := { s | ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ * t₂ ⊆ s } }⟩ #align filter.has_mul Filter.instMul #align filter.has_add Filter.instAdd @@ -435,8 +435,8 @@ variable [Div α] {f f₁ f₂ g g₁ g₂ h : Filter α} {s t : Set α} {a b : /-- The filter `f / g` is generated by `{s / t | s ∈ f, t ∈ g}` in locale `Pointwise`. -/ @[to_additive "The filter `f - g` is generated by `{s - t | s ∈ f, t ∈ g}` in locale `Pointwise`."] protected def instDiv : Div (Filter α) := - ⟨/- This is defeq to `map₂ (/) f g`, but the hypothesis unfolds to `t₁ / t₂ ⊆ s` rather than all - the way to `Set.image2 (/) t₁ t₂ ⊆ s`. -/ + ⟨/- This is defeq to `map₂ (· / ·) f g`, but the hypothesis unfolds to `t₁ / t₂ ⊆ s` + rather than all the way to `Set.image2 (· / ·) t₁ t₂ ⊆ s`. -/ fun f g => { map₂ (· / ·) f g with sets := { s | ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ / t₂ ⊆ s } }⟩ #align filter.has_div Filter.instDiv #align filter.has_sub Filter.instSub @@ -963,8 +963,8 @@ variable [SMul α β] {f f₁ f₂ : Filter α} {g g₁ g₂ h : Filter β} {s : @[to_additive "The filter `f +ᵥ g` is generated by `{s +ᵥ t | s ∈ f, t ∈ g}` in locale `Pointwise`."] protected def instSMul : SMul (Filter α) (Filter β) := - ⟨/- This is defeq to `map₂ (•) f g`, but the hypothesis unfolds to `t₁ • t₂ ⊆ s` rather than all - the way to `Set.image2 (•) t₁ t₂ ⊆ s`. -/ + ⟨/- This is defeq to `map₂ (· • ·) f g`, but the hypothesis unfolds to `t₁ • t₂ ⊆ s` + rather than all the way to `Set.image2 (· • ·) t₁ t₂ ⊆ s`. -/ fun f g => { map₂ (· • ·) f g with sets := { s | ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ • t₂ ⊆ s } }⟩ #align filter.has_smul Filter.instSMul #align filter.has_vadd Filter.instVAdd From 503aade4d0e7ff8a311f99e9a1f57f43ec5d3cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 22 Dec 2023 22:10:09 +0000 Subject: [PATCH 140/353] feat: Antidiagonal lemmas (#9224) From LeanAPAP --- Mathlib/Data/Finset/Antidiagonal.lean | 31 +++++++++++++++++++----- Mathlib/Data/Finset/NatAntidiagonal.lean | 17 +++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Mathlib/Data/Finset/Antidiagonal.lean b/Mathlib/Data/Finset/Antidiagonal.lean index e7c0e8f21ad13..86d9c25a68108 100644 --- a/Mathlib/Data/Finset/Antidiagonal.lean +++ b/Mathlib/Data/Finset/Antidiagonal.lean @@ -94,9 +94,14 @@ theorem swap_mem_antidiagonal [AddCommMonoid A] [HasAntidiagonal A] {n : A} {xy map_prodComm_antidiagonal #align finset.nat.map_swap_antidiagonal Finset.map_swap_antidiagonal -/-- A point in the antidiagonal is determined by its first co-ordinate. -/ -theorem antidiagonal_congr [AddCancelMonoid A] [HasAntidiagonal A] {n : A} {p q : A × A} - (hp : p ∈ antidiagonal n) (hq : q ∈ antidiagonal n) : p = q ↔ p.fst = q.fst := by +section AddCancelMonoid +variable [AddCancelMonoid A] [HasAntidiagonal A] {p q : A × A} {n : A} + +/-- A point in the antidiagonal is determined by its first coordinate. + +See also `Finset.antidiagonal_congr'`. -/ +theorem antidiagonal_congr (hp : p ∈ antidiagonal n) (hq : q ∈ antidiagonal n) : + p = q ↔ p.1 = q.1 := by refine' ⟨congr_arg Prod.fst, fun h ↦ Prod.ext h ((add_right_inj q.fst).mp _)⟩ rw [mem_antidiagonal] at hp hq rw [hq, ← h, hp] @@ -104,9 +109,23 @@ theorem antidiagonal_congr [AddCancelMonoid A] [HasAntidiagonal A] {n : A} {p q /-- A point in the antidiagonal is determined by its first co-ordinate (subtype version of `Finset.antidiagonal_congr`). This lemma is used by the `ext` tactic. -/ -@[ext] theorem antidiagonal_subtype_ext [AddCancelMonoid A] [HasAntidiagonal A] - {n : A} {p q : antidiagonal n} (h : p.val.1 = q.val.1) : - p = q := Subtype.ext ((antidiagonal_congr p.prop q.prop).mpr h) +@[ext] theorem antidiagonal_subtype_ext {p q : antidiagonal n} (h : p.val.1 = q.val.1) : p = q := + Subtype.ext ((antidiagonal_congr p.prop q.prop).mpr h) + +end AddCancelMonoid + +section AddCancelCommMonoid +variable [AddCancelCommMonoid A] [HasAntidiagonal A] {p q : A × A} {n : A} + +/-- A point in the antidiagonal is determined by its second coordinate. + +See also `Finset.antidiagonal_congr`. -/ +lemma antidiagonal_congr' (hp : p ∈ antidiagonal n) (hq : q ∈ antidiagonal n) : + p = q ↔ p.2 = q.2 := by + rw [← Prod.swap_inj] + exact antidiagonal_congr (swap_mem_antidiagonal.2 hp) (swap_mem_antidiagonal.2 hq) + +end AddCancelCommMonoid section CanonicallyOrderedAddCommMonoid variable [CanonicallyOrderedAddCommMonoid A] [HasAntidiagonal A] diff --git a/Mathlib/Data/Finset/NatAntidiagonal.lean b/Mathlib/Data/Finset/NatAntidiagonal.lean index ae6a9c67e5890..7a0c66b041439 100644 --- a/Mathlib/Data/Finset/NatAntidiagonal.lean +++ b/Mathlib/Data/Finset/NatAntidiagonal.lean @@ -35,6 +35,23 @@ instance instHasAntidiagonal : HasAntidiagonal ℕ where mem_antidiagonal {n} {xy} := by rw [mem_def, Multiset.Nat.mem_antidiagonal] +lemma antidiagonal_eq_map (n : ℕ) : + antidiagonal n = (range (n + 1)).map ⟨fun i ↦ (i, n - i), fun _ _ h ↦ (Prod.ext_iff.1 h).1⟩ := + rfl + +lemma antidiagonal_eq_map' (n : ℕ) : + antidiagonal n = + (range (n + 1)).map ⟨fun i ↦ (n - i, i), fun _ _ h ↦ (Prod.ext_iff.1 h).2⟩ := by + rw [← map_swap_antidiagonal, antidiagonal_eq_map, map_map]; rfl + +lemma antidiagonal_eq_image (n : ℕ) : + antidiagonal n = (range (n + 1)).image fun i ↦ (i, n - i) := by + simp only [antidiagonal_eq_map, map_eq_image, Function.Embedding.coeFn_mk] + +lemma antidiagonal_eq_image' (n : ℕ) : + antidiagonal n = (range (n + 1)).image fun i ↦ (n - i, i) := by + simp only [antidiagonal_eq_map', map_eq_image, Function.Embedding.coeFn_mk] + /-- The cardinality of the antidiagonal of `n` is `n + 1`. -/ @[simp] theorem card_antidiagonal (n : ℕ) : (antidiagonal n).card = n + 1 := by simp [antidiagonal] From 36ed38da4322ed83da53a07bc58a4b374d2d173c Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Fri, 22 Dec 2023 17:15:04 -0500 Subject: [PATCH 141/353] fix: adapt to lean4#3084 --- Mathlib/Tactic/Cases.lean | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Mathlib/Tactic/Cases.lean b/Mathlib/Tactic/Cases.lean index 42da5cf508638..39ef2f371ba90 100644 --- a/Mathlib/Tactic/Cases.lean +++ b/Mathlib/Tactic/Cases.lean @@ -40,7 +40,8 @@ open Lean Meta Elab Elab.Tactic open private getAltNumFields in evalCases ElimApp.evalAlts.go in def ElimApp.evalNames (elimInfo : ElimInfo) (alts : Array ElimApp.Alt) (withArg : Syntax) - (numEqs := 0) (numGeneralized := 0) (toClear : Array FVarId := #[]) : + (numEqs := 0) (generalized : Array FVarId := #[]) (toClear : Array FVarId := #[]) + (toTag : Array (Ident × FVarId) := #[]) : TermElabM (Array MVarId) := do let mut names : List Syntax := withArg[1].getArgs |>.toList let mut subgoals := #[] @@ -50,10 +51,15 @@ def ElimApp.evalNames (elimInfo : ElimInfo) (alts : Array ElimApp.Alt) (withArg names := names' let (fvars, g) ← g.introN numFields <| altVarNames.map (getNameOfIdent' ·[0]) let some (g, subst) ← Cases.unifyEqs? numEqs g {} | pure () - let (_, g) ← g.introNP numGeneralized + let (introduced, g) ← g.introNP generalized.size + let subst := (generalized.zip introduced).foldl (init := subst) fun subst (a, b) => + subst.insert a (.fvar b) let g ← liftM $ toClear.foldlM (·.tryClear) g - for fvar in fvars, stx in altVarNames do - g.withContext <| (subst.apply <| .fvar fvar).addLocalVarInfoForBinderIdent ⟨stx⟩ + g.withContext do + for (stx, fvar) in toTag do + Term.addLocalVarInfo stx (subst.get fvar) + for fvar in fvars, stx in altVarNames do + (subst.get fvar).addLocalVarInfoForBinderIdent ⟨stx⟩ subgoals := subgoals.push g pure subgoals @@ -62,7 +68,7 @@ elab (name := induction') "induction' " tgts:(Parser.Tactic.casesTarget,+) usingArg:((" using " ident)?) withArg:((" with" (ppSpace colGt binderIdent)+)?) genArg:((" generalizing" (ppSpace colGt ident)+)?) : tactic => do - let targets ← elabCasesTargets tgts.1.getSepArgs + let (targets, toTag) ← elabCasesTargets tgts.1.getSepArgs let g :: gs ← getUnsolvedGoals | throwNoGoalsToBeSolved g.withContext do let elimInfo ← getElimNameInfo usingArg targets (induction := true) @@ -88,12 +94,12 @@ elab (name := induction') "induction' " tgts:(Parser.Tactic.casesTarget,+) ElimApp.setMotiveArg g elimArgs[elimInfo.motivePos]!.mvarId! targetFVarIds g.assign result.elimApp let subgoals ← ElimApp.evalNames elimInfo result.alts withArg - (numGeneralized := fvarIds.size) (toClear := targetFVarIds) + (generalized := fvarIds) (toClear := targetFVarIds) (toTag := toTag) setGoals <| (subgoals ++ result.others).toList ++ gs elab (name := cases') "cases' " tgts:(Parser.Tactic.casesTarget,+) usingArg:((" using " ident)?) withArg:((" with" (ppSpace colGt binderIdent)+)?) : tactic => do - let targets ← elabCasesTargets tgts.1.getSepArgs + let (targets, toTag) ← elabCasesTargets tgts.1.getSepArgs let g :: gs ← getUnsolvedGoals | throwNoGoalsToBeSolved g.withContext do let elimInfo ← getElimNameInfo usingArg targets (induction := false) @@ -108,5 +114,5 @@ elab (name := cases') "cases' " tgts:(Parser.Tactic.casesTarget,+) usingArg:((" ElimApp.setMotiveArg g motive.mvarId! targetsNew g.assign result.elimApp let subgoals ← ElimApp.evalNames elimInfo result.alts withArg - (numEqs := targets.size) (toClear := targetsNew) + (numEqs := targets.size) (toClear := targetsNew) (toTag := toTag) setGoals <| subgoals.toList ++ gs From 038fe40c101de4ef704c77f8f75ee38f12f89ea7 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 23:13:09 +0000 Subject: [PATCH 142/353] chore(Topology/../Nonarchimedean): minor golf (#9209) --- Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean | 6 +----- Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean | 7 ++----- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean index 51489dbd4cf9a..216b486b39f63 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean @@ -59,11 +59,7 @@ theorem of_comm {A ι : Type*} [CommRing A] (B : ι → AddSubgroup A) { inter mul leftMul - rightMul := by - intro x i - cases' leftMul x i with j hj - use j - simpa [mul_comm] using hj } + rightMul := fun x i ↦ (leftMul x i).imp fun j hj ↦ by simpa only [mul_comm] using hj } #align ring_subgroups_basis.of_comm RingSubgroupsBasis.of_comm /-- Every subgroups basis on a ring leads to a ring filter basis. -/ diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean index e2403c1b06ea8..0ec8fc0d61b1c 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean @@ -142,11 +142,8 @@ theorem left_mul_subset (U : OpenAddSubgroup R) (r : R) : /-- An open subgroup of a nonarchimedean ring contains the square of another one. -/ theorem mul_subset (U : OpenAddSubgroup R) : ∃ V : OpenAddSubgroup R, (V : Set R) * V ⊆ U := by - let ⟨V, H⟩ := - prod_self_subset - (IsOpen.mem_nhds (IsOpen.preimage continuous_mul U.isOpen) - (by simpa only [Set.mem_preimage, SetLike.mem_coe, Prod.snd_zero, - mul_zero] using U.zero_mem)) + let ⟨V, H⟩ := prod_self_subset <| (U.isOpen.preimage continuous_mul).mem_nhds <| by + simpa only [Set.mem_preimage, Prod.snd_zero, mul_zero] using U.zero_mem use V rintro v ⟨a, b, ha, hb, hv⟩ have hy := H (Set.mk_mem_prod ha hb) From 983cf2223ba675764dd6602c425ff6d20a683993 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 23:36:00 +0000 Subject: [PATCH 143/353] chore(*): use `rintro` to golf some proofs (#9204) --- Mathlib/Analysis/Convex/Star.lean | 9 ++++----- Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean | 7 ++----- Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean | 10 ++++------ Mathlib/Probability/Kernel/Disintegration.lean | 4 +--- Mathlib/Topology/Algebra/Group/Basic.lean | 5 ++--- 5 files changed, 13 insertions(+), 22 deletions(-) diff --git a/Mathlib/Analysis/Convex/Star.lean b/Mathlib/Analysis/Convex/Star.lean index 3b52d25c277a6..d36393427237c 100644 --- a/Mathlib/Analysis/Convex/Star.lean +++ b/Mathlib/Analysis/Convex/Star.lean @@ -201,10 +201,9 @@ theorem starConvex_singleton (x : E) : StarConvex 𝕜 x {x} := by #align star_convex_singleton starConvex_singleton theorem StarConvex.linear_image (hs : StarConvex 𝕜 x s) (f : E →ₗ[𝕜] F) : - StarConvex 𝕜 (f x) (s.image f) := by - intro y hy a b ha hb hab - obtain ⟨y', hy', rfl⟩ := hy - exact ⟨a • x + b • y', hs hy' ha hb hab, by rw [f.map_add, f.map_smul, f.map_smul]⟩ + StarConvex 𝕜 (f x) (f '' s) := by + rintro _ ⟨y, hy, rfl⟩ a b ha hb hab + exact ⟨a • x + b • y, hs hy ha hb hab, by rw [f.map_add, f.map_smul, f.map_smul]⟩ #align star_convex.linear_image StarConvex.linear_image theorem StarConvex.is_linear_image (hs : StarConvex 𝕜 x s) {f : E → F} (hf : IsLinearMap 𝕜 f) : @@ -213,7 +212,7 @@ theorem StarConvex.is_linear_image (hs : StarConvex 𝕜 x s) {f : E → F} (hf #align star_convex.is_linear_image StarConvex.is_linear_image theorem StarConvex.linear_preimage {s : Set F} (f : E →ₗ[𝕜] F) (hs : StarConvex 𝕜 (f x) s) : - StarConvex 𝕜 x (s.preimage f) := by + StarConvex 𝕜 x (f ⁻¹' s) := by intro y hy a b ha hb hab rw [mem_preimage, f.map_add, f.map_smul, f.map_smul] exact hs hy ha hb hab diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean index 46ac77e1d746e..4c1fe9ed28b1f 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean @@ -214,16 +214,13 @@ def directionOfNonempty {s : AffineSubspace k P} (h : (s : Set P).Nonempty) : Su cases' h with p hp exact vsub_self p ▸ vsub_mem_vsub hp hp add_mem' := by - intro a b ha hb - rcases ha with ⟨p1, p2, hp1, hp2, rfl⟩ - rcases hb with ⟨p3, p4, hp3, hp4, rfl⟩ + rintro _ _ ⟨p1, p2, hp1, hp2, rfl⟩ ⟨p3, p4, hp3, hp4, rfl⟩ rw [← vadd_vsub_assoc] refine' vsub_mem_vsub _ hp4 convert s.smul_vsub_vadd_mem 1 hp1 hp2 hp3 rw [one_smul] smul_mem' := by - intro c v hv - rcases hv with ⟨p1, p2, hp1, hp2, rfl⟩ + rintro c _ ⟨p1, p2, hp1, hp2, rfl⟩ rw [← vadd_vsub (c • (p1 -ᵥ p2)) p2] refine' vsub_mem_vsub _ hp2 exact s.smul_vsub_vadd_mem c hp1 hp2 hp2 diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean index 2d4f7909ad377..4226ccaebf17c 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean @@ -59,13 +59,11 @@ theorem ι_mul_ι_mem_evenOdd_zero (m₁ m₂ : M) : ι Q m₁ * ι Q m₂ ∈ e theorem evenOdd_mul_le (i j : ZMod 2) : evenOdd Q i * evenOdd Q j ≤ evenOdd Q (i + j) := by simp_rw [evenOdd, Submodule.iSup_eq_span, Submodule.span_mul_span] apply Submodule.span_mono - intro z hz - obtain ⟨x, y, hx, hy, rfl⟩ := hz - obtain ⟨xi, hx'⟩ := Set.mem_iUnion.mp hx - obtain ⟨yi, hy'⟩ := Set.mem_iUnion.mp hy - refine' Set.mem_iUnion.mpr ⟨⟨xi + yi, by simp only [Nat.cast_add, xi.prop, yi.prop]⟩, _⟩ + simp_rw [Set.iUnion_mul, Set.mul_iUnion, Set.iUnion_subset_iff, Set.mul_subset_iff] + rintro ⟨xi, rfl⟩ ⟨yi, rfl⟩ x hx y hy + refine Set.mem_iUnion.mpr ⟨⟨xi + yi, Nat.cast_add _ _⟩, ?_⟩ simp only [Subtype.coe_mk, Nat.cast_add, pow_add] - exact Submodule.mul_mem_mul hx' hy' + exact Submodule.mul_mem_mul hx hy #align clifford_algebra.even_odd_mul_le CliffordAlgebra.evenOdd_mul_le instance evenOdd.gradedMonoid : SetLike.GradedMonoid (evenOdd Q) where diff --git a/Mathlib/Probability/Kernel/Disintegration.lean b/Mathlib/Probability/Kernel/Disintegration.lean index 9d1b2ad0afe80..a328de26de972 100644 --- a/Mathlib/Probability/Kernel/Disintegration.lean +++ b/Mathlib/Probability/Kernel/Disintegration.lean @@ -139,9 +139,7 @@ theorem lintegral_condKernelReal_mem {s : Set (α × ℝ)} (hs : MeasurableSet s apply MeasurableSpace.induction_on_inter generateFrom_prod.symm isPiSystem_prod _ _ _ _ hs · simp only [mem_empty_iff_false, setOf_false, measure_empty, lintegral_const, zero_mul] - · intro t ht - rw [mem_image2] at ht - obtain ⟨t₁, t₂, ht₁, ht₂, rfl⟩ := ht + · rintro _ ⟨t₁, t₂, ht₁, ht₂, rfl⟩ have h_prod_eq_snd : ∀ a ∈ t₁, {x : ℝ | (a, x) ∈ t₁ ×ˢ t₂} = t₂ := by intro a ha simp only [ha, prod_mk_mem_set_prod_eq, true_and_iff, setOf_mem_eq] diff --git a/Mathlib/Topology/Algebra/Group/Basic.lean b/Mathlib/Topology/Algebra/Group/Basic.lean index cf7bfae09dc79..d088dae427535 100644 --- a/Mathlib/Topology/Algebra/Group/Basic.lean +++ b/Mathlib/Topology/Algebra/Group/Basic.lean @@ -1257,10 +1257,9 @@ variable [TopologicalSpace α] [TopologicalSpace β] [Group α] [MulAction α β theorem IsClosed.smul_left_of_isCompact (ht : IsClosed t) (hs : IsCompact s) : IsClosed (s • t) := by have : ∀ x ∈ s • t, ∃ g ∈ s, g⁻¹ • x ∈ t := by - intro x ⟨g, y, hgs, hyt, hgyx⟩ + rintro x ⟨g, y, hgs, hyt, rfl⟩ refine ⟨g, hgs, ?_⟩ - convert hyt - rwa [inv_smul_eq_iff, eq_comm] + rwa [inv_smul_smul] choose! f hf using this refine isClosed_of_closure_subset (fun x hx ↦ ?_) rcases mem_closure_iff_ultrafilter.mp hx with ⟨u, hust, hux⟩ From e9294e6f5daa84082cd381e7f6e9035b9aca7ef3 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Dec 2023 23:36:01 +0000 Subject: [PATCH 144/353] =?UTF-8?q?chore(Subgroup/Pointwise):=20golf,=20us?= =?UTF-8?q?e=20`=E2=88=A9`=20(#9208)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/GroupTheory/Subgroup/Pointwise.lean | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Mathlib/GroupTheory/Subgroup/Pointwise.lean b/Mathlib/GroupTheory/Subgroup/Pointwise.lean index 9a6769c1e66a3..fd92511d3bd72 100644 --- a/Mathlib/GroupTheory/Subgroup/Pointwise.lean +++ b/Mathlib/GroupTheory/Subgroup/Pointwise.lean @@ -166,10 +166,8 @@ theorem sup_eq_closure_mul (H K : Subgroup G) : H ⊔ K = closure ((H : Set G) * @[to_additive] theorem set_mul_normal_comm (s : Set G) (N : Subgroup G) [hN : N.Normal] : s * (N : Set G) = (N : Set G) * s := by - ext x - refine (exists_congr fun y => ?_).trans exists_swap - simp only [exists_and_left, @and_left_comm _ (y ∈ s), ← eq_inv_mul_iff_mul_eq (b := y), - ← eq_mul_inv_iff_mul_eq (c := y), exists_eq_right, SetLike.mem_coe, hN.mem_comm_iff] + rw [← iUnion_mul_left_image, ← iUnion_mul_right_image] + simp only [image_mul_left, image_mul_right, Set.preimage, SetLike.mem_coe, hN.mem_comm_iff] /-- The carrier of `H ⊔ N` is just `↑H * ↑N` (pointwise set product) when `N` is normal. -/ @[to_additive "The carrier of `H ⊔ N` is just `↑H + ↑N` (pointwise set addition) @@ -199,12 +197,11 @@ theorem normal_mul (N H : Subgroup G) [N.Normal] : (↑(N ⊔ H) : Set G) = N * #align subgroup.normal_mul Subgroup.normal_mul #align add_subgroup.normal_add AddSubgroup.normal_add --- porting note: todo: use `∩` in the RHS @[to_additive] theorem mul_inf_assoc (A B C : Subgroup G) (h : A ≤ C) : - (A : Set G) * ↑(B ⊓ C) = (A : Set G) * (B : Set G) ⊓ C := by + (A : Set G) * ↑(B ⊓ C) = (A : Set G) * (B : Set G) ∩ C := by ext - simp only [coe_inf, Set.inf_eq_inter, Set.mem_mul, Set.mem_inter_iff] + simp only [coe_inf, Set.mem_mul, Set.mem_inter_iff] constructor · rintro ⟨y, z, hy, ⟨hzB, hzC⟩, rfl⟩ refine' ⟨_, mul_mem (h hy) hzC⟩ @@ -216,12 +213,11 @@ theorem mul_inf_assoc (A B C : Subgroup G) (h : A ≤ C) : #align subgroup.mul_inf_assoc Subgroup.mul_inf_assoc #align add_subgroup.add_inf_assoc AddSubgroup.add_inf_assoc --- porting note: todo: use `∩` in the RHS @[to_additive] theorem inf_mul_assoc (A B C : Subgroup G) (h : C ≤ A) : - ((A ⊓ B : Subgroup G) : Set G) * C = (A : Set G) ⊓ ↑B * ↑C := by + ((A ⊓ B : Subgroup G) : Set G) * C = (A : Set G) ∩ (↑B * ↑C) := by ext - simp only [coe_inf, Set.inf_eq_inter, Set.mem_mul, Set.mem_inter_iff] + simp only [coe_inf, Set.mem_mul, Set.mem_inter_iff] constructor · rintro ⟨y, z, ⟨hyA, hyB⟩, hz, rfl⟩ refine' ⟨A.mul_mem hyA (h hz), _⟩ From be62dd13c801d3789f991c36b03a27adf7f22bd8 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Fri, 22 Dec 2023 18:38:17 -0500 Subject: [PATCH 145/353] chore: fix unused variables --- Mathlib/Data/FP/Basic.lean | 4 ++-- Mathlib/Data/List/MinMax.lean | 2 +- Mathlib/Data/PFunctor/Univariate/M.lean | 4 ++-- Mathlib/Data/QPF/Univariate/Basic.lean | 2 +- Mathlib/Logic/Encodable/Basic.lean | 2 +- Mathlib/MeasureTheory/Integral/SetToL1.lean | 2 +- Mathlib/Order/Estimator.lean | 2 +- Mathlib/Order/InitialSeg.lean | 2 +- Mathlib/RingTheory/Ideal/Norm.lean | 2 +- Mathlib/SetTheory/Ordinal/Notation.lean | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Mathlib/Data/FP/Basic.lean b/Mathlib/Data/FP/Basic.lean index d1d2bb060cc8a..8bec271be9db9 100644 --- a/Mathlib/Data/FP/Basic.lean +++ b/Mathlib/Data/FP/Basic.lean @@ -147,10 +147,10 @@ def divNatLtTwoPow (n d : ℕ) : ℤ → Bool @[nolint docBlame] unsafe def ofPosRatDn (n : ℕ+) (d : ℕ+) : Float × Bool := by let e₁ : ℤ := n.1.size - d.1.size - prec - cases' h₁ : Int.shift2 d.1 n.1 (e₁ + prec) with d₁ n₁ + cases' Int.shift2 d.1 n.1 (e₁ + prec) with d₁ n₁ let e₂ := if n₁ < d₁ then e₁ - 1 else e₁ let e₃ := max e₂ emin - cases' h₂ : Int.shift2 d.1 n.1 (e₃ + prec) with d₂ n₂ + cases' Int.shift2 d.1 n.1 (e₃ + prec) with d₂ n₂ let r := mkRat n₂ d₂ let m := r.floor refine' (Float.finite Bool.false e₃ (Int.toNat m) _, r.den = 1) diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index 06313430b3b7d..068ff7022be5c 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -345,7 +345,7 @@ variable [LinearOrder α] {l : List α} {a m : α} theorem maximum_concat (a : α) (l : List α) : maximum (l ++ [a]) = max (maximum l) a := by simp only [maximum, argmax_concat, id] - cases h : argmax id l + cases argmax id l · exact (max_eq_right bot_le).symm · simp [WithBot.some_eq_coe, max_def_lt, WithBot.coe_lt_coe] #align list.maximum_concat List.maximum_concat diff --git a/Mathlib/Data/PFunctor/Univariate/M.lean b/Mathlib/Data/PFunctor/Univariate/M.lean index 31072132ad0bc..b61c4dfa2c78f 100644 --- a/Mathlib/Data/PFunctor/Univariate/M.lean +++ b/Mathlib/Data/PFunctor/Univariate/M.lean @@ -129,7 +129,7 @@ def sCorec : X → ∀ n, CofixA F n theorem P_corec (i : X) (n : ℕ) : Agree (sCorec f i n) (sCorec f i (succ n)) := by induction' n with n n_ih generalizing i constructor - cases' h : f i with y g + cases' f i with y g constructor introv apply n_ih @@ -578,7 +578,7 @@ theorem corec_def {X} (f : X → F X) (x₀ : X) : M.corec f x₀ = M.mk (F.map cases' n with n · dsimp only [sCorec, Approx.sMk] · dsimp only [sCorec, Approx.sMk] - cases h : f x₀ + cases f x₀ dsimp only [PFunctor.map] congr set_option linter.uppercaseLean3 false in diff --git a/Mathlib/Data/QPF/Univariate/Basic.lean b/Mathlib/Data/QPF/Univariate/Basic.lean index ee47afa0ec54e..5901731de0182 100644 --- a/Mathlib/Data/QPF/Univariate/Basic.lean +++ b/Mathlib/Data/QPF/Univariate/Basic.lean @@ -541,7 +541,7 @@ def comp : QPF (Functor.Comp F₂ F₁) where conv => rhs rw [← abs_repr x] - cases' h : repr x with a f + cases' repr x with a f dsimp congr with x cases' h' : repr (f x) with b g diff --git a/Mathlib/Logic/Encodable/Basic.lean b/Mathlib/Logic/Encodable/Basic.lean index 5fe3ed0d0456e..62579a65debf8 100644 --- a/Mathlib/Logic/Encodable/Basic.lean +++ b/Mathlib/Logic/Encodable/Basic.lean @@ -644,7 +644,7 @@ theorem sequence_mono_nat {r : β → β → Prop} {f : α → β} (hf : Directe r (f (hf.sequence f n)) (f (hf.sequence f (n + 1))) := by dsimp [Directed.sequence] generalize hf.sequence f n = p - cases' h : (decode n: Option α) with a + cases' (decode n : Option α) with a · exact (Classical.choose_spec (hf p p)).1 · exact (Classical.choose_spec (hf p a)).1 #align directed.sequence_mono_nat Directed.sequence_mono_nat diff --git a/Mathlib/MeasureTheory/Integral/SetToL1.lean b/Mathlib/MeasureTheory/Integral/SetToL1.lean index 573afc7088656..742ffde8dd441 100644 --- a/Mathlib/MeasureTheory/Integral/SetToL1.lean +++ b/Mathlib/MeasureTheory/Integral/SetToL1.lean @@ -637,7 +637,7 @@ theorem setToSimpleFunc_const' [Nonempty α] (T : Set α → F →L[ℝ] F') (x theorem setToSimpleFunc_const (T : Set α → F →L[ℝ] F') (hT_empty : T ∅ = 0) (x : F) {m : MeasurableSpace α} : SimpleFunc.setToSimpleFunc T (SimpleFunc.const α x) = T univ x := by - cases hα : isEmpty_or_nonempty α + cases isEmpty_or_nonempty α · have h_univ_empty : (univ : Set α) = ∅ := Subsingleton.elim _ _ rw [h_univ_empty, hT_empty] simp only [setToSimpleFunc, ContinuousLinearMap.zero_apply, sum_empty, diff --git a/Mathlib/Order/Estimator.lean b/Mathlib/Order/Estimator.lean index 763f956bfc634..364c8baeb69cb 100644 --- a/Mathlib/Order/Estimator.lean +++ b/Mathlib/Order/Estimator.lean @@ -179,7 +179,7 @@ instance (a b : Thunk ℕ) {εa εb : Type*} [Estimator a εa] [Estimator b εb] have s₁ := Estimator.improve_spec (a := a) e.1 have s₂ := Estimator.improve_spec (a := b) e.2 revert s₁ s₂ - cases h₁ : improve a e.fst <;> cases h₂ : improve b e.snd <;> intro s₁ s₂ <;> simp_all only + cases improve a e.fst <;> cases improve b e.snd <;> intro s₁ s₂ <;> simp_all only · apply Nat.add_lt_add_left s₂ · apply Nat.add_lt_add_right s₁ · apply Nat.add_lt_add_right s₁ diff --git a/Mathlib/Order/InitialSeg.lean b/Mathlib/Order/InitialSeg.lean index 67a77c84ab0bf..1062281ebc660 100644 --- a/Mathlib/Order/InitialSeg.lean +++ b/Mathlib/Order/InitialSeg.lean @@ -513,7 +513,7 @@ noncomputable def InitialSeg.leLT [IsWellOrder β s] [IsTrans γ t] (f : r ≼i @[simp] theorem InitialSeg.leLT_apply [IsWellOrder β s] [IsTrans γ t] (f : r ≼i s) (g : s ≺i t) (a : α) : (f.leLT g) a = g (f a) := by - delta InitialSeg.leLT; cases' h : f.ltOrEq with f' f' + delta InitialSeg.leLT; cases' f.ltOrEq with f' f' · simp only [PrincipalSeg.trans_apply, f.ltOrEq_apply_left] · simp only [PrincipalSeg.equivLT_apply, f.ltOrEq_apply_right] #align initial_seg.le_lt_apply InitialSeg.leLT_apply diff --git a/Mathlib/RingTheory/Ideal/Norm.lean b/Mathlib/RingTheory/Ideal/Norm.lean index 4100795d4f52f..f498dbb54e50f 100644 --- a/Mathlib/RingTheory/Ideal/Norm.lean +++ b/Mathlib/RingTheory/Ideal/Norm.lean @@ -553,7 +553,7 @@ theorem spanNorm_localization (I : Ideal S) [Module.Finite R S] [Module.Free R S [Algebra Rₘ Sₘ] [Algebra R Sₘ] [IsScalarTower R Rₘ Sₘ] [IsScalarTower R S Sₘ] [IsLocalization M Rₘ] [IsLocalization (Algebra.algebraMapSubmonoid S M) Sₘ] : spanNorm Rₘ (I.map (algebraMap S Sₘ)) = (spanNorm R I).map (algebraMap R Rₘ) := by - cases h : subsingleton_or_nontrivial R + cases subsingleton_or_nontrivial R · haveI := IsLocalization.unique R Rₘ M simp [eq_iff_true_of_subsingleton] let b := Module.Free.chooseBasis R S diff --git a/Mathlib/SetTheory/Ordinal/Notation.lean b/Mathlib/SetTheory/Ordinal/Notation.lean index 113f6b9987dd5..9a9ca65077236 100644 --- a/Mathlib/SetTheory/Ordinal/Notation.lean +++ b/Mathlib/SetTheory/Ordinal/Notation.lean @@ -515,7 +515,7 @@ theorem sub_nfBelow : ∀ {o₁ o₂ b}, NFBelow o₁ b → NF o₂ → NFBelow · apply NFBelow.zero · simp only [h, Ordering.compares_eq] at this subst e₂ - cases mn : (n₁ : ℕ) - n₂ <;> simp [sub] + cases (n₁ : ℕ) - n₂ <;> simp [sub] · by_cases en : n₁ = n₂ <;> simp [en] · exact h'.mono (le_of_lt h₁.lt) · exact NFBelow.zero From 161290d8e2ea232b3326ffd10fbe76e2d5b795f9 Mon Sep 17 00:00:00 2001 From: Chris Birkbeck Date: Sat, 23 Dec 2023 00:28:55 +0000 Subject: [PATCH 146/353] feat(ModularForm): Graded Ring instance on spaces of modular forms (#9164) This adds the graded ring instance to spaces of modular forms. Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Co-authored-by: Eric Wieser Co-authored-by: Chris Birkbeck --- Mathlib/NumberTheory/ModularForms/Basic.lean | 96 +++++++++++++++++-- .../ModularForms/SlashActions.lean | 10 +- .../ModularForms/SlashInvariantForms.lean | 23 ++++- 3 files changed, 115 insertions(+), 14 deletions(-) diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index e0298e68531dd..ff53fe5380695 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -3,6 +3,8 @@ Copyright (c) 2022 Chris Birkbeck. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ +import Mathlib.Algebra.DirectSum.Algebra +import Mathlib.Algebra.GradedMonoid import Mathlib.Analysis.Complex.UpperHalfPlane.FunctionsBoundedAtInfty import Mathlib.Analysis.Complex.UpperHalfPlane.Manifold import Mathlib.NumberTheory.ModularForms.SlashInvariantForms @@ -12,7 +14,8 @@ import Mathlib.NumberTheory.ModularForms.SlashInvariantForms /-! # Modular forms -This file defines modular forms and proves some basic properties about them. +This file defines modular forms and proves some basic properties about them. Including constructing +the graded ring of modular forms. We begin by defining modular forms and cusp forms as extension of `SlashInvariantForm`s then we define the space of modular forms, cusp forms and prove that the product of two modular forms is a @@ -265,18 +268,43 @@ theorem mul_coe {k_1 k_2 : ℤ} {Γ : Subgroup SL(2, ℤ)} (f : ModularForm Γ k rfl #align modular_form.mul_coe ModularForm.mul_coe -instance : One (ModularForm Γ 0) := - ⟨ { toSlashInvariantForm := 1 - holo' := fun x => mdifferentiableAt_const 𝓘(ℂ, ℂ) 𝓘(ℂ, ℂ) - bdd_at_infty' := fun A => by - simpa only [SlashInvariantForm.one_coe_eq_one, - ModularForm.is_invariant_one] using atImInfty.const_boundedAtFilter (1 : ℂ) }⟩ +/-- The constant function with value `x : ℂ` as a modular form of weight 0 and any level. -/ +@[simps! (config := .asFn) toFun toSlashInvariantForm] +def const (x : ℂ) : ModularForm Γ 0 where + toSlashInvariantForm := .const x + holo' x := mdifferentiableAt_const 𝓘(ℂ, ℂ) 𝓘(ℂ, ℂ) + bdd_at_infty' A := by + simpa only [SlashInvariantForm.const_toFun, + ModularForm.is_invariant_const] using atImInfty.const_boundedAtFilter x + +instance : One (ModularForm Γ 0) where + one := { const 1 with toSlashInvariantForm := 1 } @[simp] -theorem one_coe_eq_one : ((1 : ModularForm Γ 0) : ℍ → ℂ) = 1 := +theorem one_coe_eq_one : ⇑(1 : ModularForm Γ 0) = 1 := rfl #align modular_form.one_coe_eq_one ModularForm.one_coe_eq_one +instance (Γ : Subgroup SL(2, ℤ)) : NatCast (ModularForm Γ 0) where + natCast n := const n + +@[simp, norm_cast] +lemma coe_natCast (Γ : Subgroup SL(2, ℤ)) (n : ℕ) : + ⇑(n : ModularForm Γ 0) = n := rfl + +lemma toSlashInvariantForm_natCast (Γ : Subgroup SL(2, ℤ)) (n : ℕ) : + (n : ModularForm Γ 0).toSlashInvariantForm = n := rfl + +instance (Γ : Subgroup SL(2, ℤ)) : IntCast (ModularForm Γ 0) where + intCast z := const z + +@[simp, norm_cast] +lemma coe_intCast (Γ : Subgroup SL(2, ℤ)) (z : ℤ) : + ⇑(z : ModularForm Γ 0) = z := rfl + +lemma toSlashInvariantForm_intCast (Γ : Subgroup SL(2, ℤ)) (z : ℤ) : + (z : ModularForm Γ 0).toSlashInvariantForm = z := rfl + end ModularForm namespace CuspForm @@ -397,3 +425,55 @@ instance (priority := 99) [CuspFormClass F Γ k] : ModularFormClass F Γ k where bdd_at_infty _ _ := (CuspFormClass.zero_at_infty _ _).boundedAtFilter end CuspForm + +namespace ModularForm + +section GradedRing + +/-- Cast for modular forms, which is useful for avoiding `Heq`s. -/ +def mcast {a b : ℤ} {Γ : Subgroup SL(2, ℤ)} (h : a = b) (f : ModularForm Γ a) : ModularForm Γ b + where + toFun := (f : ℍ → ℂ) + slash_action_eq' A := h ▸ f.slash_action_eq' A + holo' := f.holo' + bdd_at_infty' A := h ▸ f.bdd_at_infty' A + +@[ext] +theorem gradedMonoid_eq_of_cast {Γ : Subgroup SL(2, ℤ)} {a b : GradedMonoid (ModularForm Γ)} + (h : a.fst = b.fst) (h2 : mcast h a.snd = b.snd) : a = b := by + obtain ⟨i, a⟩ := a + obtain ⟨j, b⟩ := b + cases h + exact congr_arg _ h2 + +instance (Γ : Subgroup SL(2, ℤ)) : GradedMonoid.GOne (ModularForm Γ) where + one := 1 + +instance (Γ : Subgroup SL(2, ℤ)) : GradedMonoid.GMul (ModularForm Γ) where + mul f g := f.mul g + +instance instGCommRing (Γ : Subgroup SL(2, ℤ)) : DirectSum.GCommRing (ModularForm Γ) where + one_mul a := gradedMonoid_eq_of_cast (zero_add _) (ext fun _ => one_mul _) + mul_one a := gradedMonoid_eq_of_cast (add_zero _) (ext fun _ => mul_one _) + mul_assoc a b c := gradedMonoid_eq_of_cast (add_assoc _ _ _) (ext fun _ => mul_assoc _ _ _) + mul_zero {i j} f := ext fun _ => mul_zero _ + zero_mul {i j} f := ext fun _ => zero_mul _ + mul_add {i j} f g h := ext fun _ => mul_add _ _ _ + add_mul {i j} f g h := ext fun _ => add_mul _ _ _ + mul_comm a b := gradedMonoid_eq_of_cast (add_comm _ _) (ext fun _ => mul_comm _ _) + natCast := Nat.cast + natCast_zero := ext fun _ => Nat.cast_zero + natCast_succ n := ext fun _ => Nat.cast_succ _ + intCast := Int.cast + intCast_ofNat n := ext fun _ => AddGroupWithOne.intCast_ofNat _ + intCast_negSucc_ofNat n := ext fun _ => AddGroupWithOne.intCast_negSucc _ + +instance instGAlgebra (Γ : Subgroup SL(2, ℤ)) : DirectSum.GAlgebra ℂ (ModularForm Γ) where + toFun := { toFun := const, map_zero' := rfl, map_add' := fun _ _ => rfl } + map_one := rfl + map_mul _x _y := rfl + commutes _c _x := gradedMonoid_eq_of_cast (add_comm _ _) (ext fun _ => mul_comm _ _) + smul_def _x _x := gradedMonoid_eq_of_cast (zero_add _).symm (ext fun _ => rfl) + +open scoped DirectSum in +example (Γ : Subgroup SL(2, ℤ)) : Algebra ℂ (⨁ i, ModularForm Γ i) := inferInstance diff --git a/Mathlib/NumberTheory/ModularForms/SlashActions.lean b/Mathlib/NumberTheory/ModularForms/SlashActions.lean index 50c6c2484f6da..5e6e77c79789b 100644 --- a/Mathlib/NumberTheory/ModularForms/SlashActions.lean +++ b/Mathlib/NumberTheory/ModularForms/SlashActions.lean @@ -176,13 +176,17 @@ theorem SL_slash (γ : SL(2, ℤ)) : f ∣[k] γ = f ∣[k] (γ : GL(2, ℝ)⁺) set_option linter.uppercaseLean3 false in #align modular_form.SL_slash ModularForm.SL_slash -/-- The constant function 1 is invariant under any element of `SL(2, ℤ)`. -/ --- @[simp] -- Porting note: simpNF says LHS simplifies to something more complex -theorem is_invariant_one (A : SL(2, ℤ)) : (1 : ℍ → ℂ) ∣[(0 : ℤ)] A = (1 : ℍ → ℂ) := by +theorem is_invariant_const (A : SL(2, ℤ)) (x : ℂ) : + Function.const ℍ x ∣[(0 : ℤ)] A = Function.const ℍ x := by have : ((↑ₘ(A : GL(2, ℝ)⁺)).det : ℝ) = 1 := det_coe' funext rw [SL_slash, slash_def, slash, zero_sub, this] simp + +/-- The constant function 1 is invariant under any element of `SL(2, ℤ)`. -/ +-- @[simp] -- Porting note: simpNF says LHS simplifies to something more complex +theorem is_invariant_one (A : SL(2, ℤ)) : (1 : ℍ → ℂ) ∣[(0 : ℤ)] A = (1 : ℍ → ℂ) := + is_invariant_const _ _ #align modular_form.is_invariant_one ModularForm.is_invariant_one /-- A function `f : ℍ → ℂ` is slash-invariant, of weight `k ∈ ℤ` and level `Γ`, diff --git a/Mathlib/NumberTheory/ModularForms/SlashInvariantForms.lean b/Mathlib/NumberTheory/ModularForms/SlashInvariantForms.lean index 8b27dc3a16d42..f81e304b46da1 100644 --- a/Mathlib/NumberTheory/ModularForms/SlashInvariantForms.lean +++ b/Mathlib/NumberTheory/ModularForms/SlashInvariantForms.lean @@ -208,9 +208,14 @@ theorem coeHom_injective : Function.Injective (@coeHom Γ k) := instance : Module ℂ (SlashInvariantForm Γ k) := coeHom_injective.module ℂ coeHom fun _ _ => rfl -instance : One (SlashInvariantForm Γ 0) := - ⟨{toFun := 1 - slash_action_eq' := fun A => ModularForm.is_invariant_one A }⟩ +/-- The `SlashInvariantForm` corresponding to `Function.const _ x`. -/ +@[simps (config := .asFn)] +def const (x : ℂ) : SlashInvariantForm Γ 0 where + toFun := Function.const _ x + slash_action_eq' A := ModularForm.is_invariant_const A x + +instance : One (SlashInvariantForm Γ 0) where + one := { const 1 with toFun := 1 } @[simp] theorem one_coe_eq_one : ((1 : SlashInvariantForm Γ 0) : ℍ → ℂ) = 1 := @@ -233,4 +238,16 @@ theorem coe_mul {k₁ k₂ : ℤ} {Γ : Subgroup SL(2, ℤ)} (f : SlashInvariant (g : SlashInvariantForm Γ k₂) : ⇑(f.mul g) = ⇑f * ⇑g := rfl +instance (Γ : Subgroup SL(2, ℤ)) : NatCast (SlashInvariantForm Γ 0) where + natCast n := const n + +@[simp, norm_cast] +theorem coe_natCast (n : ℕ) : ⇑(n : SlashInvariantForm Γ 0) = n := rfl + +instance (Γ : Subgroup SL(2, ℤ)) : IntCast (SlashInvariantForm Γ 0) where + intCast z := const z + +@[simp, norm_cast] +theorem coe_intCast (z : ℤ) : ⇑(z : SlashInvariantForm Γ 0) = z := rfl + end SlashInvariantForm From c56af57a40806059eac6542227502b4bd959fc38 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 23 Dec 2023 00:28:56 +0000 Subject: [PATCH 147/353] feat(Algebra/GradedMonoid): missing lemmas about `fst` and `snd` (#9227) --- Mathlib/Algebra/GradedMonoid.lean | 48 ++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/Mathlib/Algebra/GradedMonoid.lean b/Mathlib/Algebra/GradedMonoid.lean index aadfc5ba3fe89..383bab6b9b10a 100644 --- a/Mathlib/Algebra/GradedMonoid.lean +++ b/Mathlib/Algebra/GradedMonoid.lean @@ -112,26 +112,33 @@ def mk {A : ι → Type*} : ∀ i, A i → GradedMonoid A := /-! ### Actions -/ section actions +variable {α β} {A : ι → Type*} /-- If `R` acts on each `A i`, then it acts on `GradedMonoid A` via the `.2` projection. -/ -instance {α} {A : ι → Type*} [∀ i, SMul α (A i)] : SMul α (GradedMonoid A) where +instance [∀ i, SMul α (A i)] : SMul α (GradedMonoid A) where smul r g := GradedMonoid.mk g.1 (r • g.2) -theorem smul_mk {α} {A : ι → Type*} [∀ i, SMul α (A i)] {i} (c : α) (a : A i) : +@[simp] theorem fst_smul [∀ i, SMul α (A i)] (a : α) (x : GradedMonoid A) : + (a • x).fst = x.fst := rfl + +@[simp] theorem snd_smul [∀ i, SMul α (A i)] (a : α) (x : GradedMonoid A) : + (a • x).snd = a • x.snd := rfl + +theorem smul_mk [∀ i, SMul α (A i)] {i} (c : α) (a : A i) : c • mk i a = mk i (c • a) := rfl -instance {α β} {A : ι → Type*} [∀ i, SMul α (A i)] [∀ i, SMul β (A i)] +instance [∀ i, SMul α (A i)] [∀ i, SMul β (A i)] [∀ i, SMulCommClass α β (A i)] : SMulCommClass α β (GradedMonoid A) where smul_comm a b g := Sigma.ext rfl <| heq_of_eq <| smul_comm a b g.2 -instance {α β} {A : ι → Type*} [SMul α β] [∀ i, SMul α (A i)] [∀ i, SMul β (A i)] +instance [SMul α β] [∀ i, SMul α (A i)] [∀ i, SMul β (A i)] [∀ i, IsScalarTower α β (A i)] : IsScalarTower α β (GradedMonoid A) where smul_assoc a b g := Sigma.ext rfl <| heq_of_eq <| smul_assoc a b g.2 -instance {α} {A : ι → Type*} [Monoid α] [∀ i, MulAction α (A i)] : +instance [Monoid α] [∀ i, MulAction α (A i)] : MulAction α (GradedMonoid A) where one_smul g := Sigma.ext rfl <| heq_of_eq <| one_smul _ g.2 mul_smul r₁ r₂ g := Sigma.ext rfl <| heq_of_eq <| mul_smul r₁ r₂ g.2 @@ -155,6 +162,10 @@ instance GOne.toOne [Zero ι] [GOne A] : One (GradedMonoid A) := ⟨⟨_, GOne.one⟩⟩ #align graded_monoid.ghas_one.to_has_one GradedMonoid.GOne.toOne +@[simp] theorem fst_one [Zero ι] [GOne A] : (1 : GradedMonoid A).fst = 0 := rfl + +@[simp] theorem snd_one [Zero ι] [GOne A] : (1 : GradedMonoid A).snd = GOne.one := rfl + /-- A graded version of `Mul`. Multiplication combines grades additively, like `AddMonoidAlgebra`. -/ class GMul [Add ι] where @@ -167,6 +178,12 @@ instance GMul.toMul [Add ι] [GMul A] : Mul (GradedMonoid A) := ⟨fun x y : GradedMonoid A => ⟨_, GMul.mul x.snd y.snd⟩⟩ #align graded_monoid.ghas_mul.to_has_mul GradedMonoid.GMul.toMul +@[simp] theorem fst_mul [Add ι] [GMul A] (x y : GradedMonoid A) : + (x * y).fst = x.fst + y.fst := rfl + +@[simp] theorem snd_mul [Add ι] [GMul A] (x y : GradedMonoid A) : + (x * y).snd = GMul.mul x.snd y.snd := rfl + theorem mk_mul_mk [Add ι] [GMul A] {i j} (a : A i) (b : A j) : mk i a * mk j b = mk (i + j) (GMul.mul a b) := rfl @@ -225,8 +242,7 @@ class GMonoid [AddMonoid ι] extends GMul A, GOne A where #align graded_monoid.gmonoid GradedMonoid.GMonoid /-- `GMonoid` implies a `Monoid (GradedMonoid A)`. -/ -instance GMonoid.toMonoid [AddMonoid ι] [GMonoid A] : Monoid (GradedMonoid A) - where +instance GMonoid.toMonoid [AddMonoid ι] [GMonoid A] : Monoid (GradedMonoid A) where one := 1 mul := (· * ·) npow n a := GradedMonoid.mk _ (GMonoid.gnpow n a.snd) @@ -237,15 +253,14 @@ instance GMonoid.toMonoid [AddMonoid ι] [GMonoid A] : Monoid (GradedMonoid A) mul_assoc := GMonoid.mul_assoc #align graded_monoid.gmonoid.to_monoid GradedMonoid.GMonoid.toMonoid +@[simp] theorem fst_pow [AddMonoid ι] [GMonoid A] (x : GradedMonoid A) (n : ℕ) : + (x ^ n).fst = n • x.fst := rfl + +@[simp] theorem snd_pow [AddMonoid ι] [GMonoid A] (x : GradedMonoid A) (n : ℕ) : + (x ^ n).snd = GMonoid.gnpow n x.snd := rfl + theorem mk_pow [AddMonoid ι] [GMonoid A] {i} (a : A i) (n : ℕ) : - mk i a ^ n = mk (n • i) (GMonoid.gnpow _ a) := by - match n with - | 0 => - rw [pow_zero] - exact (GMonoid.gnpow_zero' ⟨_, a⟩).symm - | n+1 => - rw [pow_succ, mk_pow a n, mk_mul_mk] - exact (GMonoid.gnpow_succ' n ⟨_, a⟩).symm + mk i a ^ n = mk (n • i) (GMonoid.gnpow _ a) := rfl #align graded_monoid.mk_pow GradedMonoid.mk_pow /-- A graded version of `CommMonoid`. -/ @@ -356,8 +371,7 @@ variable [AddMonoid ι] [GMonoid A] /-- `GradedMonoid.mk 0` is a `MonoidHom`, using the `GradedMonoid.GradeZero.monoid` structure. -/ -def mkZeroMonoidHom : A 0 →* GradedMonoid A - where +def mkZeroMonoidHom : A 0 →* GradedMonoid A where toFun := mk 0 map_one' := rfl map_mul' := mk_zero_smul From a7fbc9ec101d941ce1e02955a6e130a25d5ab907 Mon Sep 17 00:00:00 2001 From: Michael Stoll Date: Sat, 23 Dec 2023 06:38:50 +0000 Subject: [PATCH 148/353] feat(Analysis/SpecialFunctions/Complex/Arg): add definition for slit plane and API, and use it (#9116) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of future PRs dealing with estimates of the complex logarithm and its Taylor series, this introduces `Complex.slitPlane` for the set of complex numbers not on the closed negative real axis (in `Analysis.SpecialFunctions.Complex.Arg`), adds a bunch of API lemmas, and replaces hypotheses of the form `0 < x.re ∨ x.im ≠ 0` by `x ∈ slitPlane` in several other files. (We do not introduce a new file for that to avoid circular imports with `Analysis.SpecialFunctions.Complex.Arg`.) Co-authored-by: Yury G. Kudryashov --- Mathlib.lean | 1 + Mathlib/Analysis/Complex/Basic.lean | 58 +++++++++++++++++++ Mathlib/Analysis/Complex/Convex.lean | 36 ++++++++++++ Mathlib/Analysis/Convex/Star.lean | 25 +++++++- .../SpecialFunctions/Complex/Arg.lean | 30 ++++++++-- .../SpecialFunctions/Complex/Log.lean | 16 +++-- .../SpecialFunctions/Complex/LogDeriv.lean | 40 ++++++------- .../SpecialFunctions/Gamma/Basic.lean | 11 ++-- .../Analysis/SpecialFunctions/Gamma/Beta.lean | 4 +- .../Analysis/SpecialFunctions/Integrals.lean | 4 +- .../Analysis/SpecialFunctions/PolarCoord.lean | 9 ++- .../SpecialFunctions/Pow/Continuity.lean | 23 +++----- .../Analysis/SpecialFunctions/Pow/Deriv.lean | 32 +++++----- 13 files changed, 209 insertions(+), 80 deletions(-) create mode 100644 Mathlib/Analysis/Complex/Convex.lean diff --git a/Mathlib.lean b/Mathlib.lean index f6c157c8d77e1..79ab6330bfa83 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -655,6 +655,7 @@ import Mathlib.Analysis.Complex.Basic import Mathlib.Analysis.Complex.CauchyIntegral import Mathlib.Analysis.Complex.Circle import Mathlib.Analysis.Complex.Conformal +import Mathlib.Analysis.Complex.Convex import Mathlib.Analysis.Complex.Isometry import Mathlib.Analysis.Complex.Liouville import Mathlib.Analysis.Complex.LocallyUniformLimit diff --git a/Mathlib/Analysis/Complex/Basic.lean b/Mathlib/Analysis/Complex/Basic.lean index 9e1c2f1a459ea..076cf049ab763 100644 --- a/Mathlib/Analysis/Complex/Basic.lean +++ b/Mathlib/Analysis/Complex/Basic.lean @@ -628,4 +628,62 @@ theorem hasSum_iff (f : α → ℂ) (c : ℂ) : end tsum +section slitPlane + +/-! +### Define the "slit plane" `ℂ ∖ ℝ≤0` and provide some API +-/ + +open scoped ComplexOrder + +/-- The *slit plane* is the complex plane with the closed negative real axis removed. -/ +def slitPlane : Set ℂ := {z | 0 < z.re ∨ z.im ≠ 0} + +lemma mem_slitPlane_iff {z : ℂ} : z ∈ slitPlane ↔ 0 < z.re ∨ z.im ≠ 0 := Iff.rfl + +lemma slitPlane_eq_union : slitPlane = {z | 0 < z.re} ∪ {z | z.im ≠ 0} := rfl + +lemma isOpen_slitPlane : IsOpen slitPlane := + (isOpen_lt continuous_const continuous_re).union (isOpen_ne_fun continuous_im continuous_const) + +@[simp] +lemma ofReal_mem_slitPlane {x : ℝ} : ↑x ∈ slitPlane ↔ 0 < x := by simp [mem_slitPlane_iff] + +@[simp] +lemma neg_ofReal_mem_slitPlane {x : ℝ} : -↑x ∈ slitPlane ↔ x < 0 := by + simpa using ofReal_mem_slitPlane (x := -x) + +@[simp] lemma one_mem_slitPlane : 1 ∈ slitPlane := ofReal_mem_slitPlane.2 one_pos + +@[simp] +lemma zero_not_mem_slitPlane : 0 ∉ slitPlane := mt ofReal_mem_slitPlane.1 (lt_irrefl _) + +@[simp] +lemma nat_cast_mem_slitPlane {n : ℕ} : ↑n ∈ slitPlane ↔ n ≠ 0 := by + simpa [pos_iff_ne_zero] using @ofReal_mem_slitPlane n + +@[simp] +lemma ofNat_mem_slitPlane (n : ℕ) [h : n.AtLeastTwo] : no_index (OfNat.ofNat n) ∈ slitPlane := + nat_cast_mem_slitPlane.2 h.ne_zero + +lemma mem_slitPlane_iff_not_le_zero {z : ℂ} : z ∈ slitPlane ↔ ¬z ≤ 0 := + mem_slitPlane_iff.trans not_le_zero_iff.symm + +protected lemma compl_Iic_zero : (Set.Iic 0)ᶜ = slitPlane := Set.ext fun _ ↦ + mem_slitPlane_iff_not_le_zero.symm + +lemma slitPlane_ne_zero {z : ℂ} (hz : z ∈ slitPlane) : z ≠ 0 := + ne_of_mem_of_not_mem hz zero_not_mem_slitPlane + +/-- The slit plane includes the open unit ball of radius `1` around `1`. -/ +lemma ball_one_subset_slitPlane : Metric.ball 1 1 ⊆ slitPlane := fun z hz ↦ .inl <| + have : -1 < z.re - 1 := neg_lt_of_abs_lt <| (abs_re_le_abs _).trans_lt hz + by linarith + +/-- The slit plane includes the open unit ball of radius `1` around `1`. -/ +lemma mem_slitPlane_of_norm_lt_one {z : ℂ} (hz : ‖z‖ < 1) : 1 + z ∈ slitPlane := + ball_one_subset_slitPlane <| by simpa + +end slitPlane + end Complex diff --git a/Mathlib/Analysis/Complex/Convex.lean b/Mathlib/Analysis/Complex/Convex.lean new file mode 100644 index 0000000000000..96693661423f2 --- /dev/null +++ b/Mathlib/Analysis/Complex/Convex.lean @@ -0,0 +1,36 @@ +/- +Copyright (c) 2023 Yury G. Kudryashov. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yury G. Kudryashov +-/ +import Mathlib.Analysis.Convex.Combination +import Mathlib.Analysis.Complex.Basic + +/-! +# Theorems about convexity on the complex plane +-/ + +open Set +open scoped ComplexOrder + +namespace Complex + +/-- A version of `convexHull_prod` for `Set.reProdIm`. -/ +lemma convexHull_reProdIm (s t : Set ℝ) : + convexHull ℝ (s ×ℂ t) = convexHull ℝ s ×ℂ convexHull ℝ t := + calc + convexHull ℝ (equivRealProdLm ⁻¹' (s ×ˢ t)) = equivRealProdLm ⁻¹' (convexHull ℝ (s ×ˢ t)) := by + simpa only [← LinearEquiv.image_symm_eq_preimage] + using equivRealProdLm.symm.toLinearMap.convexHull_image (s ×ˢ t) + _ = convexHull ℝ s ×ℂ convexHull ℝ t := by rw [convexHull_prod]; rfl + +/-- The slit plane is star-convex at a positive number. -/ +lemma starConvex_slitPlane {z : ℂ} (hz : 0 < z) : StarConvex ℝ z slitPlane := + Complex.compl_Iic_zero ▸ starConvex_compl_Iic hz + +/-- The slit plane is star-shaped at a positive real number. -/ +lemma starConvex_ofReal_slitPlane {x : ℝ} (hx : 0 < x) : StarConvex ℝ ↑x slitPlane := + starConvex_slitPlane <| zero_lt_real.2 hx + +/-- The slit plane is star-shaped at `1`. -/ +lemma starConvex_one_slitPlane : StarConvex ℝ 1 slitPlane := starConvex_slitPlane one_pos diff --git a/Mathlib/Analysis/Convex/Star.lean b/Mathlib/Analysis/Convex/Star.lean index d36393427237c..bf6fb39a588e4 100644 --- a/Mathlib/Analysis/Convex/Star.lean +++ b/Mathlib/Analysis/Convex/Star.lean @@ -376,6 +376,28 @@ theorem StarConvex.sub (hs : StarConvex 𝕜 x s) (ht : StarConvex 𝕜 y t) : end AddCommGroup +section OrderedAddCommGroup + +variable [OrderedAddCommGroup E] [Module 𝕜 E] [OrderedSMul 𝕜 E] {x y : E} + +/-- If `x < y`, then `(Set.Iic x)ᶜ` is star convex at `y`. -/ +lemma starConvex_compl_Iic (h : x < y) : StarConvex 𝕜 y (Iic x)ᶜ := by + refine (starConvex_iff_forall_pos <| by simp [h.not_le]).mpr fun z hz a b ha hb hab ↦ ?_ + rw [mem_compl_iff, mem_Iic] at hz ⊢ + contrapose! hz + refine (lt_of_smul_lt_smul_of_nonneg ?_ hb.le).le + calc + b • z ≤ (a + b) • x - a • y := by rwa [le_sub_iff_add_le', hab, one_smul] + _ < b • x := by + rw [add_smul, sub_lt_iff_lt_add'] + gcongr + +/-- If `x < y`, then `(Set.Ici y)ᶜ` is star convex at `x`. -/ +lemma starConvex_compl_Ici (h : x < y) : StarConvex 𝕜 x (Ici y)ᶜ := + starConvex_compl_Iic (E := Eᵒᵈ) h + +end OrderedAddCommGroup + end OrderedRing section LinearOrderedField @@ -417,9 +439,10 @@ end LinearOrderedField Relates `starConvex` and `Set.ordConnected`. -/ - section OrdConnected +/-- If `s` is an order-connected set in an ordered module over an ordered semiring +and all elements of `s` are comparable with `x ∈ s`, then `s` is `StarConvex` at `x`. -/ theorem Set.OrdConnected.starConvex [OrderedSemiring 𝕜] [OrderedAddCommMonoid E] [Module 𝕜 E] [OrderedSMul 𝕜 E] {x : E} {s : Set E} (hs : s.OrdConnected) (hx : x ∈ s) (h : ∀ y ∈ s, x ≤ y ∨ y ≤ x) : StarConvex 𝕜 x s := by diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean index 6a8f900b4f81e..6789f86147e78 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean @@ -236,6 +236,10 @@ theorem arg_eq_zero_iff {z : ℂ} : arg z = 0 ↔ 0 ≤ z.re ∧ z.im = 0 := by exact arg_ofReal_of_nonneg h #align complex.arg_eq_zero_iff Complex.arg_eq_zero_iff +open ComplexOrder in +lemma arg_eq_zero_iff_zero_le {z : ℂ} : arg z = 0 ↔ 0 ≤ z := by + rw [arg_eq_zero_iff, eq_comm]; rfl + theorem arg_eq_pi_iff {z : ℂ} : arg z = π ↔ z.re < 0 ∧ z.im = 0 := by by_cases h₀ : z = 0; simp [h₀, lt_irrefl, Real.pi_ne_zero.symm] constructor @@ -248,6 +252,9 @@ theorem arg_eq_pi_iff {z : ℂ} : arg z = π ↔ z.re < 0 ∧ z.im = 0 := by simp [← ofReal_def] #align complex.arg_eq_pi_iff Complex.arg_eq_pi_iff +open ComplexOrder in +lemma arg_eq_pi_iff_lt_zero {z : ℂ} : arg z = π ↔ z < 0 := arg_eq_pi_iff + theorem arg_lt_pi_iff {z : ℂ} : arg z < π ↔ 0 ≤ z.re ∨ z.im ≠ 0 := by rw [(arg_le_pi z).lt_iff_ne, not_iff_comm, not_or, not_le, Classical.not_not, arg_eq_pi_iff] #align complex.arg_lt_pi_iff Complex.arg_lt_pi_iff @@ -521,6 +528,19 @@ lemma arg_mul_eq_add_arg_iff {x y : ℂ} (hx₀ : x ≠ 0) (hy₀ : y ≠ 0) : alias ⟨_, arg_mul⟩ := arg_mul_eq_add_arg_iff +section slitPlane + +open ComplexOrder in +/-- An alternative description of the slit plane as consisting of nonzero complex numbers +whose argument is not π. -/ +lemma mem_slitPlane_iff_arg {z : ℂ} : z ∈ slitPlane ↔ z.arg ≠ π ∧ z ≠ 0 := by + simp only [mem_slitPlane_iff_not_le_zero, le_iff_lt_or_eq, ne_eq, arg_eq_pi_iff_lt_zero, not_or] + +lemma slitPlane_arg_ne_pi {z : ℂ} (hz : z ∈ slitPlane) : z.arg ≠ Real.pi := + (mem_slitPlane_iff_arg.mp hz).1 + +end slitPlane + section Continuity variable {x z : ℂ} @@ -555,12 +575,11 @@ theorem arg_eq_nhds_of_im_neg (hz : im z < 0) : arg =ᶠ[𝓝 z] fun x => -Real. ((continuous_im.tendsto _).eventually (gt_mem_nhds hz)).mono fun _ => arg_of_im_neg #align complex.arg_eq_nhds_of_im_neg Complex.arg_eq_nhds_of_im_neg -theorem continuousAt_arg (h : 0 < x.re ∨ x.im ≠ 0) : ContinuousAt arg x := by +theorem continuousAt_arg (h : x ∈ slitPlane) : ContinuousAt arg x := by have h₀ : abs x ≠ 0 := by rw [abs.ne_zero_iff] - rintro rfl - simp at h - rw [← lt_or_lt_iff_ne] at h + exact slitPlane_ne_zero h + rw [mem_slitPlane_iff, ← lt_or_lt_iff_ne] at h rcases h with (hx_re | hx_im | hx_im) exacts [(Real.continuousAt_arcsin.comp (continuous_im.continuousAt.div continuous_abs.continuousAt h₀)).congr @@ -619,7 +638,7 @@ theorem tendsto_arg_nhdsWithin_im_nonneg_of_re_neg_of_im_zero {z : ℂ} (hre : z #align complex.tendsto_arg_nhds_within_im_nonneg_of_re_neg_of_im_zero Complex.tendsto_arg_nhdsWithin_im_nonneg_of_re_neg_of_im_zero theorem continuousAt_arg_coe_angle (h : x ≠ 0) : ContinuousAt ((↑) ∘ arg : ℂ → Real.Angle) x := by - by_cases hs : 0 < x.re ∨ x.im ≠ 0 + by_cases hs : x ∈ slitPlane · exact Real.Angle.continuous_coe.continuousAt.comp (continuousAt_arg hs) · rw [← Function.comp.right_id (((↑) : ℝ → Real.Angle) ∘ arg), (Function.funext_iff.2 fun _ => (neg_neg _).symm : (id : ℂ → ℂ) = Neg.neg ∘ Neg.neg), ← @@ -633,6 +652,7 @@ theorem continuousAt_arg_coe_angle (h : x ≠ 0) : ContinuousAt ((↑) ∘ arg : rw [Function.update_eq_iff] exact ⟨by simp, fun z hz => arg_neg_coe_angle hz⟩ rw [ha] + replace hs := mem_slitPlane_iff.mpr.mt hs push_neg at hs refine' (Real.Angle.continuous_coe.continuousAt.comp (continuousAt_arg (Or.inl _))).add diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Log.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Log.lean index cc12497371ab1..24f6176baa772 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Log.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Log.lean @@ -236,20 +236,18 @@ open Topology variable {α : Type*} -theorem continuousAt_clog {x : ℂ} (h : 0 < x.re ∨ x.im ≠ 0) : ContinuousAt log x := by +theorem continuousAt_clog {x : ℂ} (h : x ∈ slitPlane) : ContinuousAt log x := by refine' ContinuousAt.add _ _ · refine' continuous_ofReal.continuousAt.comp _ refine' (Real.continuousAt_log _).comp Complex.continuous_abs.continuousAt - rw [Complex.abs.ne_zero_iff] - rintro rfl - simp at h + exact Complex.abs.ne_zero_iff.mpr <| slitPlane_ne_zero h · have h_cont_mul : Continuous fun x : ℂ => x * I := continuous_id'.mul continuous_const refine' h_cont_mul.continuousAt.comp (continuous_ofReal.continuousAt.comp _) exact continuousAt_arg h #align continuous_at_clog continuousAt_clog theorem _root_.Filter.Tendsto.clog {l : Filter α} {f : α → ℂ} {x : ℂ} (h : Tendsto f l (𝓝 x)) - (hx : 0 < x.re ∨ x.im ≠ 0) : Tendsto (fun t => log (f t)) l (𝓝 <| log x) := + (hx : x ∈ slitPlane) : Tendsto (fun t => log (f t)) l (𝓝 <| log x) := (continuousAt_clog hx).tendsto.comp h #align filter.tendsto.clog Filter.Tendsto.clog @@ -257,26 +255,26 @@ variable [TopologicalSpace α] nonrec theorem _root_.ContinuousAt.clog {f : α → ℂ} {x : α} (h₁ : ContinuousAt f x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : ContinuousAt (fun t => log (f t)) x := + (h₂ : f x ∈ slitPlane) : ContinuousAt (fun t => log (f t)) x := h₁.clog h₂ #align continuous_at.clog ContinuousAt.clog nonrec theorem _root_.ContinuousWithinAt.clog {f : α → ℂ} {s : Set α} {x : α} - (h₁ : ContinuousWithinAt f s x) (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : + (h₁ : ContinuousWithinAt f s x) (h₂ : f x ∈ slitPlane) : ContinuousWithinAt (fun t => log (f t)) s x := h₁.clog h₂ #align continuous_within_at.clog ContinuousWithinAt.clog nonrec theorem _root_.ContinuousOn.clog {f : α → ℂ} {s : Set α} (h₁ : ContinuousOn f s) - (h₂ : ∀ x ∈ s, 0 < (f x).re ∨ (f x).im ≠ 0) : ContinuousOn (fun t => log (f t)) s := fun x hx => + (h₂ : ∀ x ∈ s, f x ∈ slitPlane) : ContinuousOn (fun t => log (f t)) s := fun x hx => (h₁ x hx).clog (h₂ x hx) #align continuous_on.clog ContinuousOn.clog nonrec theorem _root_.Continuous.clog {f : α → ℂ} (h₁ : Continuous f) - (h₂ : ∀ x, 0 < (f x).re ∨ (f x).im ≠ 0) : Continuous fun t => log (f t) := + (h₂ : ∀ x, f x ∈ slitPlane) : Continuous fun t => log (f t) := continuous_iff_continuousAt.2 fun x => h₁.continuousAt.clog (h₂ x) #align continuous.clog Continuous.clog diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean index fc9706d537e53..7fddce82151b9 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean @@ -33,35 +33,35 @@ noncomputable def expPartialHomeomorph : PartialHomeomorph ℂ ℂ := { toFun := exp invFun := log source := {z : ℂ | z.im ∈ Ioo (-π) π} - target := {z : ℂ | 0 < z.re} ∪ {z : ℂ | z.im ≠ 0} + target := slitPlane map_source' := by rintro ⟨x, y⟩ ⟨h₁ : -π < y, h₂ : y < π⟩ refine' (not_or_of_imp fun hz => _).symm obtain rfl : y = 0 := by rw [exp_im] at hz simpa [(Real.exp_pos _).ne', Real.sin_eq_zero_iff_of_lt_of_lt h₁ h₂] using hz - rw [mem_setOf_eq, ← ofReal_def, exp_ofReal_re] + rw [← ofReal_def, exp_ofReal_re] exact Real.exp_pos x map_target' := fun z h => by simp only [mem_setOf, log_im, mem_Ioo, neg_pi_lt_arg, arg_lt_pi_iff, true_and] exact h.imp_left le_of_lt left_inv' := fun x hx => log_exp hx.1 (le_of_lt hx.2) - right_inv' := fun x hx => exp_log <| by rintro rfl; simp [lt_irrefl] at hx } + right_inv' := fun x hx => exp_log <| slitPlane_ne_zero hx } continuous_exp.continuousOn isOpenMap_exp (isOpen_Ioo.preimage continuous_im) #align complex.exp_local_homeomorph Complex.expPartialHomeomorph -theorem hasStrictDerivAt_log {x : ℂ} (h : 0 < x.re ∨ x.im ≠ 0) : HasStrictDerivAt log x⁻¹ x := - have h0 : x ≠ 0 := by rintro rfl; simp [lt_irrefl] at h +theorem hasStrictDerivAt_log {x : ℂ} (h : x ∈ slitPlane) : HasStrictDerivAt log x⁻¹ x := + have h0 : x ≠ 0 := slitPlane_ne_zero h expPartialHomeomorph.hasStrictDerivAt_symm h h0 <| by simpa [exp_log h0] using hasStrictDerivAt_exp (log x) #align complex.has_strict_deriv_at_log Complex.hasStrictDerivAt_log -theorem hasStrictFDerivAt_log_real {x : ℂ} (h : 0 < x.re ∨ x.im ≠ 0) : +theorem hasStrictFDerivAt_log_real {x : ℂ} (h : x ∈ slitPlane) : HasStrictFDerivAt log (x⁻¹ • (1 : ℂ →L[ℝ] ℂ)) x := (hasStrictDerivAt_log h).complexToReal_fderiv #align complex.has_strict_fderiv_at_log_real Complex.hasStrictFDerivAt_log_real -theorem contDiffAt_log {x : ℂ} (h : 0 < x.re ∨ x.im ≠ 0) {n : ℕ∞} : ContDiffAt ℂ n log x := +theorem contDiffAt_log {x : ℂ} (h : x ∈ slitPlane) {n : ℕ∞} : ContDiffAt ℂ n log x := expPartialHomeomorph.contDiffAt_symm_deriv (exp_ne_zero <| log x) h (hasDerivAt_exp _) contDiff_exp.contDiffAt #align complex.cont_diff_at_log Complex.contDiffAt_log @@ -77,73 +77,73 @@ open scoped Topology variable {α : Type*} [TopologicalSpace α] {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] theorem HasStrictFDerivAt.clog {f : E → ℂ} {f' : E →L[ℂ] ℂ} {x : E} (h₁ : HasStrictFDerivAt f f' x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : HasStrictFDerivAt (fun t => log (f t)) ((f x)⁻¹ • f') x := + (h₂ : f x ∈ slitPlane) : HasStrictFDerivAt (fun t => log (f t)) ((f x)⁻¹ • f') x := (hasStrictDerivAt_log h₂).comp_hasStrictFDerivAt x h₁ #align has_strict_fderiv_at.clog HasStrictFDerivAt.clog theorem HasStrictDerivAt.clog {f : ℂ → ℂ} {f' x : ℂ} (h₁ : HasStrictDerivAt f f' x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : HasStrictDerivAt (fun t => log (f t)) (f' / f x) x := by + (h₂ : f x ∈ slitPlane) : HasStrictDerivAt (fun t => log (f t)) (f' / f x) x := by rw [div_eq_inv_mul]; exact (hasStrictDerivAt_log h₂).comp x h₁ #align has_strict_deriv_at.clog HasStrictDerivAt.clog theorem HasStrictDerivAt.clog_real {f : ℝ → ℂ} {x : ℝ} {f' : ℂ} (h₁ : HasStrictDerivAt f f' x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : HasStrictDerivAt (fun t => log (f t)) (f' / f x) x := by + (h₂ : f x ∈ slitPlane) : HasStrictDerivAt (fun t => log (f t)) (f' / f x) x := by simpa only [div_eq_inv_mul] using (hasStrictFDerivAt_log_real h₂).comp_hasStrictDerivAt x h₁ #align has_strict_deriv_at.clog_real HasStrictDerivAt.clog_real theorem HasFDerivAt.clog {f : E → ℂ} {f' : E →L[ℂ] ℂ} {x : E} (h₁ : HasFDerivAt f f' x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : HasFDerivAt (fun t => log (f t)) ((f x)⁻¹ • f') x := + (h₂ : f x ∈ slitPlane) : HasFDerivAt (fun t => log (f t)) ((f x)⁻¹ • f') x := (hasStrictDerivAt_log h₂).hasDerivAt.comp_hasFDerivAt x h₁ #align has_fderiv_at.clog HasFDerivAt.clog theorem HasDerivAt.clog {f : ℂ → ℂ} {f' x : ℂ} (h₁ : HasDerivAt f f' x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : HasDerivAt (fun t => log (f t)) (f' / f x) x := by + (h₂ : f x ∈ slitPlane) : HasDerivAt (fun t => log (f t)) (f' / f x) x := by rw [div_eq_inv_mul]; exact (hasStrictDerivAt_log h₂).hasDerivAt.comp x h₁ #align has_deriv_at.clog HasDerivAt.clog theorem HasDerivAt.clog_real {f : ℝ → ℂ} {x : ℝ} {f' : ℂ} (h₁ : HasDerivAt f f' x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : HasDerivAt (fun t => log (f t)) (f' / f x) x := by + (h₂ : f x ∈ slitPlane) : HasDerivAt (fun t => log (f t)) (f' / f x) x := by simpa only [div_eq_inv_mul] using (hasStrictFDerivAt_log_real h₂).hasFDerivAt.comp_hasDerivAt x h₁ #align has_deriv_at.clog_real HasDerivAt.clog_real theorem DifferentiableAt.clog {f : E → ℂ} {x : E} (h₁ : DifferentiableAt ℂ f x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : DifferentiableAt ℂ (fun t => log (f t)) x := + (h₂ : f x ∈ slitPlane) : DifferentiableAt ℂ (fun t => log (f t)) x := (h₁.hasFDerivAt.clog h₂).differentiableAt #align differentiable_at.clog DifferentiableAt.clog theorem HasFDerivWithinAt.clog {f : E → ℂ} {f' : E →L[ℂ] ℂ} {s : Set E} {x : E} - (h₁ : HasFDerivWithinAt f f' s x) (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : + (h₁ : HasFDerivWithinAt f f' s x) (h₂ : f x ∈ slitPlane) : HasFDerivWithinAt (fun t => log (f t)) ((f x)⁻¹ • f') s x := (hasStrictDerivAt_log h₂).hasDerivAt.comp_hasFDerivWithinAt x h₁ #align has_fderiv_within_at.clog HasFDerivWithinAt.clog theorem HasDerivWithinAt.clog {f : ℂ → ℂ} {f' x : ℂ} {s : Set ℂ} (h₁ : HasDerivWithinAt f f' s x) - (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : HasDerivWithinAt (fun t => log (f t)) (f' / f x) s x := by + (h₂ : f x ∈ slitPlane) : HasDerivWithinAt (fun t => log (f t)) (f' / f x) s x := by rw [div_eq_inv_mul] exact (hasStrictDerivAt_log h₂).hasDerivAt.comp_hasDerivWithinAt x h₁ #align has_deriv_within_at.clog HasDerivWithinAt.clog theorem HasDerivWithinAt.clog_real {f : ℝ → ℂ} {s : Set ℝ} {x : ℝ} {f' : ℂ} - (h₁ : HasDerivWithinAt f f' s x) (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : + (h₁ : HasDerivWithinAt f f' s x) (h₂ : f x ∈ slitPlane) : HasDerivWithinAt (fun t => log (f t)) (f' / f x) s x := by simpa only [div_eq_inv_mul] using (hasStrictFDerivAt_log_real h₂).hasFDerivAt.comp_hasDerivWithinAt x h₁ #align has_deriv_within_at.clog_real HasDerivWithinAt.clog_real theorem DifferentiableWithinAt.clog {f : E → ℂ} {s : Set E} {x : E} - (h₁ : DifferentiableWithinAt ℂ f s x) (h₂ : 0 < (f x).re ∨ (f x).im ≠ 0) : + (h₁ : DifferentiableWithinAt ℂ f s x) (h₂ : f x ∈ slitPlane) : DifferentiableWithinAt ℂ (fun t => log (f t)) s x := (h₁.hasFDerivWithinAt.clog h₂).differentiableWithinAt #align differentiable_within_at.clog DifferentiableWithinAt.clog theorem DifferentiableOn.clog {f : E → ℂ} {s : Set E} (h₁ : DifferentiableOn ℂ f s) - (h₂ : ∀ x ∈ s, 0 < (f x).re ∨ (f x).im ≠ 0) : DifferentiableOn ℂ (fun t => log (f t)) s := + (h₂ : ∀ x ∈ s, f x ∈ slitPlane) : DifferentiableOn ℂ (fun t => log (f t)) s := fun x hx => (h₁ x hx).clog (h₂ x hx) #align differentiable_on.clog DifferentiableOn.clog theorem Differentiable.clog {f : E → ℂ} (h₁ : Differentiable ℂ f) - (h₂ : ∀ x, 0 < (f x).re ∨ (f x).im ≠ 0) : Differentiable ℂ fun t => log (f t) := fun x => + (h₂ : ∀ x, f x ∈ slitPlane) : Differentiable ℂ fun t => log (f t) := fun x => (h₁ x).clog (h₂ x) #align differentiable.clog Differentiable.clog diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean index 462ed8d781a71..e000d4540f824 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean @@ -100,8 +100,8 @@ theorem GammaIntegral_convergent {s : ℂ} (hs : 0 < s.re) : apply (continuous_ofReal.comp continuous_neg.exp).continuousOn.mul apply ContinuousAt.continuousOn intro x hx - have : ContinuousAt (fun x : ℂ => x ^ (s - 1)) ↑x := by - apply continuousAt_cpow_const; rw [ofReal_re]; exact Or.inl hx + have : ContinuousAt (fun x : ℂ => x ^ (s - 1)) ↑x := + continuousAt_cpow_const <| ofReal_mem_slitPlane.2 hx exact ContinuousAt.comp this continuous_ofReal.continuousAt · rw [← hasFiniteIntegral_norm_iff] refine' HasFiniteIntegral.congr (Real.GammaIntegral_convergent hs).2 _ @@ -189,7 +189,7 @@ private theorem Gamma_integrand_deriv_integrable_B {s : ℂ} (hs : 0 < s.re) {Y apply ContinuousAt.continuousOn intro x hx refine' (_ : ContinuousAt (fun x : ℂ => x ^ (s - 1)) _).comp continuous_ofReal.continuousAt - apply continuousAt_cpow_const; rw [ofReal_re]; exact Or.inl hx.1 + exact continuousAt_cpow_const <| ofReal_mem_slitPlane.2 hx.1 rw [← hasFiniteIntegral_norm_iff] simp_rw [norm_eq_abs, map_mul] refine' (((Real.GammaIntegral_convergent hs).mono_set @@ -211,9 +211,8 @@ theorem partialGamma_add_one {s : ℂ} (hs : 0 < s.re) {X : ℝ} (hX : 0 ≤ X) simpa using (hasDerivAt_neg x).exp have d2 : HasDerivAt (fun y : ℝ => (y : ℂ) ^ s) (s * x ^ (s - 1)) x := by have t := @HasDerivAt.cpow_const _ _ _ s (hasDerivAt_id ↑x) ?_ - simpa only [mul_one] using t.comp_ofReal - simpa only [id.def, ofReal_re, ofReal_im, Ne.def, eq_self_iff_true, not_true, or_false_iff, - mul_one] using hx.1 + · simpa only [mul_one] using t.comp_ofReal + · exact ofReal_mem_slitPlane.2 hx.1 simpa only [ofReal_neg, neg_mul] using d1.ofReal_comp.mul d2 have cont := (continuous_ofReal.comp continuous_neg.exp).mul (continuous_ofReal_cpow_const hs) have der_ible := diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean index f5af478858237..82d5e3c41cabd 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean @@ -71,8 +71,8 @@ theorem betaIntegral_convergent_left {u : ℂ} (hu : 0 < re u) (v : ℂ) : apply ContinuousAt.cpow · exact (continuous_const.sub continuous_ofReal).continuousAt · exact continuousAt_const - · rw [sub_re, one_re, ofReal_re, sub_pos] - exact Or.inl (hx.2.trans_lt (by norm_num : (1 / 2 : ℝ) < 1)) + · norm_cast + exact ofReal_mem_slitPlane.2 <| by linarith only [hx.2] #align complex.beta_integral_convergent_left Complex.betaIntegral_convergent_left /-- The Beta integral is convergent for all `u, v` of positive real part. -/ diff --git a/Mathlib/Analysis/SpecialFunctions/Integrals.lean b/Mathlib/Analysis/SpecialFunctions/Integrals.lean index 7df44514485bb..ff8cef8b00bee 100644 --- a/Mathlib/Analysis/SpecialFunctions/Integrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/Integrals.lean @@ -610,8 +610,8 @@ theorem integral_mul_cpow_one_add_sq {t : ℂ} (ht : t ≠ -1) : · exact continuous_const.add (continuous_ofReal.pow 2) · exact continuous_const · intro a - rw [add_re, one_re, ← ofReal_pow, ofReal_re] - exact Or.inl (add_pos_of_pos_of_nonneg zero_lt_one (sq_nonneg a)) + norm_cast + exact ofReal_mem_slitPlane.2 <| add_pos_of_pos_of_nonneg one_pos <| sq_nonneg a #align integral_mul_cpow_one_add_sq integral_mul_cpow_one_add_sq theorem integral_mul_rpow_one_add_sq {t : ℝ} (ht : t ≠ -1) : diff --git a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean index 80db011c91c89..964110be02c95 100644 --- a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean +++ b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean @@ -83,7 +83,7 @@ def polarCoord : PartialHomeomorph (ℝ × ℝ) (ℝ × ℝ) where continuousOn_toFun := by apply ((continuous_fst.pow 2).add (continuous_snd.pow 2)).sqrt.continuousOn.prod have A : MapsTo Complex.equivRealProd.symm ({q : ℝ × ℝ | 0 < q.1} ∪ {q : ℝ × ℝ | q.2 ≠ 0}) - {z | 0 < z.re ∨ z.im ≠ 0} := by + Complex.slitPlane := by rintro ⟨x, y⟩ hxy; simpa only using hxy refine' ContinuousOn.comp (f := Complex.equivRealProd.symm) (g := Complex.arg) (fun z hz => _) _ A @@ -161,18 +161,17 @@ open scoped Real /-- The polar coordinates local homeomorphism in `ℂ`, mapping `r (cos θ + I * sin θ)` to `(r, θ)`. It is a homeomorphism between `ℂ - ℝ≤0` and `(0, +∞) × (-π, π)`. -/ protected noncomputable def polarCoord : PartialHomeomorph ℂ (ℝ × ℝ) := - equivRealProdClm.toHomeomorph.toPartialHomeomorph.trans polarCoord + equivRealProdClm.toHomeomorph.transPartialHomeomorph polarCoord protected theorem polarCoord_apply (a : ℂ) : Complex.polarCoord a = (Complex.abs a, Complex.arg a) := by simp_rw [Complex.abs_def, Complex.normSq_apply, ← pow_two] rfl -protected theorem polarCoord_source : - Complex.polarCoord.source = {a | 0 < a.re} ∪ {a | a.im ≠ 0} := by simp [Complex.polarCoord] +protected theorem polarCoord_source : Complex.polarCoord.source = slitPlane := rfl protected theorem polarCoord_target : - Complex.polarCoord.target = Set.Ioi (0 : ℝ) ×ˢ Set.Ioo (-π) π := by simp [Complex.polarCoord] + Complex.polarCoord.target = Set.Ioi (0 : ℝ) ×ˢ Set.Ioo (-π) π := rfl @[simp] protected theorem polarCoord_symm_apply (p : ℝ × ℝ) : diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean index cc599f1328a88..79902cf702f13 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean @@ -83,14 +83,9 @@ theorem continuousAt_const_cpow' {a b : ℂ} (h : b ≠ 0) : ContinuousAt (fun x /-- The function `z ^ w` is continuous in `(z, w)` provided that `z` does not belong to the interval `(-∞, 0]` on the real line. See also `Complex.continuousAt_cpow_zero_of_re_pos` for a version that works for `z = 0` but assumes `0 < re w`. -/ -theorem continuousAt_cpow {p : ℂ × ℂ} (hp_fst : 0 < p.fst.re ∨ p.fst.im ≠ 0) : +theorem continuousAt_cpow {p : ℂ × ℂ} (hp_fst : p.fst ∈ slitPlane) : ContinuousAt (fun x : ℂ × ℂ => x.1 ^ x.2) p := by - have hp_fst_ne_zero : p.fst ≠ 0 := by - intro h - cases' hp_fst with hp_fst hp_fst <;> - · rw [h] at hp_fst - simp at hp_fst - rw [continuousAt_congr (cpow_eq_nhds' hp_fst_ne_zero)] + rw [continuousAt_congr (cpow_eq_nhds' <| slitPlane_ne_zero hp_fst)] refine' continuous_exp.continuousAt.comp _ exact ContinuousAt.mul @@ -98,13 +93,13 @@ theorem continuousAt_cpow {p : ℂ × ℂ} (hp_fst : 0 < p.fst.re ∨ p.fst.im continuous_snd.continuousAt #align continuous_at_cpow continuousAt_cpow -theorem continuousAt_cpow_const {a b : ℂ} (ha : 0 < a.re ∨ a.im ≠ 0) : +theorem continuousAt_cpow_const {a b : ℂ} (ha : a ∈ slitPlane) : ContinuousAt (fun x => cpow x b) a := Tendsto.comp (@continuousAt_cpow (a, b) ha) (continuousAt_id.prod continuousAt_const) #align continuous_at_cpow_const continuousAt_cpow_const theorem Filter.Tendsto.cpow {l : Filter α} {f g : α → ℂ} {a b : ℂ} (hf : Tendsto f l (𝓝 a)) - (hg : Tendsto g l (𝓝 b)) (ha : 0 < a.re ∨ a.im ≠ 0) : + (hg : Tendsto g l (𝓝 b)) (ha : a ∈ slitPlane) : Tendsto (fun x => f x ^ g x) l (𝓝 (a ^ b)) := (@continuousAt_cpow (a, b) ha).tendsto.comp (hf.prod_mk_nhds hg) #align filter.tendsto.cpow Filter.Tendsto.cpow @@ -119,7 +114,7 @@ theorem Filter.Tendsto.const_cpow {l : Filter α} {f : α → ℂ} {a b : ℂ} ( variable [TopologicalSpace α] {f g : α → ℂ} {s : Set α} {a : α} nonrec theorem ContinuousWithinAt.cpow (hf : ContinuousWithinAt f s a) - (hg : ContinuousWithinAt g s a) (h0 : 0 < (f a).re ∨ (f a).im ≠ 0) : + (hg : ContinuousWithinAt g s a) (h0 : f a ∈ slitPlane) : ContinuousWithinAt (fun x => f x ^ g x) s a := hf.cpow hg h0 #align continuous_within_at.cpow ContinuousWithinAt.cpow @@ -130,7 +125,7 @@ nonrec theorem ContinuousWithinAt.const_cpow {b : ℂ} (hf : ContinuousWithinAt #align continuous_within_at.const_cpow ContinuousWithinAt.const_cpow nonrec theorem ContinuousAt.cpow (hf : ContinuousAt f a) (hg : ContinuousAt g a) - (h0 : 0 < (f a).re ∨ (f a).im ≠ 0) : ContinuousAt (fun x => f x ^ g x) a := + (h0 : f a ∈ slitPlane) : ContinuousAt (fun x => f x ^ g x) a := hf.cpow hg h0 #align continuous_at.cpow ContinuousAt.cpow @@ -140,7 +135,7 @@ nonrec theorem ContinuousAt.const_cpow {b : ℂ} (hf : ContinuousAt f a) (h : b #align continuous_at.const_cpow ContinuousAt.const_cpow theorem ContinuousOn.cpow (hf : ContinuousOn f s) (hg : ContinuousOn g s) - (h0 : ∀ a ∈ s, 0 < (f a).re ∨ (f a).im ≠ 0) : ContinuousOn (fun x => f x ^ g x) s := fun a ha => + (h0 : ∀ a ∈ s, f a ∈ slitPlane) : ContinuousOn (fun x => f x ^ g x) s := fun a ha => (hf a ha).cpow (hg a ha) (h0 a ha) #align continuous_on.cpow ContinuousOn.cpow @@ -149,7 +144,7 @@ theorem ContinuousOn.const_cpow {b : ℂ} (hf : ContinuousOn f s) (h : b ≠ 0 #align continuous_on.const_cpow ContinuousOn.const_cpow theorem Continuous.cpow (hf : Continuous f) (hg : Continuous g) - (h0 : ∀ a, 0 < (f a).re ∨ (f a).im ≠ 0) : Continuous fun x => f x ^ g x := + (h0 : ∀ a, f a ∈ slitPlane) : Continuous fun x => f x ^ g x := continuous_iff_continuousAt.2 fun a => hf.continuousAt.cpow hg.continuousAt (h0 a) #align continuous.cpow Continuous.cpow @@ -159,7 +154,7 @@ theorem Continuous.const_cpow {b : ℂ} (hf : Continuous f) (h : b ≠ 0 ∨ ∀ #align continuous.const_cpow Continuous.const_cpow theorem ContinuousOn.cpow_const {b : ℂ} (hf : ContinuousOn f s) - (h : ∀ a : α, a ∈ s → 0 < (f a).re ∨ (f a).im ≠ 0) : ContinuousOn (fun x => f x ^ b) s := + (h : ∀ a : α, a ∈ s → f a ∈ slitPlane) : ContinuousOn (fun x => f x ^ b) s := hf.cpow continuousOn_const h #align continuous_on.cpow_const ContinuousOn.cpow_const diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean index 41bded1ec1b11..5af1765dc0489 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean @@ -28,11 +28,11 @@ open Filter namespace Complex -theorem hasStrictFDerivAt_cpow {p : ℂ × ℂ} (hp : 0 < p.1.re ∨ p.1.im ≠ 0) : +theorem hasStrictFDerivAt_cpow {p : ℂ × ℂ} (hp : p.1 ∈ slitPlane) : HasStrictFDerivAt (fun x : ℂ × ℂ => x.1 ^ x.2) ((p.2 * p.1 ^ (p.2 - 1)) • ContinuousLinearMap.fst ℂ ℂ ℂ + (p.1 ^ p.2 * log p.1) • ContinuousLinearMap.snd ℂ ℂ ℂ) p := by - have A : p.1 ≠ 0 := by intro h; simp [h, lt_irrefl] at hp + have A : p.1 ≠ 0 := slitPlane_ne_zero hp have : (fun x : ℂ × ℂ => x.1 ^ x.2) =ᶠ[𝓝 p] fun x => exp (log x.1 * x.2) := ((isOpen_ne.preimage continuous_fst).eventually_mem A).mono fun p hp => cpow_def_of_ne_zero hp _ @@ -42,7 +42,7 @@ theorem hasStrictFDerivAt_cpow {p : ℂ × ℂ} (hp : 0 < p.1.re ∨ p.1.im ≠ ((hasStrictFDerivAt_fst.clog hp).mul hasStrictFDerivAt_snd).cexp #align complex.has_strict_fderiv_at_cpow Complex.hasStrictFDerivAt_cpow -theorem hasStrictFDerivAt_cpow' {x y : ℂ} (hp : 0 < x.re ∨ x.im ≠ 0) : +theorem hasStrictFDerivAt_cpow' {x y : ℂ} (hp : x ∈ slitPlane) : HasStrictFDerivAt (fun x : ℂ × ℂ => x.1 ^ x.2) ((y * x ^ (y - 1)) • ContinuousLinearMap.fst ℂ ℂ ℂ + (x ^ y * log x) • ContinuousLinearMap.snd ℂ ℂ ℂ) (x, y) := @@ -60,7 +60,7 @@ theorem hasStrictDerivAt_const_cpow {x y : ℂ} (h : x ≠ 0 ∨ y ≠ 0) : ((hasStrictDerivAt_id y).const_mul (log x)).cexp #align complex.has_strict_deriv_at_const_cpow Complex.hasStrictDerivAt_const_cpow -theorem hasFDerivAt_cpow {p : ℂ × ℂ} (hp : 0 < p.1.re ∨ p.1.im ≠ 0) : +theorem hasFDerivAt_cpow {p : ℂ × ℂ} (hp : p.1 ∈ slitPlane) : HasFDerivAt (fun x : ℂ × ℂ => x.1 ^ x.2) ((p.2 * p.1 ^ (p.2 - 1)) • ContinuousLinearMap.fst ℂ ℂ ℂ + (p.1 ^ p.2 * log p.1) • ContinuousLinearMap.snd ℂ ℂ ℂ) p := @@ -77,7 +77,7 @@ variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {f g : E → ℂ {x : E} {s : Set E} {c : ℂ} theorem HasStrictFDerivAt.cpow (hf : HasStrictFDerivAt f f' x) (hg : HasStrictFDerivAt g g' x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : HasStrictFDerivAt (fun x => f x ^ g x) + (h0 : f x ∈ slitPlane) : HasStrictFDerivAt (fun x => f x ^ g x) ((g x * f x ^ (g x - 1)) • f' + (f x ^ g x * Complex.log (f x)) • g') x := by convert (@hasStrictFDerivAt_cpow ((fun x => (f x, g x)) x) h0).comp x (hf.prod hg) #align has_strict_fderiv_at.cpow HasStrictFDerivAt.cpow @@ -88,7 +88,7 @@ theorem HasStrictFDerivAt.const_cpow (hf : HasStrictFDerivAt f f' x) (h0 : c ≠ #align has_strict_fderiv_at.const_cpow HasStrictFDerivAt.const_cpow theorem HasFDerivAt.cpow (hf : HasFDerivAt f f' x) (hg : HasFDerivAt g g' x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : HasFDerivAt (fun x => f x ^ g x) + (h0 : f x ∈ slitPlane) : HasFDerivAt (fun x => f x ^ g x) ((g x * f x ^ (g x - 1)) • f' + (f x ^ g x * Complex.log (f x)) • g') x := by convert (@Complex.hasFDerivAt_cpow ((fun x => (f x, g x)) x) h0).comp x (hf.prod hg) #align has_fderiv_at.cpow HasFDerivAt.cpow @@ -99,7 +99,7 @@ theorem HasFDerivAt.const_cpow (hf : HasFDerivAt f f' x) (h0 : c ≠ 0 ∨ f x #align has_fderiv_at.const_cpow HasFDerivAt.const_cpow theorem HasFDerivWithinAt.cpow (hf : HasFDerivWithinAt f f' s x) (hg : HasFDerivWithinAt g g' s x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : HasFDerivWithinAt (fun x => f x ^ g x) + (h0 : f x ∈ slitPlane) : HasFDerivWithinAt (fun x => f x ^ g x) ((g x * f x ^ (g x - 1)) • f' + (f x ^ g x * Complex.log (f x)) • g') s x := by convert (@Complex.hasFDerivAt_cpow ((fun x => (f x, g x)) x) h0).comp_hasFDerivWithinAt x (hf.prod hg) @@ -111,7 +111,7 @@ theorem HasFDerivWithinAt.const_cpow (hf : HasFDerivWithinAt f f' s x) (h0 : c #align has_fderiv_within_at.const_cpow HasFDerivWithinAt.const_cpow theorem DifferentiableAt.cpow (hf : DifferentiableAt ℂ f x) (hg : DifferentiableAt ℂ g x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : DifferentiableAt ℂ (fun x => f x ^ g x) x := + (h0 : f x ∈ slitPlane) : DifferentiableAt ℂ (fun x => f x ^ g x) x := (hf.hasFDerivAt.cpow hg.hasFDerivAt h0).differentiableAt #align differentiable_at.cpow DifferentiableAt.cpow @@ -121,7 +121,7 @@ theorem DifferentiableAt.const_cpow (hf : DifferentiableAt ℂ f x) (h0 : c ≠ #align differentiable_at.const_cpow DifferentiableAt.const_cpow theorem DifferentiableWithinAt.cpow (hf : DifferentiableWithinAt ℂ f s x) - (hg : DifferentiableWithinAt ℂ g s x) (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : + (hg : DifferentiableWithinAt ℂ g s x) (h0 : f x ∈ slitPlane) : DifferentiableWithinAt ℂ (fun x => f x ^ g x) s x := (hf.hasFDerivWithinAt.cpow hg.hasFDerivWithinAt h0).differentiableWithinAt #align differentiable_within_at.cpow DifferentiableWithinAt.cpow @@ -149,7 +149,7 @@ private theorem aux : ((g x * f x ^ (g x - 1)) • (1 : ℂ →L[ℂ] ℂ).smulR ContinuousLinearMap.coe_smul'] nonrec theorem HasStrictDerivAt.cpow (hf : HasStrictDerivAt f f' x) (hg : HasStrictDerivAt g g' x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : HasStrictDerivAt (fun x => f x ^ g x) + (h0 : f x ∈ slitPlane) : HasStrictDerivAt (fun x => f x ^ g x) (g x * f x ^ (g x - 1) * f' + f x ^ g x * Complex.log (f x) * g') x := by simpa using (hf.cpow hg h0).hasStrictDerivAt #align has_strict_deriv_at.cpow HasStrictDerivAt.cpow @@ -159,20 +159,20 @@ theorem HasStrictDerivAt.const_cpow (hf : HasStrictDerivAt f f' x) (h : c ≠ 0 (hasStrictDerivAt_const_cpow h).comp x hf #align has_strict_deriv_at.const_cpow HasStrictDerivAt.const_cpow -theorem Complex.hasStrictDerivAt_cpow_const (h : 0 < x.re ∨ x.im ≠ 0) : +theorem Complex.hasStrictDerivAt_cpow_const (h : x ∈ slitPlane) : HasStrictDerivAt (fun z : ℂ => z ^ c) (c * x ^ (c - 1)) x := by simpa only [mul_zero, add_zero, mul_one] using (hasStrictDerivAt_id x).cpow (hasStrictDerivAt_const x c) h #align complex.has_strict_deriv_at_cpow_const Complex.hasStrictDerivAt_cpow_const theorem HasStrictDerivAt.cpow_const (hf : HasStrictDerivAt f f' x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : + (h0 : f x ∈ slitPlane) : HasStrictDerivAt (fun x => f x ^ c) (c * f x ^ (c - 1) * f') x := (Complex.hasStrictDerivAt_cpow_const h0).comp x hf #align has_strict_deriv_at.cpow_const HasStrictDerivAt.cpow_const theorem HasDerivAt.cpow (hf : HasDerivAt f f' x) (hg : HasDerivAt g g' x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : HasDerivAt (fun x => f x ^ g x) + (h0 : f x ∈ slitPlane) : HasDerivAt (fun x => f x ^ g x) (g x * f x ^ (g x - 1) * f' + f x ^ g x * Complex.log (f x) * g') x := by simpa only [aux] using (hf.hasFDerivAt.cpow hg h0).hasDerivAt #align has_deriv_at.cpow HasDerivAt.cpow @@ -182,13 +182,13 @@ theorem HasDerivAt.const_cpow (hf : HasDerivAt f f' x) (h0 : c ≠ 0 ∨ f x ≠ (hasStrictDerivAt_const_cpow h0).hasDerivAt.comp x hf #align has_deriv_at.const_cpow HasDerivAt.const_cpow -theorem HasDerivAt.cpow_const (hf : HasDerivAt f f' x) (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : +theorem HasDerivAt.cpow_const (hf : HasDerivAt f f' x) (h0 : f x ∈ slitPlane) : HasDerivAt (fun x => f x ^ c) (c * f x ^ (c - 1) * f') x := (Complex.hasStrictDerivAt_cpow_const h0).hasDerivAt.comp x hf #align has_deriv_at.cpow_const HasDerivAt.cpow_const theorem HasDerivWithinAt.cpow (hf : HasDerivWithinAt f f' s x) (hg : HasDerivWithinAt g g' s x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : HasDerivWithinAt (fun x => f x ^ g x) + (h0 : f x ∈ slitPlane) : HasDerivWithinAt (fun x => f x ^ g x) (g x * f x ^ (g x - 1) * f' + f x ^ g x * Complex.log (f x) * g') s x := by simpa only [aux] using (hf.hasFDerivWithinAt.cpow hg h0).hasDerivWithinAt #align has_deriv_within_at.cpow HasDerivWithinAt.cpow @@ -199,7 +199,7 @@ theorem HasDerivWithinAt.const_cpow (hf : HasDerivWithinAt f f' s x) (h0 : c ≠ #align has_deriv_within_at.const_cpow HasDerivWithinAt.const_cpow theorem HasDerivWithinAt.cpow_const (hf : HasDerivWithinAt f f' s x) - (h0 : 0 < (f x).re ∨ (f x).im ≠ 0) : + (h0 : f x ∈ slitPlane) : HasDerivWithinAt (fun x => f x ^ c) (c * f x ^ (c - 1) * f') s x := (Complex.hasStrictDerivAt_cpow_const h0).hasDerivAt.comp_hasDerivWithinAt x hf #align has_deriv_within_at.cpow_const HasDerivWithinAt.cpow_const From a9c72c7018c30a7edf1517d93753996c0f2a0da2 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 23 Dec 2023 07:20:01 +0000 Subject: [PATCH 149/353] feat(SetTheory/Cardinal/Basic): add missing `lift` versions of `iUnion` lemmas (#9187) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also move some lift lemmas to be next to their non-lift counterparts. For now this does not generalize to `ι : Sort v` as this would make a mess with `PLift`. --- Mathlib/SetTheory/Cardinal/Basic.lean | 74 ++++++++++++++++++--------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index 8c3e3617af161..94c0f5b2086c9 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -2167,6 +2167,11 @@ theorem mk_range_eq (f : α → β) (h : Injective f) : #(range f) = #α := mk_congr (Equiv.ofInjective f h).symm #align cardinal.mk_range_eq Cardinal.mk_range_eq +theorem mk_range_eq_lift {α : Type u} {β : Type v} {f : α → β} (hf : Injective f) : + lift.{max u w} #(range f) = lift.{max v w} #α := + lift_mk_eq.{v,u,w}.mpr ⟨(Equiv.ofInjective f hf).symm⟩ +#align cardinal.mk_range_eq_lift Cardinal.mk_range_eq_lift + theorem mk_range_eq_of_injective {α : Type u} {β : Type v} {f : α → β} (hf : Injective f) : lift.{u} #(range f) = lift.{v} #α := lift_mk_eq'.mpr ⟨(Equiv.ofInjective f hf).symm⟩ @@ -2177,21 +2182,38 @@ lemma lift_mk_le_lift_mk_of_injective {α : Type u} {β : Type v} {f : α → β rw [← Cardinal.mk_range_eq_of_injective hf] exact Cardinal.lift_le.2 (Cardinal.mk_set_le _) -theorem mk_range_eq_lift {α : Type u} {β : Type v} {f : α → β} (hf : Injective f) : - lift.{max u w} #(range f) = lift.{max v w} #α := - lift_mk_eq.{v,u,w}.mpr ⟨(Equiv.ofInjective f hf).symm⟩ -#align cardinal.mk_range_eq_lift Cardinal.mk_range_eq_lift +theorem mk_image_eq_of_injOn {α β : Type u} (f : α → β) (s : Set α) (h : InjOn f s) : + #(f '' s) = #s := + mk_congr (Equiv.Set.imageOfInjOn f s h).symm +#align cardinal.mk_image_eq_of_inj_on Cardinal.mk_image_eq_of_injOn + +theorem mk_image_eq_of_injOn_lift {α : Type u} {β : Type v} (f : α → β) (s : Set α) + (h : InjOn f s) : lift.{u} #(f '' s) = lift.{v} #s := + lift_mk_eq.{v, u, 0}.mpr ⟨(Equiv.Set.imageOfInjOn f s h).symm⟩ +#align cardinal.mk_image_eq_of_inj_on_lift Cardinal.mk_image_eq_of_injOn_lift theorem mk_image_eq {α β : Type u} {f : α → β} {s : Set α} (hf : Injective f) : #(f '' s) = #s := - mk_congr (Equiv.Set.image f s hf).symm + mk_image_eq_of_injOn _ _ <| hf.injOn _ #align cardinal.mk_image_eq Cardinal.mk_image_eq +theorem mk_image_eq_lift {α : Type u} {β : Type v} (f : α → β) (s : Set α) (h : Injective f) : + lift.{u} #(f '' s) = lift.{v} #s := + mk_image_eq_of_injOn_lift _ _ <| h.injOn _ +#align cardinal.mk_image_eq_lift Cardinal.mk_image_eq_lift + theorem mk_iUnion_le_sum_mk {α ι : Type u} {f : ι → Set α} : #(⋃ i, f i) ≤ sum fun i => #(f i) := calc #(⋃ i, f i) ≤ #(Σi, f i) := mk_le_of_surjective (Set.sigmaToiUnion_surjective f) _ = sum fun i => #(f i) := mk_sigma _ #align cardinal.mk_Union_le_sum_mk Cardinal.mk_iUnion_le_sum_mk +theorem mk_iUnion_le_sum_mk_lift {α : Type u} {ι : Type v} {f : ι → Set α} : + lift.{v} #(⋃ i, f i) ≤ sum fun i => #(f i) := + calc + lift.{v} #(⋃ i, f i) ≤ #(Σi, f i) := + mk_le_of_surjective <| ULift.up_surjective.comp (Set.sigmaToiUnion_surjective f) + _ = sum fun i => #(f i) := mk_sigma _ + theorem mk_iUnion_eq_sum_mk {α ι : Type u} {f : ι → Set α} (h : ∀ i j, i ≠ j → Disjoint (f i) (f j)) : #(⋃ i, f i) = sum fun i => #(f i) := calc @@ -2199,10 +2221,23 @@ theorem mk_iUnion_eq_sum_mk {α ι : Type u} {f : ι → Set α} _ = sum fun i => #(f i) := mk_sigma _ #align cardinal.mk_Union_eq_sum_mk Cardinal.mk_iUnion_eq_sum_mk +theorem mk_iUnion_eq_sum_mk_lift {α : Type u} {ι : Type v} {f : ι → Set α} + (h : ∀ i j, i ≠ j → Disjoint (f i) (f j)) : + lift.{v} #(⋃ i, f i) = sum fun i => #(f i) := + calc + lift.{v} #(⋃ i, f i) = #(Σi, f i) := + mk_congr <| .trans Equiv.ulift (Set.unionEqSigmaOfDisjoint h) + _ = sum fun i => #(f i) := mk_sigma _ + theorem mk_iUnion_le {α ι : Type u} (f : ι → Set α) : #(⋃ i, f i) ≤ #ι * ⨆ i, #(f i) := mk_iUnion_le_sum_mk.trans (sum_le_iSup _) #align cardinal.mk_Union_le Cardinal.mk_iUnion_le +theorem mk_iUnion_le_lift {α : Type u} {ι : Type v} (f : ι → Set α) : + lift.{v} #(⋃ i, f i) ≤ lift.{u} #ι * ⨆ i, lift.{v} #(f i) := by + refine mk_iUnion_le_sum_mk_lift.trans <| Eq.trans_le ?_ (sum_le_iSup_lift _) + rw [← lift_sum, lift_id'.{_,u}] + theorem mk_sUnion_le {α : Type u} (A : Set (Set α)) : #(⋃₀ A) ≤ #A * ⨆ s : A, #s := by rw [sUnion_eq_iUnion] apply mk_iUnion_le @@ -2214,6 +2249,11 @@ theorem mk_biUnion_le {ι α : Type u} (A : ι → Set α) (s : Set ι) : apply mk_iUnion_le #align cardinal.mk_bUnion_le Cardinal.mk_biUnion_le +theorem mk_biUnion_le_lift {α : Type u} {ι : Type v} (A : ι → Set α) (s : Set ι) : + lift.{v} #(⋃ x ∈ s, A x) ≤ lift.{u} #s * ⨆ x : s, lift.{v} #(A x.1) := by + rw [biUnion_eq_iUnion] + apply mk_iUnion_le_lift + theorem finset_card_lt_aleph0 (s : Finset α) : #(↑s : Set α) < ℵ₀ := lt_aleph0_of_finite _ #align cardinal.finset_card_lt_aleph_0 Cardinal.finset_card_lt_aleph0 @@ -2303,20 +2343,6 @@ theorem mk_union_le_aleph0 {α} {P Q : Set α} : ← countable_union] #align cardinal.mk_union_le_aleph_0 Cardinal.mk_union_le_aleph0 -theorem mk_image_eq_lift {α : Type u} {β : Type v} (f : α → β) (s : Set α) (h : Injective f) : - lift.{u} #(f '' s) = lift.{v} #s := - lift_mk_eq.{v, u, 0}.mpr ⟨(Equiv.Set.image f s h).symm⟩ -#align cardinal.mk_image_eq_lift Cardinal.mk_image_eq_lift - -theorem mk_image_eq_of_injOn_lift {α : Type u} {β : Type v} (f : α → β) (s : Set α) - (h : InjOn f s) : lift.{u} #(f '' s) = lift.{v} #s := - lift_mk_eq.{v, u, 0}.mpr ⟨(Equiv.Set.imageOfInjOn f s h).symm⟩ -#align cardinal.mk_image_eq_of_inj_on_lift Cardinal.mk_image_eq_of_injOn_lift - -theorem mk_image_eq_of_injOn {α β : Type u} (f : α → β) (s : Set α) (h : InjOn f s) : - #(f '' s) = #s := - mk_congr (Equiv.Set.imageOfInjOn f s h).symm -#align cardinal.mk_image_eq_of_inj_on Cardinal.mk_image_eq_of_injOn theorem mk_subtype_of_equiv {α β : Type u} (p : β → Prop) (e : α ≃ β) : #{ a : α // p (e a) } = #{ b : β // p b } := @@ -2353,6 +2379,11 @@ theorem mk_preimage_of_injective_of_subset_range_lift {β : Type v} (f : α → le_antisymm (mk_preimage_of_injective_lift f s h) (mk_preimage_of_subset_range_lift f s h2) #align cardinal.mk_preimage_of_injective_of_subset_range_lift Cardinal.mk_preimage_of_injective_of_subset_range_lift +theorem mk_preimage_of_injective_of_subset_range (f : α → β) (s : Set β) (h : Injective f) + (h2 : s ⊆ range f) : #(f ⁻¹' s) = #s := by + convert mk_preimage_of_injective_of_subset_range_lift.{u, u} f s h h2 using 1 <;> rw [lift_id] +#align cardinal.mk_preimage_of_injective_of_subset_range Cardinal.mk_preimage_of_injective_of_subset_range + theorem mk_preimage_of_injective (f : α → β) (s : Set β) (h : Injective f) : #(f ⁻¹' s) ≤ #s := by rw [← lift_id #(↑(f ⁻¹' s)), ← lift_id #(↑s)] @@ -2365,11 +2396,6 @@ theorem mk_preimage_of_subset_range (f : α → β) (s : Set β) (h : s ⊆ rang exact mk_preimage_of_subset_range_lift f s h #align cardinal.mk_preimage_of_subset_range Cardinal.mk_preimage_of_subset_range -theorem mk_preimage_of_injective_of_subset_range (f : α → β) (s : Set β) (h : Injective f) - (h2 : s ⊆ range f) : #(f ⁻¹' s) = #s := by - convert mk_preimage_of_injective_of_subset_range_lift.{u, u} f s h h2 using 1 <;> rw [lift_id] -#align cardinal.mk_preimage_of_injective_of_subset_range Cardinal.mk_preimage_of_injective_of_subset_range - theorem mk_subset_ge_of_subset_image_lift {α : Type u} {β : Type v} (f : α → β) {s : Set α} {t : Set β} (h : t ⊆ f '' s) : lift.{u} #t ≤ lift.{v} #({ x ∈ s | f x ∈ t } : Set α) := by rw [image_eq_range] at h From 08e759d85fd728a516ad5fe2fbd19740d141a317 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Sat, 23 Dec 2023 07:20:02 +0000 Subject: [PATCH 150/353] feat: `OrderIso` between `minimals` and `maximals` (#9190) Also extracts some lemmas from `minimals_image_of_rel_iff_rel` and remove `_on` from `maximals_image_of_rel_iff_rel_on` to match the former. for [#9088](https://github.com/leanprover-community/mathlib4/pull/9088#discussion_r1434641111) Co-authored-by: Junyan Xu --- Mathlib/Order/Minimal.lean | 114 ++++++++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 22 deletions(-) diff --git a/Mathlib/Order/Minimal.lean b/Mathlib/Order/Minimal.lean index 0f160ecab2bfc..c91147d4d5677 100644 --- a/Mathlib/Order/Minimal.lean +++ b/Mathlib/Order/Minimal.lean @@ -302,28 +302,98 @@ section Image variable {f : α → β} {r : α → α → Prop} {s : β → β → Prop} -theorem minimals_image_of_rel_iff_rel (hf : ∀ ⦃a a'⦄, a ∈ x → a' ∈ x → (r a a' ↔ s (f a) (f a'))) : - minimals s (f '' x) = f '' (minimals r x) := by - ext a - simp only [minimals, mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] - constructor - · rintro ⟨⟨a, ha, rfl⟩ , h⟩ - exact ⟨a, ⟨ha, fun y hy hya ↦ (hf ha hy).mpr (h _ hy ((hf hy ha).mp hya))⟩, rfl⟩ - rintro ⟨a,⟨⟨ha,h⟩,rfl⟩⟩ - exact ⟨⟨_, ha, rfl⟩, fun y hy hya ↦ (hf ha hy).mp (h hy ((hf hy ha).mpr hya))⟩ - -theorem maximals_image_of_rel_iff_rel_on - (hf : ∀ ⦃a a'⦄, a ∈ x → a' ∈ x → (r a a' ↔ s (f a) (f a'))) : - maximals s (f '' x) = f '' (maximals r x) := - minimals_image_of_rel_iff_rel (fun _ _ a_1 a_2 ↦ hf a_2 a_1) - -theorem RelEmbedding.minimals_image_eq (f : r ↪r s) (x : Set α) : - minimals s (f '' x) = f '' (minimals r x) := by - rw [minimals_image_of_rel_iff_rel]; simp [f.map_rel_iff] - -theorem RelEmbedding.maximals_image_eq (f : r ↪r s) (x : Set α) : - maximals s (f '' x) = f '' (maximals r x) := - (f.swap).minimals_image_eq x +section +variable {x : Set α} (hf : ∀ ⦃a a'⦄, a ∈ x → a' ∈ x → (r a a' ↔ s (f a) (f a'))) {a : α} + +theorem map_mem_minimals (ha : a ∈ minimals r x) : f a ∈ minimals s (f '' x) := + ⟨⟨a, ha.1, rfl⟩, by rintro _ ⟨a', h', rfl⟩; rw [← hf ha.1 h', ← hf h' ha.1]; exact ha.2 h'⟩ + +theorem map_mem_maximals (ha : a ∈ maximals r x) : f a ∈ maximals s (f '' x) := + map_mem_minimals (fun _ _ h₁ h₂ ↦ by exact hf h₂ h₁) ha + +theorem map_mem_minimals_iff (ha : a ∈ x) : f a ∈ minimals s (f '' x) ↔ a ∈ minimals r x := + ⟨fun ⟨_, hmin⟩ ↦ ⟨ha, fun a' h' ↦ by + simpa only [hf h' ha, hf ha h'] using hmin ⟨a', h', rfl⟩⟩, map_mem_minimals hf⟩ + +theorem map_mem_maximals_iff (ha : a ∈ x) : f a ∈ maximals s (f '' x) ↔ a ∈ maximals r x := + map_mem_minimals_iff (fun _ _ h₁ h₂ ↦ by exact hf h₂ h₁) ha + +theorem image_minimals_of_rel_iff_rel : f '' minimals r x = minimals s (f '' x) := by + ext b; refine ⟨?_, fun h ↦ ?_⟩ + · rintro ⟨a, ha, rfl⟩; exact map_mem_minimals hf ha + · obtain ⟨a, ha, rfl⟩ := h.1; exact ⟨a, (map_mem_minimals_iff hf ha).mp h, rfl⟩ + +theorem image_maximals_of_rel_iff_rel : f '' maximals r x = maximals s (f '' x) := + image_minimals_of_rel_iff_rel fun _ _ h₁ h₂ ↦ hf h₂ h₁ + +end + +theorem RelEmbedding.image_minimals_eq (f : r ↪r s) (x : Set α) : + f '' minimals r x = minimals s (f '' x) := by + rw [image_minimals_of_rel_iff_rel]; simp [f.map_rel_iff] + +theorem RelEmbedding.image_maximals_eq (f : r ↪r s) (x : Set α) : + f '' maximals r x = maximals s (f '' x) := + f.swap.image_minimals_eq x + +section + +variable [LE α] [LE β] {s : Set α} {t : Set β} + +theorem image_minimals_univ : + Subtype.val '' minimals (· ≤ ·) (univ : Set s) = minimals (· ≤ ·) s := by + rw [image_minimals_of_rel_iff_rel, image_univ, Subtype.range_val]; intros; rfl + +theorem image_maximals_univ : + Subtype.val '' maximals (· ≤ ·) (univ : Set s) = maximals (· ≤ ·) s := + image_minimals_univ (α := αᵒᵈ) + +nonrec theorem OrderIso.map_mem_minimals (f : s ≃o t) {x : α} + (hx : x ∈ minimals (· ≤ ·) s) : (f ⟨x, hx.1⟩).val ∈ minimals (· ≤ ·) t := by + rw [← image_minimals_univ] at hx + obtain ⟨x, h, rfl⟩ := hx + convert map_mem_minimals (f := Subtype.val ∘ f) (fun _ _ _ _ ↦ f.map_rel_iff.symm) h + rw [image_comp, image_univ, f.range_eq, image_univ, Subtype.range_val] + +theorem OrderIso.map_mem_maximals (f : s ≃o t) {x : α} + (hx : x ∈ maximals (· ≤ ·) s) : (f ⟨x, hx.1⟩).val ∈ maximals (· ≤ ·) t := + (show OrderDual.ofDual ⁻¹' s ≃o OrderDual.ofDual ⁻¹' t from f.dual).map_mem_minimals hx + +/-- If two sets are order isomorphic, their minimals are also order isomorphic. -/ +def OrderIso.mapMinimals (f : s ≃o t) : minimals (· ≤ ·) s ≃o minimals (· ≤ ·) t where + toFun x := ⟨f ⟨x, x.2.1⟩, f.map_mem_minimals x.2⟩ + invFun x := ⟨f.symm ⟨x, x.2.1⟩, f.symm.map_mem_minimals x.2⟩ + left_inv x := Subtype.ext (by apply congr_arg Subtype.val <| f.left_inv ⟨x, x.2.1⟩) + right_inv x := Subtype.ext (by apply congr_arg Subtype.val <| f.right_inv ⟨x, x.2.1⟩) + map_rel_iff' {_ _} := f.map_rel_iff + +/-- If two sets are order isomorphic, their maximals are also order isomorphic. -/ +def OrderIso.mapMaximals (f : s ≃o t) : maximals (· ≤ ·) s ≃o maximals (· ≤ ·) t where + toFun x := ⟨f ⟨x, x.2.1⟩, f.map_mem_maximals x.2⟩ + invFun x := ⟨f.symm ⟨x, x.2.1⟩, f.symm.map_mem_maximals x.2⟩ + __ := (show OrderDual.ofDual ⁻¹' s ≃o OrderDual.ofDual ⁻¹' t from f.dual).mapMinimals + -- defeq abuse to fill in the proof fields. + -- If OrderDual ever becomes a structure, just copy the last three lines from OrderIso.mapMinimals + +open OrderDual in +/-- If two sets are antitonically order isomorphic, their minimals are too. -/ +def OrderIso.minimalsIsoMaximals (f : s ≃o tᵒᵈ) : + minimals (· ≤ ·) s ≃o (maximals (· ≤ ·) t)ᵒᵈ where + toFun x := toDual ⟨↑(ofDual (f ⟨x, x.2.1⟩)), (show s ≃o ofDual ⁻¹' t from f).map_mem_minimals x.2⟩ + invFun x := ⟨f.symm (toDual ⟨_, (ofDual x).2.1⟩), + (show ofDual ⁻¹' t ≃o s from f.symm).map_mem_minimals x.2⟩ + __ := (show s ≃o ofDual⁻¹' t from f).mapMinimals + +open OrderDual in +/-- If two sets are antitonically order isomorphic, their minimals are too. -/ +def OrderIso.maximalsIsoMinimals (f : s ≃o tᵒᵈ) : + maximals (· ≤ ·) s ≃o (minimals (· ≤ ·) t)ᵒᵈ where + toFun x := toDual ⟨↑(ofDual (f ⟨x, x.2.1⟩)), (show s ≃o ofDual ⁻¹' t from f).map_mem_maximals x.2⟩ + invFun x := ⟨f.symm (toDual ⟨_, (ofDual x).2.1⟩), + (show ofDual ⁻¹' t ≃o s from f.symm).map_mem_maximals x.2⟩ + __ := (show s ≃o ofDual⁻¹' t from f).mapMaximals + +end theorem inter_minimals_preimage_inter_eq_of_rel_iff_rel_on (hf : ∀ ⦃a a'⦄, a ∈ x → a' ∈ x → (r a a' ↔ s (f a) (f a'))) (y : Set β) : From 66c1128b276e9627e793b992beedb20eb6d7f437 Mon Sep 17 00:00:00 2001 From: Xavier Roblot <46200072+xroblot@users.noreply.github.com> Date: Sat, 23 Dec 2023 07:20:03 +0000 Subject: [PATCH 151/353] feat: If the monoid S contains 0 then the localization at S is trivial (#9207) --- Mathlib/Algebra/Module/LocalizedModule.lean | 6 ++++++ Mathlib/GroupTheory/MonoidLocalization.lean | 8 ++++++++ Mathlib/RingTheory/Localization/Basic.lean | 3 +++ 3 files changed, 17 insertions(+) diff --git a/Mathlib/Algebra/Module/LocalizedModule.lean b/Mathlib/Algebra/Module/LocalizedModule.lean index 79c8a2fca751a..4ab2e590e5ba5 100644 --- a/Mathlib/Algebra/Module/LocalizedModule.lean +++ b/Mathlib/Algebra/Module/LocalizedModule.lean @@ -142,6 +142,12 @@ theorem liftOn₂_mk {α : Type*} (f : M × S → M × S → α) instance : Zero (LocalizedModule S M) := ⟨mk 0 1⟩ +/-- If `S` contains `0` then the localization at `S` is trivial. -/ +theorem subsingleton (h : 0 ∈ S) : Subsingleton (LocalizedModule S M) := by + refine ⟨fun a b ↦ ?_⟩ + induction a,b using LocalizedModule.induction_on₂ + exact mk_eq.mpr ⟨⟨0, h⟩, by simp only [Submonoid.mk_smul, zero_smul]⟩ + @[simp] theorem zero_mk (s : S) : mk (0 : M) s = 0 := mk_eq.mpr ⟨1, by rw [one_smul, smul_zero, smul_zero, one_smul]⟩ diff --git a/Mathlib/GroupTheory/MonoidLocalization.lean b/Mathlib/GroupTheory/MonoidLocalization.lean index bc1d2dc6f6eb0..b6a8a69d017ab 100644 --- a/Mathlib/GroupTheory/MonoidLocalization.lean +++ b/Mathlib/GroupTheory/MonoidLocalization.lean @@ -1794,6 +1794,14 @@ variable {M : Type*} [CommMonoidWithZero M] (S : Submonoid M) (N : Type*) [CommM namespace Submonoid +variable {S N} in +/-- If `S` contains `0` then the localization at `S` is trivial. -/ +theorem LocalizationMap.subsingleton (f : Submonoid.LocalizationMap S N) (h : 0 ∈ S) : + Subsingleton N := by + refine ⟨fun a b ↦ ?_⟩ + rw [← LocalizationMap.mk'_sec f a, ← LocalizationMap.mk'_sec f b, LocalizationMap.eq] + exact ⟨⟨0, h⟩, by simp only [zero_mul]⟩ + /-- 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`. -/ diff --git a/Mathlib/RingTheory/Localization/Basic.lean b/Mathlib/RingTheory/Localization/Basic.lean index 53992ef79332c..e8165150d19db 100644 --- a/Mathlib/RingTheory/Localization/Basic.lean +++ b/Mathlib/RingTheory/Localization/Basic.lean @@ -206,6 +206,9 @@ theorem sec_spec' (z : S) : variable {M} +/-- If `M` contains `0` then the localization at `M` is trivial. -/ +theorem subsingleton (h : 0 ∈ M) : Subsingleton S := (toLocalizationMap M S).subsingleton h + theorem map_right_cancel {x y} {c : M} (h : algebraMap R S (c * x) = algebraMap R S (c * y)) : algebraMap R S x = algebraMap R S y := (toLocalizationMap M S).map_right_cancel h From 539b49a5a004e87f927ba5b98d1e8d2efcbd5472 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 23 Dec 2023 07:20:04 +0000 Subject: [PATCH 152/353] =?UTF-8?q?chore(Filter/NAry):=20use=20`Filter.cop?= =?UTF-8?q?y`=20to=20define=20`map=E2=82=82`=20(#9217)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/Order/Filter/NAry.lean | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/Mathlib/Order/Filter/NAry.lean b/Mathlib/Order/Filter/NAry.lean index 15ed7f6b17526..4fd8d3dbb9b5f 100644 --- a/Mathlib/Order/Filter/NAry.lean +++ b/Mathlib/Order/Filter/NAry.lean @@ -36,19 +36,9 @@ variable {α α' β β' γ γ' δ δ' ε ε' : Type*} {m : α → β → γ} {f /-- The image of a binary function `m : α → β → γ` as a function `Filter α → Filter β → Filter γ`. Mathematically this should be thought of as the image of the corresponding function `α × β → γ`. -/ -def map₂ (m : α → β → γ) (f : Filter α) (g : Filter β) : Filter γ - where - sets := { s | ∃ u v, u ∈ f ∧ v ∈ g ∧ image2 m u v ⊆ s } - univ_sets := ⟨univ, univ, univ_sets _, univ_sets _, subset_univ _⟩ - sets_of_superset hs hst := - Exists₂.imp (fun u v => And.imp_right <| And.imp_right fun h => Subset.trans h hst) hs - inter_sets := by - simp only [exists_prop, Set.mem_setOf_eq, subset_inter_iff] - rintro _ _ ⟨s₁, s₂, hs₁, hs₂, hs⟩ ⟨t₁, t₂, ht₁, ht₂, ht⟩ - exact - ⟨s₁ ∩ t₁, s₂ ∩ t₂, inter_sets f hs₁ ht₁, inter_sets g hs₂ ht₂, - (image2_subset (inter_subset_left _ _) <| inter_subset_left _ _).trans hs, - (image2_subset (inter_subset_right _ _) <| inter_subset_right _ _).trans ht⟩ +def map₂ (m : α → β → γ) (f : Filter α) (g : Filter β) : Filter γ := + ((f ×ˢ g).map (uncurry m)).copy { s | ∃ u v, u ∈ f ∧ v ∈ g ∧ image2 m u v ⊆ s } fun _ ↦ by + simp only [mem_map, mem_prod_iff, image2_subset_iff, prod_subset_iff, exists_and_left]; rfl #align filter.map₂ Filter.map₂ @[simp 900] @@ -62,8 +52,7 @@ theorem image2_mem_map₂ (hs : s ∈ f) (ht : t ∈ g) : image2 m s t ∈ map theorem map_prod_eq_map₂ (m : α → β → γ) (f : Filter α) (g : Filter β) : Filter.map (fun p : α × β => m p.1 p.2) (f ×ˢ g) = map₂ m f g := by - ext s - simp [mem_prod_iff, prod_subset_iff] + rw [map₂, copy_eq]; rfl #align filter.map_prod_eq_map₂ Filter.map_prod_eq_map₂ theorem map_prod_eq_map₂' (m : α × β → γ) (f : Filter α) (g : Filter β) : @@ -159,8 +148,7 @@ theorem map₂_pure : map₂ m (pure a) (pure b) = pure (m a b) := by rw [map₂ theorem map₂_swap (m : α → β → γ) (f : Filter α) (g : Filter β) : map₂ m f g = map₂ (fun a b => m b a) g f := by - ext u - constructor <;> rintro ⟨s, t, hs, ht, hu⟩ <;> refine' ⟨t, s, ht, hs, by rwa [image2_swap]⟩ + rw [← map_prod_eq_map₂, prod_comm, map_map, ← map_prod_eq_map₂]; rfl #align filter.map₂_swap Filter.map₂_swap @[simp] @@ -269,7 +257,7 @@ theorem map_map₂_right_comm {m : α → β' → γ} {n : β → β'} {m' : α (map_map₂_distrib_right fun a b => (h_right_comm a b).symm).symm #align filter.map_map₂_right_comm Filter.map_map₂_right_comm -/-- The other direction does not hold because of the `f`-`f` cross terms on the RHS. -/ +/-- The other direction does not hold because of the `f-f` cross terms on the RHS. -/ theorem map₂_distrib_le_left {m : α → δ → ε} {n : β → γ → δ} {m₁ : α → β → β'} {m₂ : α → γ → γ'} {n' : β' → γ' → ε} (h_distrib : ∀ a b c, m a (n b c) = n' (m₁ a b) (m₂ a c)) : map₂ m f (map₂ n g h) ≤ map₂ n' (map₂ m₁ f g) (map₂ m₂ f h) := by From bb307ab2566ba3c58e63ee327d1139781a6b94ea Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 23 Dec 2023 07:20:05 +0000 Subject: [PATCH 153/353] refactor(Order/Extension): use `OrderHom` (#9232) Redefine `toLinearExtension` as an `OrderHom`. --- Mathlib/Order/Extension/Linear.lean | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Mathlib/Order/Extension/Linear.lean b/Mathlib/Order/Extension/Linear.lean index 4fdb7b279deb9..21a1d6636a702 100644 --- a/Mathlib/Order/Extension/Linear.lean +++ b/Mathlib/Order/Extension/Linear.lean @@ -86,12 +86,10 @@ noncomputable instance {α : Type u} [PartialOrder α] : LinearOrder (LinearExte le_total := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.choose.2.1 decidableLE := Classical.decRel _ -/-- The embedding of `α` into `LinearExtension α` as a relation homomorphism. -/ -def toLinearExtension {α : Type u} [PartialOrder α] : - ((· ≤ ·) : α → α → Prop) →r ((· ≤ ·) : LinearExtension α → LinearExtension α → Prop) - where +/-- The embedding of `α` into `LinearExtension α` as an order homomorphism. -/ +def toLinearExtension {α : Type u} [PartialOrder α] : α →o LinearExtension α where toFun x := x - map_rel' := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.choose_spec _ _ + monotone' := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.choose_spec #align to_linear_extension toLinearExtension instance {α : Type u} [Inhabited α] : Inhabited (LinearExtension α) := From 56db9f133eae41e09911b68c532b474d30e220f2 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sat, 23 Dec 2023 10:02:55 +0000 Subject: [PATCH 154/353] chore: bump to nightly-2023-12-23 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 0a830983958ad..214b445e62d53 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-22 +leanprover/lean4:nightly-2023-12-23 From ea70e843f6449df0777fbfebe222d09a083bd844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sat, 23 Dec 2023 10:52:46 +0000 Subject: [PATCH 155/353] =?UTF-8?q?refactor:=20Deduplicate=20monotonicity?= =?UTF-8?q?=20of=20`=E2=80=A2`=20lemmas=20(#9179)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the duplicates introduced in #8869 by sorting the lemmas in `Algebra.Order.SMul` into three files: * `Algebra.Order.Module.Defs` for the order isomorphism induced by scalar multiplication by a positivity element * `Algebra.Order.Module.Pointwise` for the order properties of scalar multiplication of sets. This file is new. I credit myself for https://github.com/leanprover-community/mathlib/pull/9078 * `Algebra.Order.Module.OrderedSMul`: The material about `OrderedSMul` per se. Inherits the copyright header from `Algebra.Order.SMul`. This file should eventually be deleted. I move each `#align` to the correct file. On top of that, I delete unused redundant `OrderedSMul` instances (they were useful in Lean 3, but not anymore) and `eq_of_smul_eq_smul_of_pos_of_le`/`eq_of_smul_eq_smul_of_neg_of_le` since those lemmas are weird and unused. --- Mathlib.lean | 3 +- Mathlib/Algebra/Order/Algebra.lean | 4 +- Mathlib/Algebra/Order/Module.lean | 21 +- Mathlib/Algebra/Order/Module/Defs.lean | 119 ++++++- Mathlib/Algebra/Order/Module/OrderedSMul.lean | 147 ++++++++ Mathlib/Algebra/Order/Module/Pointwise.lean | 63 ++++ Mathlib/Algebra/Order/SMul.lean | 331 ------------------ Mathlib/Algebra/Star/CHSH.lean | 12 +- Mathlib/Analysis/Convex/Basic.lean | 9 +- Mathlib/Analysis/Convex/Combination.lean | 4 +- Mathlib/Analysis/Convex/Extrema.lean | 2 +- Mathlib/Analysis/Convex/Function.lean | 36 +- Mathlib/Analysis/Convex/Jensen.lean | 4 +- Mathlib/Analysis/Convex/Segment.lean | 2 +- Mathlib/Analysis/Convex/Star.lean | 2 +- Mathlib/Analysis/Normed/Group/Basic.lean | 3 + Mathlib/Analysis/NormedSpace/Pointwise.lean | 2 +- Mathlib/Data/Complex/Module.lean | 2 +- Mathlib/Data/Real/ENNReal.lean | 24 +- Mathlib/Data/Real/Pointwise.lean | 5 +- Mathlib/GroupTheory/GroupAction/Group.lean | 7 + .../LinearAlgebra/AffineSpace/Ordered.lean | 19 +- .../MeasureTheory/Function/LpSeminorm.lean | 4 +- Mathlib/MeasureTheory/Measure/Hausdorff.lean | 4 +- Mathlib/Probability/Martingale/Basic.lean | 2 +- 25 files changed, 413 insertions(+), 418 deletions(-) create mode 100644 Mathlib/Algebra/Order/Module/OrderedSMul.lean create mode 100644 Mathlib/Algebra/Order/Module/Pointwise.lean delete mode 100644 Mathlib/Algebra/Order/SMul.lean diff --git a/Mathlib.lean b/Mathlib.lean index 79ab6330bfa83..88571562b0e33 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -377,6 +377,8 @@ import Mathlib.Algebra.Order.Kleene import Mathlib.Algebra.Order.LatticeGroup import Mathlib.Algebra.Order.Module import Mathlib.Algebra.Order.Module.Defs +import Mathlib.Algebra.Order.Module.OrderedSMul +import Mathlib.Algebra.Order.Module.Pointwise import Mathlib.Algebra.Order.Module.Synonym import Mathlib.Algebra.Order.Monoid.Basic import Mathlib.Algebra.Order.Monoid.Canonical.Defs @@ -411,7 +413,6 @@ import Mathlib.Algebra.Order.Ring.InjSurj import Mathlib.Algebra.Order.Ring.Lemmas import Mathlib.Algebra.Order.Ring.Star import Mathlib.Algebra.Order.Ring.WithTop -import Mathlib.Algebra.Order.SMul import Mathlib.Algebra.Order.Sub.Basic import Mathlib.Algebra.Order.Sub.Canonical import Mathlib.Algebra.Order.Sub.Defs diff --git a/Mathlib/Algebra/Order/Algebra.lean b/Mathlib/Algebra/Order/Algebra.lean index f2cabc5780f6b..b49a531478621 100644 --- a/Mathlib/Algebra/Order/Algebra.lean +++ b/Mathlib/Algebra/Order/Algebra.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ import Mathlib.Algebra.Algebra.Basic -import Mathlib.Algebra.Order.SMul +import Mathlib.Algebra.Order.Module.OrderedSMul #align_import algebra.order.algebra from "leanprover-community/mathlib"@"f5a600f8102c8bfdbd22781968a20a539304c1b4" @@ -45,7 +45,7 @@ theorem algebraMap_monotone : Monotone (algebraMap R A) := fun a b h => by rw [Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, ← sub_nonneg, ← sub_smul] trans (b - a) • (0 : A) · simp - · exact smul_le_smul_of_nonneg zero_le_one (sub_nonneg.mpr h) + · exact smul_le_smul_of_nonneg_left zero_le_one (sub_nonneg.mpr h) #align algebra_map_monotone algebraMap_monotone end OrderedAlgebra diff --git a/Mathlib/Algebra/Order/Module.lean b/Mathlib/Algebra/Order/Module.lean index f8c47a176922a..320cba192aadf 100644 --- a/Mathlib/Algebra/Order/Module.lean +++ b/Mathlib/Algebra/Order/Module.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Frédéric Dupuis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Frédéric Dupuis, Yaël Dillies -/ -import Mathlib.Algebra.Order.SMul +import Mathlib.Algebra.Order.Module.OrderedSMul #align_import algebra.order.module from "leanprover-community/mathlib"@"3ba15165bd6927679be7c22d6091a87337e3cd0c" @@ -40,7 +40,7 @@ where `DistribMulActionWithZero k M`is the conjunction of `DistribMulAction k M` `SMulWithZero k M`.-/ theorem smul_neg_iff_of_pos (hc : 0 < c) : c • a < 0 ↔ a < 0 := by rw [← neg_neg a, smul_neg, neg_neg_iff_pos, neg_neg_iff_pos] - exact smul_pos_iff_of_pos hc + exact smul_pos_iff_of_pos_left hc #align smul_neg_iff_of_pos smul_neg_iff_of_pos end Semiring @@ -51,32 +51,29 @@ variable [OrderedRing k] [OrderedAddCommGroup M] [Module k M] [OrderedSMul k M] theorem smul_lt_smul_of_neg (h : a < b) (hc : c < 0) : c • b < c • a := by rw [← neg_neg c, neg_smul, neg_smul (-c), neg_lt_neg_iff] - exact smul_lt_smul_of_pos h (neg_pos_of_neg hc) + exact smul_lt_smul_of_pos_left h (neg_pos_of_neg hc) #align smul_lt_smul_of_neg smul_lt_smul_of_neg theorem smul_le_smul_of_nonpos (h : a ≤ b) (hc : c ≤ 0) : c • b ≤ c • a := by rw [← neg_neg c, neg_smul, neg_smul (-c), neg_le_neg_iff] - exact smul_le_smul_of_nonneg h (neg_nonneg_of_nonpos hc) + exact smul_le_smul_of_nonneg_left h (neg_nonneg_of_nonpos hc) #align smul_le_smul_of_nonpos smul_le_smul_of_nonpos -theorem eq_of_smul_eq_smul_of_neg_of_le (hab : c • a = c • b) (hc : c < 0) (h : a ≤ b) : a = b := by - rw [← neg_neg c, neg_smul, neg_smul (-c), neg_inj] at hab - exact eq_of_smul_eq_smul_of_pos_of_le hab (neg_pos_of_neg hc) h -#align eq_of_smul_eq_smul_of_neg_of_le eq_of_smul_eq_smul_of_neg_of_le +#noalign eq_of_smul_eq_smul_of_neg_of_le theorem lt_of_smul_lt_smul_of_nonpos (h : c • a < c • b) (hc : c ≤ 0) : b < a := by rw [← neg_neg c, neg_smul, neg_smul (-c), neg_lt_neg_iff] at h - exact lt_of_smul_lt_smul_of_nonneg h (neg_nonneg_of_nonpos hc) + exact lt_of_smul_lt_smul_of_nonneg_left h (neg_nonneg_of_nonpos hc) #align lt_of_smul_lt_smul_of_nonpos lt_of_smul_lt_smul_of_nonpos theorem smul_lt_smul_iff_of_neg (hc : c < 0) : c • a < c • b ↔ b < a := by rw [← neg_neg c, neg_smul, neg_smul (-c), neg_lt_neg_iff] - exact smul_lt_smul_iff_of_pos (neg_pos_of_neg hc) + exact smul_lt_smul_iff_of_pos_left (neg_pos_of_neg hc) #align smul_lt_smul_iff_of_neg smul_lt_smul_iff_of_neg theorem smul_neg_iff_of_neg (hc : c < 0) : c • a < 0 ↔ 0 < a := by rw [← neg_neg c, neg_smul, neg_neg_iff_pos] - exact smul_pos_iff_of_pos (neg_pos_of_neg hc) + exact smul_pos_iff_of_pos_left (neg_pos_of_neg hc) #align smul_neg_iff_of_neg smul_neg_iff_of_neg theorem smul_pos_iff_of_neg (hc : c < 0) : 0 < c • a ↔ a < 0 := by @@ -149,7 +146,7 @@ variable [LinearOrderedField k] [OrderedAddCommGroup M] [Module k M] [OrderedSMu theorem smul_le_smul_iff_of_neg (hc : c < 0) : c • a ≤ c • b ↔ b ≤ a := by rw [← neg_neg c, neg_smul, neg_smul (-c), neg_le_neg_iff] - exact smul_le_smul_iff_of_pos (neg_pos_of_neg hc) + exact smul_le_smul_iff_of_pos_left (neg_pos_of_neg hc) #align smul_le_smul_iff_of_neg smul_le_smul_iff_of_neg theorem inv_smul_le_iff_of_neg (h : c < 0) : c⁻¹ • a ≤ b ↔ c • b ≤ a := by diff --git a/Mathlib/Algebra/Order/Module/Defs.lean b/Mathlib/Algebra/Order/Module/Defs.lean index 540341d9ebf36..dc071e86d3c8d 100644 --- a/Mathlib/Algebra/Order/Module/Defs.lean +++ b/Mathlib/Algebra/Order/Module/Defs.lean @@ -248,15 +248,19 @@ variable [Zero α] lemma monotone_smul_left_of_nonneg [PosSMulMono α β] (ha : 0 ≤ a) : Monotone ((a • ·) : β → β) := PosSMulMono.elim ha +#align monotone_smul_left monotone_smul_left_of_nonneg lemma strictMono_smul_left_of_pos [PosSMulStrictMono α β] (ha : 0 < a) : StrictMono ((a • ·) : β → β) := PosSMulStrictMono.elim ha +#align strict_mono_smul_left strictMono_smul_left_of_pos -lemma smul_le_smul_of_nonneg_left [PosSMulMono α β] (hb : b₁ ≤ b₂) (ha : 0 ≤ a) : a • b₁ ≤ a • b₂ := - monotone_smul_left_of_nonneg ha hb +@[gcongr] lemma smul_le_smul_of_nonneg_left [PosSMulMono α β] (hb : b₁ ≤ b₂) (ha : 0 ≤ a) : + a • b₁ ≤ a • b₂ := monotone_smul_left_of_nonneg ha hb +#align smul_le_smul_of_nonneg smul_le_smul_of_nonneg_left -lemma smul_lt_smul_of_pos_left [PosSMulStrictMono α β] (hb : b₁ < b₂) (ha : 0 < a) : +@[gcongr] lemma smul_lt_smul_of_pos_left [PosSMulStrictMono α β] (hb : b₁ < b₂) (ha : 0 < a) : a • b₁ < a • b₂ := strictMono_smul_left_of_pos ha hb +#align smul_lt_smul_of_pos smul_lt_smul_of_pos_left lemma lt_of_smul_lt_smul_left [PosSMulReflectLT α β] (h : a • b₁ < a • b₂) (ha : 0 ≤ a) : b₁ < b₂ := PosSMulReflectLT.elim ha h @@ -266,16 +270,19 @@ lemma le_of_smul_le_smul_left [PosSMulReflectLE α β] (h : a • b₁ ≤ a • alias lt_of_smul_lt_smul_of_nonneg_left := lt_of_smul_lt_smul_left alias le_of_smul_le_smul_of_pos_left := le_of_smul_le_smul_left +#align lt_of_smul_lt_smul_of_nonneg lt_of_smul_lt_smul_of_nonneg_left @[simp] lemma smul_le_smul_iff_of_pos_left [PosSMulMono α β] [PosSMulReflectLE α β] (ha : 0 < a) : a • b₁ ≤ a • b₂ ↔ b₁ ≤ b₂ := ⟨fun h ↦ le_of_smul_le_smul_left h ha, fun h ↦ smul_le_smul_of_nonneg_left h ha.le⟩ +#align smul_le_smul_iff_of_pos smul_le_smul_iff_of_pos_left @[simp] lemma smul_lt_smul_iff_of_pos_left [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : a • b₁ < a • b₂ ↔ b₁ < b₂ := ⟨fun h ↦ lt_of_smul_lt_smul_left h ha.le, fun hb ↦ smul_lt_smul_of_pos_left hb ha⟩ +#align smul_lt_smul_iff_of_pos smul_lt_smul_iff_of_pos_left end Left @@ -288,10 +295,10 @@ lemma monotone_smul_right_of_nonneg [SMulPosMono α β] (hb : 0 ≤ b) : Monoton lemma strictMono_smul_right_of_pos [SMulPosStrictMono α β] (hb : 0 < b) : StrictMono ((· • b) : α → β) := SMulPosStrictMono.elim hb -lemma smul_le_smul_of_nonneg_right [SMulPosMono α β] (ha : a₁ ≤ a₂) (hb : 0 ≤ b) : +@[gcongr] lemma smul_le_smul_of_nonneg_right [SMulPosMono α β] (ha : a₁ ≤ a₂) (hb : 0 ≤ b) : a₁ • b ≤ a₂ • b := monotone_smul_right_of_nonneg hb ha -lemma smul_lt_smul_of_pos_right [SMulPosStrictMono α β] (ha : a₁ < a₂) (hb : 0 < b) : +@[gcongr] lemma smul_lt_smul_of_pos_right [SMulPosStrictMono α β] (ha : a₁ < a₂) (hb : 0 < b) : a₁ • b < a₂ • b := strictMono_smul_right_of_pos hb ha lemma lt_of_smul_lt_smul_right [SMulPosReflectLT α β] (h : a₁ • b < a₂ • b) (hb : 0 ≤ b) : @@ -381,9 +388,11 @@ lemma posSMulMono_iff_posSMulReflectLT : PosSMulMono α β ↔ PosSMulReflectLT lemma smul_max_of_nonneg [PosSMulMono α β] (ha : 0 ≤ a) (b₁ b₂ : β) : a • max b₁ b₂ = max (a • b₁) (a • b₂) := (monotone_smul_left_of_nonneg ha).map_max +#align smul_max smul_max_of_nonneg lemma smul_min_of_nonneg [PosSMulMono α β] (ha : 0 ≤ a) (b₁ b₂ : β) : a • min b₁ b₂ = min (a • b₁) (a • b₂) := (monotone_smul_left_of_nonneg ha).map_min +#align smul_min smul_min_of_nonneg end Left @@ -440,6 +449,7 @@ variable [Preorder α] [Preorder β] lemma smul_pos [PosSMulStrictMono α β] (ha : 0 < a) (hb : 0 < b) : 0 < a • b := by simpa only [smul_zero] using smul_lt_smul_of_pos_left hb ha +#align smul_pos smul_pos lemma smul_neg_of_pos_of_neg [PosSMulStrictMono α β] (ha : 0 < a) (hb : b < 0) : a • b < 0 := by simpa only [smul_zero] using smul_lt_smul_of_pos_left hb ha @@ -448,12 +458,15 @@ lemma smul_neg_of_pos_of_neg [PosSMulStrictMono α β] (ha : 0 < a) (hb : b < 0) lemma smul_pos_iff_of_pos_left [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : 0 < a • b ↔ 0 < b := by simpa only [smul_zero] using smul_lt_smul_iff_of_pos_left ha (b₁ := 0) (b₂ := b) +#align smul_pos_iff_of_pos smul_pos_iff_of_pos_left lemma smul_nonneg [PosSMulMono α β] (ha : 0 ≤ a) (hb : 0 ≤ b₁) : 0 ≤ a • b₁ := by simpa only [smul_zero] using smul_le_smul_of_nonneg_left hb ha +#align smul_nonneg smul_nonneg lemma smul_nonpos_of_nonneg_of_nonpos [PosSMulMono α β] (ha : 0 ≤ a) (hb : b ≤ 0) : a • b ≤ 0 := by simpa only [smul_zero] using smul_le_smul_of_nonneg_left hb ha +#align smul_nonpos_of_nonneg_of_nonpos smul_nonpos_of_nonneg_of_nonpos lemma pos_of_smul_pos_right [PosSMulReflectLT α β] (h : 0 < a • b) (ha : 0 ≤ a) : 0 < b := lt_of_smul_lt_smul_left (by rwa [smul_zero]) ha @@ -721,22 +734,35 @@ instance PosSMulStrictMono.toSMulPosStrictMono [PosSMulStrictMono α β] : SMulP end OrderedRing -section Field +section GroupWithZero variable [GroupWithZero α] [Preorder α] [Preorder β] [MulAction α β] lemma inv_smul_le_iff_of_pos [PosSMulMono α β] [PosSMulReflectLE α β] (ha : 0 < a) : a⁻¹ • b₁ ≤ b₂ ↔ b₁ ≤ a • b₂ := by rw [← smul_le_smul_iff_of_pos_left ha, smul_inv_smul₀ ha.ne'] +#align inv_smul_le_iff inv_smul_le_iff_of_pos lemma le_inv_smul_iff_of_pos [PosSMulMono α β] [PosSMulReflectLE α β] (ha : 0 < a) : b₁ ≤ a⁻¹ • b₂ ↔ a • b₁ ≤ b₂ := by rw [← smul_le_smul_iff_of_pos_left ha, smul_inv_smul₀ ha.ne'] +#align le_inv_smul_iff le_inv_smul_iff_of_pos lemma inv_smul_lt_iff_of_pos [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : a⁻¹ • b₁ < b₂ ↔ b₁ < a • b₂ := by rw [← smul_lt_smul_iff_of_pos_left ha, smul_inv_smul₀ ha.ne'] +#align inv_smul_lt_iff inv_smul_lt_iff_of_pos lemma lt_inv_smul_iff_of_pos [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : b₁ < a⁻¹ • b₂ ↔ a • b₁ < b₂ := by rw [← smul_lt_smul_iff_of_pos_left ha, smul_inv_smul₀ ha.ne'] +#align lt_inv_smul_iff lt_inv_smul_iff_of_pos -end Field +/-- Right scalar multiplication as an order isomorphism. -/ +@[simps!] +def OrderIso.smulRight [PosSMulMono α β] [PosSMulReflectLE α β] {a : α} (ha : 0 < a) : β ≃o β where + toEquiv := Equiv.smulRight ha.ne' + map_rel_iff' := smul_le_smul_iff_of_pos_left ha +#align order_iso.smul_left OrderIso.smulRight +#align order_iso.smul_left_symm_apply OrderIso.smulRight_symm_apply +#align order_iso.smul_left_apply OrderIso.smulRight_apply + +end GroupWithZero section LinearOrderedSemifield variable [LinearOrderedSemifield α] [AddCommGroup β] [PartialOrder β] @@ -889,3 +915,82 @@ lemma SMulPosReflectLT.lift [SMulPosReflectLT α γ] : SMulPosReflectLT α β wh exact lt_of_smul_lt_smul_right h hb end Lift + +namespace Mathlib.Meta.Positivity +section OrderedSMul +variable [Zero α] [Zero β] [SMulZeroClass α β] [Preorder α] [Preorder β] [PosSMulMono α β] {a : α} + {b : β} + +private theorem smul_nonneg_of_pos_of_nonneg (ha : 0 < a) (hb : 0 ≤ b) : 0 ≤ a • b := + smul_nonneg ha.le hb + +private theorem smul_nonneg_of_nonneg_of_pos (ha : 0 ≤ a) (hb : 0 < b) : 0 ≤ a • b := + smul_nonneg ha hb.le + +end OrderedSMul + +section NoZeroSMulDivisors +variable [Zero α] [Zero β] [SMul α β] [NoZeroSMulDivisors α β] {a : α} {b : β} + +private theorem smul_ne_zero_of_pos_of_ne_zero [Preorder α] (ha : 0 < a) (hb : b ≠ 0) : a • b ≠ 0 := + smul_ne_zero ha.ne' hb + +private theorem smul_ne_zero_of_ne_zero_of_pos [Preorder β] (ha : a ≠ 0) (hb : 0 < b) : a • b ≠ 0 := + smul_ne_zero ha hb.ne' + +end NoZeroSMulDivisors + +open Lean.Meta Qq + +/-- Positivity extension for HSMul, i.e. (_ • _). -/ +@[positivity HSMul.hSMul _ _] +def evalHSMul : PositivityExt where eval {_u α} zα pα (e : Q($α)) := do + let .app (.app (.app (.app (.app (.app + (.const ``HSMul.hSMul [u1, _, _]) (β : Q(Type u1))) _) _) _) + (a : Q($β))) (b : Q($α)) ← whnfR e | throwError "failed to match hSMul" + let zM : Q(Zero $β) ← synthInstanceQ (q(Zero $β)) + let pM : Q(PartialOrder $β) ← synthInstanceQ (q(PartialOrder $β)) + -- Using `q()` here would be impractical, as we would have to manually `synthInstanceQ` all the + -- required typeclasses. Ideally we could tell `q()` to do this automatically. + match ← core zM pM a, ← core zα pα b with + | .positive pa, .positive pb => + pure (.positive (← mkAppM ``smul_pos #[pa, pb])) + | .positive pa, .nonnegative pb => + pure (.nonnegative (← mkAppM ``smul_nonneg_of_pos_of_nonneg #[pa, pb])) + | .nonnegative pa, .positive pb => + pure (.nonnegative (← mkAppM ``smul_nonneg_of_nonneg_of_pos #[pa, pb])) + | .nonnegative pa, .nonnegative pb => + pure (.nonnegative (← mkAppM ``smul_nonneg #[pa, pb])) + | .positive pa, .nonzero pb => + pure (.nonzero (← mkAppM ``smul_ne_zero_of_pos_of_ne_zero #[pa, pb])) + | .nonzero pa, .positive pb => + pure (.nonzero (← mkAppM ``smul_ne_zero_of_ne_zero_of_pos #[pa, pb])) + | .nonzero pa, .nonzero pb => + pure (.nonzero (← mkAppM ``smul_ne_zero #[pa, pb])) + | _, _ => pure .none + +end Mathlib.Meta.Positivity + +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on the 2023/12/23. +-/ + +@[deprecated] alias monotone_smul_left := monotone_smul_left_of_nonneg +@[deprecated] alias strict_mono_smul_left := strictMono_smul_left_of_pos +@[deprecated] alias smul_le_smul_of_nonneg := smul_le_smul_of_nonneg_left +@[deprecated] alias smul_lt_smul_of_pos := smul_lt_smul_of_pos_left +@[deprecated] alias lt_of_smul_lt_smul_of_nonneg := lt_of_smul_lt_smul_of_nonneg_left +@[deprecated] alias smul_le_smul_iff_of_pos := smul_le_smul_iff_of_pos_left +@[deprecated] alias smul_lt_smul_iff_of_pos := smul_lt_smul_iff_of_pos_left +@[deprecated] alias smul_max := smul_max_of_nonneg +@[deprecated] alias smul_min := smul_min_of_nonneg +@[deprecated] alias smul_pos_iff_of_pos := smul_pos_iff_of_pos_left +@[deprecated] alias inv_smul_le_iff := inv_smul_le_iff_of_pos +@[deprecated] alias le_inv_smul_iff := le_inv_smul_iff_of_pos +@[deprecated] alias inv_smul_lt_iff := inv_smul_lt_iff_of_pos +@[deprecated] alias lt_inv_smul_iff := lt_inv_smul_iff_of_pos +@[deprecated] alias OrderIso.smulLeft := OrderIso.smulRight +@[deprecated] alias OrderIso.smulLeft_symm_apply := OrderIso.smulRight_symm_apply +@[deprecated] alias OrderIso.smulLeft_apply := OrderIso.smulRight_apply diff --git a/Mathlib/Algebra/Order/Module/OrderedSMul.lean b/Mathlib/Algebra/Order/Module/OrderedSMul.lean new file mode 100644 index 0000000000000..ee2eace0e4a30 --- /dev/null +++ b/Mathlib/Algebra/Order/Module/OrderedSMul.lean @@ -0,0 +1,147 @@ +/- +Copyright (c) 2020 Frédéric Dupuis. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Dupuis +-/ +import Mathlib.Algebra.Module.Pi +import Mathlib.Algebra.Module.Prod +import Mathlib.Algebra.Order.Module.Defs +import Mathlib.Algebra.Order.Monoid.Prod +import Mathlib.Algebra.Order.Pi +import Mathlib.Data.Set.Pointwise.SMul +import Mathlib.Tactic.GCongr.Core +import Mathlib.Tactic.Positivity + +#align_import algebra.order.smul from "leanprover-community/mathlib"@"3ba15165bd6927679be7c22d6091a87337e3cd0c" + +/-! +# Ordered scalar product + +In this file we define + +* `OrderedSMul R M` : an ordered additive commutative monoid `M` is an `OrderedSMul` + over an `OrderedSemiring` `R` if the scalar product respects the order relation on the + monoid and on the ring. There is a correspondence between this structure and convex cones, + which is proven in `Analysis/Convex/Cone.lean`. + +## Implementation notes +* We choose to define `OrderedSMul` as a `Prop`-valued mixin, so that it can be + used for actions, modules, and algebras + (the axioms for an "ordered algebra" are exactly that the algebra is ordered as a module). +* To get ordered modules and ordered vector spaces, it suffices to replace the + `OrderedAddCommMonoid` and the `OrderedSemiring` as desired. + +## TODO + +This file is now mostly useless. We should try deleting `OrderedSMul` + +## References + +* https://en.wikipedia.org/wiki/Ordered_vector_space + +## Tags + +ordered module, ordered scalar, ordered smul, ordered action, ordered vector space +-/ + +/-- The ordered scalar product property is when an ordered additive commutative monoid +with a partial order has a scalar multiplication which is compatible with the order. +-/ +class OrderedSMul (R M : Type*) [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] : + Prop where + /-- Scalar multiplication by positive elements preserves the order. -/ + protected smul_lt_smul_of_pos : ∀ {a b : M}, ∀ {c : R}, a < b → 0 < c → c • a < c • b + /-- If `c • a < c • b` for some positive `c`, then `a < b`. -/ + protected lt_of_smul_lt_smul_of_pos : ∀ {a b : M}, ∀ {c : R}, c • a < c • b → 0 < c → a < b +#align ordered_smul OrderedSMul + +variable {ι α β γ 𝕜 R M N : Type*} + +section OrderedSMul +variable [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] [OrderedSMul R M] + {s : Set M} {a b : M} {c : R} + +instance OrderedSMul.toPosSMulStrictMono : PosSMulStrictMono R M where + elim _a ha _b₁ _b₂ hb := OrderedSMul.smul_lt_smul_of_pos hb ha + +instance OrderedSMul.toPosSMulReflectLT : PosSMulReflectLT R M := + PosSMulReflectLT.of_pos $ fun _a ha _b₁ _b₂ h ↦ OrderedSMul.lt_of_smul_lt_smul_of_pos h ha + +instance OrderDual.instOrderedSMul [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] + [OrderedSMul R M] : OrderedSMul R Mᵒᵈ where + smul_lt_smul_of_pos := OrderedSMul.smul_lt_smul_of_pos (M := M) + lt_of_smul_lt_smul_of_pos := OrderedSMul.lt_of_smul_lt_smul_of_pos (M := M) + +end OrderedSMul + +/-- To prove that a linear ordered monoid is an ordered module, it suffices to verify only the first +axiom of `OrderedSMul`. -/ +theorem OrderedSMul.mk'' [OrderedSemiring 𝕜] [LinearOrderedAddCommMonoid M] [SMulWithZero 𝕜 M] + (h : ∀ ⦃c : 𝕜⦄, 0 < c → StrictMono fun a : M => c • a) : OrderedSMul 𝕜 M := + { smul_lt_smul_of_pos := fun hab hc => h hc hab + lt_of_smul_lt_smul_of_pos := fun hab hc => (h hc).lt_iff_lt.1 hab } +#align ordered_smul.mk'' OrderedSMul.mk'' + +instance Nat.orderedSMul [LinearOrderedCancelAddCommMonoid M] : OrderedSMul ℕ M := + OrderedSMul.mk'' fun n hn a b hab => by + cases n with + | zero => cases hn + | succ n => + induction n with + | zero => dsimp; rwa [one_nsmul, one_nsmul] + | succ n ih => simp only [succ_nsmul _ n.succ, _root_.add_lt_add hab (ih n.succ_pos)] +#align nat.ordered_smul Nat.orderedSMul + +instance Int.orderedSMul [LinearOrderedAddCommGroup M] : OrderedSMul ℤ M := + OrderedSMul.mk'' fun n hn => by + cases n + · simp only [Int.ofNat_eq_coe, Int.coe_nat_pos, coe_nat_zsmul] at hn ⊢ + exact strictMono_smul_left_of_pos hn + · cases (Int.negSucc_not_pos _).1 hn +#align int.ordered_smul Int.orderedSMul + +section LinearOrderedSemiring +variable [LinearOrderedSemiring R] [LinearOrderedAddCommMonoid M] [SMulWithZero R M] + [OrderedSMul R M] {a : R} + +-- TODO: `LinearOrderedField M → OrderedSMul ℚ M` +instance LinearOrderedSemiring.toOrderedSMul : OrderedSMul R R := + OrderedSMul.mk'' fun _ => strictMono_mul_left_of_pos +#align linear_ordered_semiring.to_ordered_smul LinearOrderedSemiring.toOrderedSMul + +end LinearOrderedSemiring + +section LinearOrderedSemifield + +variable [LinearOrderedSemifield 𝕜] [OrderedAddCommMonoid M] [OrderedAddCommMonoid N] + [MulActionWithZero 𝕜 M] [MulActionWithZero 𝕜 N] + +/-- To prove that a vector space over a linear ordered field is ordered, it suffices to verify only +the first axiom of `OrderedSMul`. -/ +theorem OrderedSMul.mk' (h : ∀ ⦃a b : M⦄ ⦃c : 𝕜⦄, a < b → 0 < c → c • a ≤ c • b) : + OrderedSMul 𝕜 M := by + have hlt' : ∀ (a b : M) (c : 𝕜), a < b → 0 < c → c • a < c • b := by + refine' fun a b c hab hc => (h hab hc).lt_of_ne _ + rw [Ne.def, hc.ne'.isUnit.smul_left_cancel] + exact hab.ne + refine' { smul_lt_smul_of_pos := fun {a b c} => hlt' a b c..} + intro a b c hab hc + obtain ⟨c, rfl⟩ := hc.ne'.isUnit + rw [← inv_smul_smul c a, ← inv_smul_smul c b] + refine' hlt' _ _ _ hab (pos_of_mul_pos_right _ hc.le) + simp only [c.mul_inv, zero_lt_one] +#align ordered_smul.mk' OrderedSMul.mk' + +instance [OrderedSMul 𝕜 M] [OrderedSMul 𝕜 N] : OrderedSMul 𝕜 (M × N) := + OrderedSMul.mk' fun _ _ _ h hc => + ⟨smul_le_smul_of_nonneg_left h.1.1 hc.le, smul_le_smul_of_nonneg_left h.1.2 hc.le⟩ + +instance Pi.orderedSMul {M : ι → Type*} [∀ i, OrderedAddCommMonoid (M i)] + [∀ i, MulActionWithZero 𝕜 (M i)] [∀ i, OrderedSMul 𝕜 (M i)] : OrderedSMul 𝕜 (∀ i, M i) := + OrderedSMul.mk' fun _ _ _ h hc i => smul_le_smul_of_nonneg_left (h.le i) hc.le +#align pi.ordered_smul Pi.orderedSMul + +#noalign pi.ordered_smul' +#noalign pi.ordered_smul'' + +end LinearOrderedSemifield diff --git a/Mathlib/Algebra/Order/Module/Pointwise.lean b/Mathlib/Algebra/Order/Module/Pointwise.lean new file mode 100644 index 0000000000000..df2102762d8cb --- /dev/null +++ b/Mathlib/Algebra/Order/Module/Pointwise.lean @@ -0,0 +1,63 @@ +/- +Copyright (c) 2023 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +import Mathlib.Data.Set.Pointwise.SMul +import Mathlib.Algebra.Order.Module.Defs + +/-! +# Bounds on scalar multiplication of set + +This file proves order properties of pointwise operations of sets. +-/ + +open scoped Pointwise + +variable {α β : Type*} + +section PosSMulMono +variable [SMul α β] [Preorder α] [Preorder β] [Zero α] [PosSMulMono α β] {a : α} {s : Set β} + +lemma smul_lowerBounds_subset_lowerBounds_smul_of_nonneg (ha : 0 ≤ a) : + a • lowerBounds s ⊆ lowerBounds (a • s) := + (monotone_smul_left_of_nonneg ha).image_lowerBounds_subset_lowerBounds_image +#align smul_lower_bounds_subset_lower_bounds_smul smul_lowerBounds_subset_lowerBounds_smul_of_nonneg + +lemma smul_upperBounds_subset_upperBounds_smul_of_nonneg (ha : 0 ≤ a) : + a • upperBounds s ⊆ upperBounds (a • s) := + (monotone_smul_left_of_nonneg ha).image_upperBounds_subset_upperBounds_image +#align smul_upper_bounds_subset_upper_bounds_smul smul_upperBounds_subset_upperBounds_smul_of_nonneg + +lemma BddBelow.smul_of_nonneg (hs : BddBelow s) (ha : 0 ≤ a) : BddBelow (a • s) := + (monotone_smul_left_of_nonneg ha).map_bddBelow hs +#align bdd_below.smul_of_nonneg BddBelow.smul_of_nonneg + +lemma BddAbove.smul_of_nonneg (hs : BddAbove s) (ha : 0 ≤ a) : BddAbove (a • s) := + (monotone_smul_left_of_nonneg ha).map_bddAbove hs +#align bdd_above.smul_of_nonneg BddAbove.smul_of_nonneg + +end PosSMulMono + + +section +variable [Preorder α] [Preorder β] [GroupWithZero α] [Zero β] [MulActionWithZero α β] + [PosSMulMono α β] [PosSMulReflectLE α β] {s : Set β} {a : α} + +@[simp] lemma lowerBounds_smul_of_pos (ha : 0 < a) : lowerBounds (a • s) = a • lowerBounds s := + (OrderIso.smulRight ha).lowerBounds_image +#align lower_bounds_smul_of_pos lowerBounds_smul_of_pos + +@[simp] lemma upperBounds_smul_of_pos (ha : 0 < a) : upperBounds (a • s) = a • upperBounds s := + (OrderIso.smulRight ha).upperBounds_image +#align upper_bounds_smul_of_pos upperBounds_smul_of_pos + +@[simp] lemma bddBelow_smul_iff_of_pos (ha : 0 < a) : BddBelow (a • s) ↔ BddBelow s := + (OrderIso.smulRight ha).bddBelow_image +#align bdd_below_smul_iff_of_pos bddBelow_smul_iff_of_pos + +@[simp] lemma bddAbove_smul_iff_of_pos (ha : 0 < a) : BddAbove (a • s) ↔ BddAbove s := + (OrderIso.smulRight ha).bddAbove_image +#align bdd_above_smul_iff_of_pos bddAbove_smul_iff_of_pos + +end diff --git a/Mathlib/Algebra/Order/SMul.lean b/Mathlib/Algebra/Order/SMul.lean deleted file mode 100644 index 3938b6e825f39..0000000000000 --- a/Mathlib/Algebra/Order/SMul.lean +++ /dev/null @@ -1,331 +0,0 @@ -/- -Copyright (c) 2020 Frédéric Dupuis. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Frédéric Dupuis --/ -import Mathlib.Algebra.Module.Pi -import Mathlib.Algebra.Module.Prod -import Mathlib.Algebra.Order.Module.Defs -import Mathlib.Algebra.Order.Monoid.Prod -import Mathlib.Algebra.Order.Pi -import Mathlib.Data.Set.Pointwise.SMul -import Mathlib.Tactic.GCongr.Core -import Mathlib.Tactic.Positivity - -#align_import algebra.order.smul from "leanprover-community/mathlib"@"3ba15165bd6927679be7c22d6091a87337e3cd0c" - -/-! -# Ordered scalar product - -In this file we define - -* `OrderedSMul R M` : an ordered additive commutative monoid `M` is an `OrderedSMul` - over an `OrderedSemiring` `R` if the scalar product respects the order relation on the - monoid and on the ring. There is a correspondence between this structure and convex cones, - which is proven in `Analysis/Convex/Cone.lean`. - -## Implementation notes -* We choose to define `OrderedSMul` as a `Prop`-valued mixin, so that it can be - used for actions, modules, and algebras - (the axioms for an "ordered algebra" are exactly that the algebra is ordered as a module). -* To get ordered modules and ordered vector spaces, it suffices to replace the - `OrderedAddCommMonoid` and the `OrderedSemiring` as desired. - -## TODO - -Delete the lemmas that have been generalised by `PosSMulMono` and friends. - -## References - -* https://en.wikipedia.org/wiki/Ordered_vector_space - -## Tags - -ordered module, ordered scalar, ordered smul, ordered action, ordered vector space --/ - - -open Pointwise - -/-- The ordered scalar product property is when an ordered additive commutative monoid -with a partial order has a scalar multiplication which is compatible with the order. --/ -class OrderedSMul (R M : Type*) [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] : - Prop where - /-- Scalar multiplication by positive elements preserves the order. -/ - protected smul_lt_smul_of_pos : ∀ {a b : M}, ∀ {c : R}, a < b → 0 < c → c • a < c • b - /-- If `c • a < c • b` for some positive `c`, then `a < b`. -/ - protected lt_of_smul_lt_smul_of_pos : ∀ {a b : M}, ∀ {c : R}, c • a < c • b → 0 < c → a < b -#align ordered_smul OrderedSMul - -variable {ι α β γ 𝕜 R M N : Type*} - -instance OrderDual.instOrderedSMul [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] - [OrderedSMul R M] : OrderedSMul R Mᵒᵈ where - smul_lt_smul_of_pos := OrderedSMul.smul_lt_smul_of_pos (M := M) - lt_of_smul_lt_smul_of_pos := OrderedSMul.lt_of_smul_lt_smul_of_pos (M := M) - -section OrderedSMul - -variable [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] [OrderedSMul R M] - {s : Set M} {a b : M} {c : R} - -instance OrderedSMul.toPosSMulStrictMono : PosSMulStrictMono R M where - elim _a ha _b₁ _b₂ hb := OrderedSMul.smul_lt_smul_of_pos hb ha - -instance OrderedSMul.toPosSMulReflectLT : PosSMulReflectLT R M := - PosSMulReflectLT.of_pos $ fun _a ha _b₁ _b₂ h ↦ OrderedSMul.lt_of_smul_lt_smul_of_pos h ha - -@[gcongr] theorem smul_lt_smul_of_pos : a < b → 0 < c → c • a < c • b := smul_lt_smul_of_pos_left -#align smul_lt_smul_of_pos smul_lt_smul_of_pos - --- TODO: Remove `smul_le_smul_of_nonneg` completely -@[gcongr] theorem smul_le_smul_of_nonneg (h₁ : a ≤ b) (h₂ : 0 ≤ c) : c • a ≤ c • b := - smul_le_smul_of_nonneg_left h₁ h₂ -#align smul_le_smul_of_nonneg smul_le_smul_of_nonneg - -#align smul_nonneg smul_nonneg -#align smul_nonpos_of_nonneg_of_nonpos smul_nonpos_of_nonneg_of_nonpos - -theorem eq_of_smul_eq_smul_of_pos_of_le (h₁ : c • a = c • b) (hc : 0 < c) (hle : a ≤ b) : a = b := - hle.lt_or_eq.resolve_left fun hlt => (smul_lt_smul_of_pos hlt hc).ne h₁ -#align eq_of_smul_eq_smul_of_pos_of_le eq_of_smul_eq_smul_of_pos_of_le - -theorem lt_of_smul_lt_smul_of_nonneg (h : c • a < c • b) (hc : 0 ≤ c) : a < b := - lt_of_smul_lt_smul_of_nonneg_left h hc -#align lt_of_smul_lt_smul_of_nonneg lt_of_smul_lt_smul_of_nonneg - -theorem smul_lt_smul_iff_of_pos (hc : 0 < c) : c • a < c • b ↔ a < b := - smul_lt_smul_iff_of_pos_left hc -#align smul_lt_smul_iff_of_pos smul_lt_smul_iff_of_pos - -theorem smul_pos_iff_of_pos (hc : 0 < c) : 0 < c • a ↔ 0 < a := smul_pos_iff_of_pos_left hc -#align smul_pos_iff_of_pos smul_pos_iff_of_pos - -#align smul_pos smul_pos - -theorem monotone_smul_left (hc : 0 ≤ c) : Monotone (SMul.smul c : M → M) := - monotone_smul_left_of_nonneg hc -#align monotone_smul_left monotone_smul_left - -theorem strictMono_smul_left (hc : 0 < c) : StrictMono (SMul.smul c : M → M) := - strictMono_smul_left_of_pos hc -#align strict_mono_smul_left strictMono_smul_left - -theorem smul_lowerBounds_subset_lowerBounds_smul (hc : 0 ≤ c) : - c • lowerBounds s ⊆ lowerBounds (c • s) := - (monotone_smul_left hc).image_lowerBounds_subset_lowerBounds_image -#align smul_lower_bounds_subset_lower_bounds_smul smul_lowerBounds_subset_lowerBounds_smul - -theorem smul_upperBounds_subset_upperBounds_smul (hc : 0 ≤ c) : - c • upperBounds s ⊆ upperBounds (c • s) := - (monotone_smul_left hc).image_upperBounds_subset_upperBounds_image -#align smul_upper_bounds_subset_upper_bounds_smul smul_upperBounds_subset_upperBounds_smul - -theorem BddBelow.smul_of_nonneg (hs : BddBelow s) (hc : 0 ≤ c) : BddBelow (c • s) := - (monotone_smul_left hc).map_bddBelow hs -#align bdd_below.smul_of_nonneg BddBelow.smul_of_nonneg - -theorem BddAbove.smul_of_nonneg (hs : BddAbove s) (hc : 0 ≤ c) : BddAbove (c • s) := - (monotone_smul_left hc).map_bddAbove hs -#align bdd_above.smul_of_nonneg BddAbove.smul_of_nonneg - -end OrderedSMul - -/-- To prove that a linear ordered monoid is an ordered module, it suffices to verify only the first -axiom of `OrderedSMul`. -/ -theorem OrderedSMul.mk'' [OrderedSemiring 𝕜] [LinearOrderedAddCommMonoid M] [SMulWithZero 𝕜 M] - (h : ∀ ⦃c : 𝕜⦄, 0 < c → StrictMono fun a : M => c • a) : OrderedSMul 𝕜 M := - { smul_lt_smul_of_pos := fun hab hc => h hc hab - lt_of_smul_lt_smul_of_pos := fun hab hc => (h hc).lt_iff_lt.1 hab } -#align ordered_smul.mk'' OrderedSMul.mk'' - -instance Nat.orderedSMul [LinearOrderedCancelAddCommMonoid M] : OrderedSMul ℕ M := - OrderedSMul.mk'' fun n hn a b hab => by - cases n with - | zero => cases hn - | succ n => - induction n with - | zero => dsimp; rwa [one_nsmul, one_nsmul] - | succ n ih => simp only [succ_nsmul _ n.succ, _root_.add_lt_add hab (ih n.succ_pos)] -#align nat.ordered_smul Nat.orderedSMul - -instance Int.orderedSMul [LinearOrderedAddCommGroup M] : OrderedSMul ℤ M := - OrderedSMul.mk'' fun n hn => by - cases n - · simp only [Int.ofNat_eq_coe, Int.coe_nat_pos, coe_nat_zsmul] at hn ⊢ - exact strictMono_smul_left hn - · cases (Int.negSucc_not_pos _).1 hn -#align int.ordered_smul Int.orderedSMul - -section LinearOrderedSemiring -variable [LinearOrderedSemiring R] [LinearOrderedAddCommMonoid M] [SMulWithZero R M] - [OrderedSMul R M] {a : R} - --- TODO: `LinearOrderedField M → OrderedSMul ℚ M` -instance LinearOrderedSemiring.toOrderedSMul : OrderedSMul R R := - OrderedSMul.mk'' fun _ => strictMono_mul_left_of_pos -#align linear_ordered_semiring.to_ordered_smul LinearOrderedSemiring.toOrderedSMul - -theorem smul_max (ha : 0 ≤ a) (b₁ b₂ : M) : a • max b₁ b₂ = max (a • b₁) (a • b₂) := - smul_max_of_nonneg ha _ _ -#align smul_max smul_max - -theorem smul_min (ha : 0 ≤ a) (b₁ b₂ : M) : a • min b₁ b₂ = min (a • b₁) (a • b₂) := - smul_min_of_nonneg ha _ _ -#align smul_min smul_min - -end LinearOrderedSemiring - -section LinearOrderedSemifield - -variable [LinearOrderedSemifield 𝕜] [OrderedAddCommMonoid M] [OrderedAddCommMonoid N] - [MulActionWithZero 𝕜 M] [MulActionWithZero 𝕜 N] - -/-- To prove that a vector space over a linear ordered field is ordered, it suffices to verify only -the first axiom of `OrderedSMul`. -/ -theorem OrderedSMul.mk' (h : ∀ ⦃a b : M⦄ ⦃c : 𝕜⦄, a < b → 0 < c → c • a ≤ c • b) : - OrderedSMul 𝕜 M := by - have hlt' : ∀ (a b : M) (c : 𝕜), a < b → 0 < c → c • a < c • b := by - refine' fun a b c hab hc => (h hab hc).lt_of_ne _ - rw [Ne.def, hc.ne'.isUnit.smul_left_cancel] - exact hab.ne - refine' { smul_lt_smul_of_pos := fun {a b c} => hlt' a b c..} - intro a b c hab hc - obtain ⟨c, rfl⟩ := hc.ne'.isUnit - rw [← inv_smul_smul c a, ← inv_smul_smul c b] - refine' hlt' _ _ _ hab (pos_of_mul_pos_right _ hc.le) - simp only [c.mul_inv, zero_lt_one] -#align ordered_smul.mk' OrderedSMul.mk' - -instance [OrderedSMul 𝕜 M] [OrderedSMul 𝕜 N] : OrderedSMul 𝕜 (M × N) := - OrderedSMul.mk' fun _ _ _ h hc => - ⟨smul_le_smul_of_nonneg h.1.1 hc.le, smul_le_smul_of_nonneg h.1.2 hc.le⟩ - -instance Pi.orderedSMul {M : ι → Type*} [∀ i, OrderedAddCommMonoid (M i)] - [∀ i, MulActionWithZero 𝕜 (M i)] [∀ i, OrderedSMul 𝕜 (M i)] : OrderedSMul 𝕜 (∀ i, M i) := - OrderedSMul.mk' fun _ _ _ h hc i => smul_le_smul_of_nonneg (h.le i) hc.le -#align pi.ordered_smul Pi.orderedSMul - -/- Sometimes Lean fails to apply the dependent version to non-dependent functions, so we define -another instance. -/ -instance Pi.orderedSMul' [OrderedSMul 𝕜 M] : OrderedSMul 𝕜 (ι → M) := - Pi.orderedSMul -#align pi.ordered_smul' Pi.orderedSMul' - --- Sometimes Lean fails to unify the module with the scalars, so we define another instance. -instance Pi.orderedSMul'' : OrderedSMul 𝕜 (ι → 𝕜) := - @Pi.orderedSMul' ι 𝕜 𝕜 _ _ _ _ -#align pi.ordered_smul'' Pi.orderedSMul'' - -variable [OrderedSMul 𝕜 M] {s : Set M} {a b : M} {c : 𝕜} - -theorem smul_le_smul_iff_of_pos (hc : 0 < c) : c • a ≤ c • b ↔ a ≤ b := - smul_le_smul_iff_of_pos_left hc -#align smul_le_smul_iff_of_pos smul_le_smul_iff_of_pos - -theorem inv_smul_le_iff (h : 0 < c) : c⁻¹ • a ≤ b ↔ a ≤ c • b := inv_smul_le_iff_of_pos h -#align inv_smul_le_iff inv_smul_le_iff - -theorem inv_smul_lt_iff (h : 0 < c) : c⁻¹ • a < b ↔ a < c • b := inv_smul_lt_iff_of_pos h -#align inv_smul_lt_iff inv_smul_lt_iff - -theorem le_inv_smul_iff (h : 0 < c) : a ≤ c⁻¹ • b ↔ c • a ≤ b := le_inv_smul_iff_of_pos h -#align le_inv_smul_iff le_inv_smul_iff - -theorem lt_inv_smul_iff (h : 0 < c) : a < c⁻¹ • b ↔ c • a < b := lt_inv_smul_iff_of_pos h -#align lt_inv_smul_iff lt_inv_smul_iff - -variable (M) - -/-- Left scalar multiplication as an order isomorphism. -/ -@[simps] -def OrderIso.smulLeft (hc : 0 < c) : M ≃o M where - toFun b := c • b - invFun b := c⁻¹ • b - left_inv := inv_smul_smul₀ hc.ne' - right_inv := smul_inv_smul₀ hc.ne' - map_rel_iff' := smul_le_smul_iff_of_pos hc -#align order_iso.smul_left OrderIso.smulLeft -#align order_iso.smul_left_symm_apply OrderIso.smulLeft_symm_apply -#align order_iso.smul_left_apply OrderIso.smulLeft_apply - -variable {M} - -@[simp] -theorem lowerBounds_smul_of_pos (hc : 0 < c) : lowerBounds (c • s) = c • lowerBounds s := - (OrderIso.smulLeft _ hc).lowerBounds_image -#align lower_bounds_smul_of_pos lowerBounds_smul_of_pos - -@[simp] -theorem upperBounds_smul_of_pos (hc : 0 < c) : upperBounds (c • s) = c • upperBounds s := - (OrderIso.smulLeft _ hc).upperBounds_image -#align upper_bounds_smul_of_pos upperBounds_smul_of_pos - -@[simp] -theorem bddBelow_smul_iff_of_pos (hc : 0 < c) : BddBelow (c • s) ↔ BddBelow s := - (OrderIso.smulLeft _ hc).bddBelow_image -#align bdd_below_smul_iff_of_pos bddBelow_smul_iff_of_pos - -@[simp] -theorem bddAbove_smul_iff_of_pos (hc : 0 < c) : BddAbove (c • s) ↔ BddAbove s := - (OrderIso.smulLeft _ hc).bddAbove_image -#align bdd_above_smul_iff_of_pos bddAbove_smul_iff_of_pos - -end LinearOrderedSemifield - -namespace Mathlib.Meta.Positivity - -section OrderedSMul - -variable [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] [OrderedSMul R M] {a : R} - {b : M} - -private theorem smul_nonneg_of_pos_of_nonneg (ha : 0 < a) (hb : 0 ≤ b) : 0 ≤ a • b := - smul_nonneg ha.le hb - -private theorem smul_nonneg_of_nonneg_of_pos (ha : 0 ≤ a) (hb : 0 < b) : 0 ≤ a • b := - smul_nonneg ha hb.le - -end OrderedSMul - -section NoZeroSMulDivisors - -variable [Zero R] [Zero M] [SMul R M] [NoZeroSMulDivisors R M] {a : R} {b : M} - -private theorem smul_ne_zero_of_pos_of_ne_zero [Preorder R] (ha : 0 < a) (hb : b ≠ 0) : a • b ≠ 0 := - smul_ne_zero ha.ne' hb - -private theorem smul_ne_zero_of_ne_zero_of_pos [Preorder M] (ha : a ≠ 0) (hb : 0 < b) : a • b ≠ 0 := - smul_ne_zero ha hb.ne' - -end NoZeroSMulDivisors - -open Lean.Meta Qq - -/-- Positivity extension for HSMul, i.e. (_ • _). -/ -@[positivity HSMul.hSMul _ _] -def evalHSMul : PositivityExt where eval {_u α} zα pα (e : Q($α)) := do - let .app (.app (.app (.app (.app (.app - (.const ``HSMul.hSMul [u1, _, _]) (M : Q(Type u1))) _) _) _) - (a : Q($M))) (b : Q($α)) ← whnfR e | throwError "failed to match hSMul" - let zM : Q(Zero $M) ← synthInstanceQ (q(Zero $M)) - let pM : Q(PartialOrder $M) ← synthInstanceQ (q(PartialOrder $M)) - -- Using `q()` here would be impractical, as we would have to manually `synthInstanceQ` all the - -- required typeclasses. Ideally we could tell `q()` to do this automatically. - match ← core zM pM a, ← core zα pα b with - | .positive pa, .positive pb => - pure (.positive (← mkAppM ``smul_pos #[pa, pb])) - | .positive pa, .nonnegative pb => - pure (.nonnegative (← mkAppM ``smul_nonneg_of_pos_of_nonneg #[pa, pb])) - | .nonnegative pa, .positive pb => - pure (.nonnegative (← mkAppM ``smul_nonneg_of_nonneg_of_pos #[pa, pb])) - | .nonnegative pa, .nonnegative pb => - pure (.nonnegative (← mkAppM ``smul_nonneg #[pa, pb])) - | .positive pa, .nonzero pb => - pure (.nonzero (← mkAppM ``smul_ne_zero_of_pos_of_ne_zero #[pa, pb])) - | .nonzero pa, .positive pb => - pure (.nonzero (← mkAppM ``smul_ne_zero_of_ne_zero_of_pos #[pa, pb])) - | .nonzero pa, .nonzero pb => - pure (.nonzero (← mkAppM ``smul_ne_zero #[pa, pb])) - | _, _ => pure .none diff --git a/Mathlib/Algebra/Star/CHSH.lean b/Mathlib/Algebra/Star/CHSH.lean index 582abd53aae97..c8785d203f579 100644 --- a/Mathlib/Algebra/Star/CHSH.lean +++ b/Mathlib/Algebra/Star/CHSH.lean @@ -132,14 +132,8 @@ theorem CHSH_inequality_of_comm [OrderedCommRing R] [StarOrderedRing R] [Algebra dsimp simp only [star_add, star_sub, star_mul, star_ofNat, star_one, T.A₀_sa, T.A₁_sa, T.B₀_sa, T.B₁_sa, mul_comm B₀, mul_comm B₁] - rw [idem'] - conv_rhs => - arg 2 - arg 1 - rw [← sa] - convert smul_le_smul_of_nonneg (R := ℝ) (star_mul_self_nonneg P) _ - · simp - · norm_num + simpa only [← idem', sa] + using smul_nonneg (by norm_num : (0 : ℝ) ≤ 1 / 4) (star_mul_self_nonneg P) apply le_of_sub_nonneg simpa only [sub_add_eq_sub_sub, ← sub_add] using i₁ set_option linter.uppercaseLean3 false in @@ -238,7 +232,7 @@ theorem tsirelson_inequality [OrderedRing R] [StarOrderedRing R] [Algebra ℝ R] congr rw [← Q_sa] convert (star_mul_self_nonneg Q) - convert smul_le_smul_of_nonneg (add_nonneg P2_nonneg Q2_nonneg) + convert smul_le_smul_of_nonneg_left (add_nonneg P2_nonneg Q2_nonneg) (le_of_lt (show 0 < √2⁻¹ by norm_num)) -- `norm_num` can't directly show `0 ≤ √2⁻¹` simp diff --git a/Mathlib/Analysis/Convex/Basic.lean b/Mathlib/Analysis/Convex/Basic.lean index 151a79a5799d9..198231f37e2ff 100644 --- a/Mathlib/Analysis/Convex/Basic.lean +++ b/Mathlib/Analysis/Convex/Basic.lean @@ -279,7 +279,7 @@ variable [OrderedAddCommMonoid β] [Module 𝕜 β] [OrderedSMul 𝕜 β] theorem convex_Iic (r : β) : Convex 𝕜 (Iic r) := fun x hx y hy a b ha hb hab => calc a • x + b • y ≤ a • r + b • r := - add_le_add (smul_le_smul_of_nonneg hx ha) (smul_le_smul_of_nonneg hy hb) + add_le_add (smul_le_smul_of_nonneg_left hx ha) (smul_le_smul_of_nonneg_left hy hb) _ = r := Convex.combo_self hab _ #align convex_Iic convex_Iic @@ -317,8 +317,8 @@ theorem convex_Iio (r : β) : Convex 𝕜 (Iio r) := by rwa [zero_smul, zero_add, hab, one_smul] rw [mem_Iio] at hx hy calc - a • x + b • y < a • r + b • r := - add_lt_add_of_lt_of_le (smul_lt_smul_of_pos hx ha') (smul_le_smul_of_nonneg hy.le hb) + a • x + b • y < a • r + b • r := add_lt_add_of_lt_of_le + (smul_lt_smul_of_pos_left hx ha') (smul_le_smul_of_nonneg_left hy.le hb) _ = r := Convex.combo_self hab _ #align convex_Iio convex_Iio @@ -561,7 +561,8 @@ theorem Convex_subadditive_le [SMul 𝕜 E] {f : E → 𝕜} (hf1 : ∀ x y, f ( rintro x hx y hy z ⟨a, b, ha, hb, hs, rfl⟩ calc _ ≤ a • (f x) + b • (f y) := le_trans (hf1 _ _) (add_le_add (hf2 x ha) (hf2 y hb)) - _ ≤ a • B + b • B := add_le_add (smul_le_smul_of_nonneg hx ha) (smul_le_smul_of_nonneg hy hb) + _ ≤ a • B + b • B := + add_le_add (smul_le_smul_of_nonneg_left hx ha) (smul_le_smul_of_nonneg_left hy hb) _ ≤ B := by rw [← add_smul, hs, one_smul] end LinearOrderedRing diff --git a/Mathlib/Analysis/Convex/Combination.lean b/Mathlib/Analysis/Convex/Combination.lean index 0c4700816b842..cd227292d44ba 100644 --- a/Mathlib/Analysis/Convex/Combination.lean +++ b/Mathlib/Analysis/Convex/Combination.lean @@ -143,8 +143,8 @@ namespace Finset theorem centerMass_le_sup {s : Finset ι} {f : ι → α} {w : ι → R} (hw₀ : ∀ i ∈ s, 0 ≤ w i) (hw₁ : 0 < ∑ i in s, w i) : s.centerMass w f ≤ s.sup' (nonempty_of_ne_empty <| by rintro rfl; simp at hw₁) f := by - rw [centerMass, inv_smul_le_iff hw₁, sum_smul] - exact sum_le_sum fun i hi => smul_le_smul_of_nonneg (le_sup' _ hi) <| hw₀ i hi + rw [centerMass, inv_smul_le_iff_of_pos hw₁, sum_smul] + exact sum_le_sum fun i hi => smul_le_smul_of_nonneg_left (le_sup' _ hi) <| hw₀ i hi #align finset.center_mass_le_sup Finset.centerMass_le_sup theorem inf_le_centerMass {s : Finset ι} {f : ι → α} {w : ι → R} (hw₀ : ∀ i ∈ s, 0 ≤ w i) diff --git a/Mathlib/Analysis/Convex/Extrema.lean b/Mathlib/Analysis/Convex/Extrema.lean index b426dad541c05..d6b03a91f2e0d 100644 --- a/Mathlib/Analysis/Convex/Extrema.lean +++ b/Mathlib/Analysis/Convex/Extrema.lean @@ -40,7 +40,7 @@ theorem IsMinOn.of_isLocalMinOn_of_convexOn_Icc {f : ℝ → β} {a b : ℝ} (a_ 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 - exact (smul_le_smul_iff_of_pos yc₀).1 (le_of_add_le_add_left this) + exact (smul_le_smul_iff_of_pos_left 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 diff --git a/Mathlib/Analysis/Convex/Function.lean b/Mathlib/Analysis/Convex/Function.lean index 3e7143150dfe0..13deb1cbd7105 100644 --- a/Mathlib/Analysis/Convex/Function.lean +++ b/Mathlib/Analysis/Convex/Function.lean @@ -547,8 +547,8 @@ theorem ConvexOn.convex_lt (hf : ConvexOn 𝕜 s f) (r : β) : Convex 𝕜 ({ x calc f (a • x + b • y) ≤ a • f x + b • f y := hf.2 hx.1 hy.1 ha.le hb.le hab _ < a • r + b • r := - (add_lt_add_of_lt_of_le (smul_lt_smul_of_pos hx.2 ha) - (smul_le_smul_of_nonneg hy.2.le hb.le)) + (add_lt_add_of_lt_of_le (smul_lt_smul_of_pos_left hx.2 ha) + (smul_le_smul_of_nonneg_left hy.2.le hb.le)) _ = r := Convex.combo_self hab _⟩ #align convex_on.convex_lt ConvexOn.convex_lt @@ -563,8 +563,8 @@ theorem ConvexOn.openSegment_subset_strict_epigraph (hf : ConvexOn 𝕜 s f) (p refine' ⟨hf.1 hp.1 hq.1 ha.le hb.le hab, _⟩ calc f (a • p.1 + b • q.1) ≤ a • f p.1 + b • f q.1 := hf.2 hp.1 hq.1 ha.le hb.le hab - _ < a • p.2 + b • q.2 := - add_lt_add_of_lt_of_le (smul_lt_smul_of_pos hp.2 ha) (smul_le_smul_of_nonneg hq.2 hb.le) + _ < a • p.2 + b • q.2 := add_lt_add_of_lt_of_le + (smul_lt_smul_of_pos_left hp.2 ha) (smul_le_smul_of_nonneg_left hq.2 hb.le) #align convex_on.open_segment_subset_strict_epigraph ConvexOn.openSegment_subset_strict_epigraph theorem ConcaveOn.openSegment_subset_strict_hypograph (hf : ConcaveOn 𝕜 s f) (p q : E × β) @@ -709,13 +709,12 @@ variable [SMul 𝕜 E] [Module 𝕜 β] [OrderedSMul 𝕜 β] {s : Set E} {f g : theorem ConvexOn.le_left_of_right_le' (hf : ConvexOn 𝕜 s f) {x y : E} (hx : x ∈ s) (hy : y ∈ s) {a b : 𝕜} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1) (hfy : f y ≤ f (a • x + b • y)) : f (a • x + b • y) ≤ f x := - le_of_not_lt fun h => - lt_irrefl (f (a • x + b • y)) <| - calc - f (a • x + b • y) ≤ a • f x + b • f y := hf.2 hx hy ha.le hb hab - _ < a • f (a • x + b • y) + b • f (a • x + b • y) := - (add_lt_add_of_lt_of_le (smul_lt_smul_of_pos h ha) (smul_le_smul_of_nonneg hfy hb)) - _ = f (a • x + b • y) := Convex.combo_self hab _ + le_of_not_lt fun h ↦ lt_irrefl (f (a • x + b • y)) <| + calc + f (a • x + b • y) ≤ a • f x + b • f y := hf.2 hx hy ha.le hb hab + _ < a • f (a • x + b • y) + b • f (a • x + b • y) := add_lt_add_of_lt_of_le + (smul_lt_smul_of_pos_left h ha) (smul_le_smul_of_nonneg_left hfy hb) + _ = f (a • x + b • y) := Convex.combo_self hab _ #align convex_on.le_left_of_right_le' ConvexOn.le_left_of_right_le' theorem ConcaveOn.left_le_of_le_right' (hf : ConcaveOn 𝕜 s f) {x y : E} (hx : x ∈ s) (hy : y ∈ s) @@ -770,13 +769,12 @@ the writing, we decided the resulting lemmas wouldn't be useful. Feel free to re theorem ConvexOn.lt_left_of_right_lt' (hf : ConvexOn 𝕜 s f) {x y : E} (hx : x ∈ s) (hy : y ∈ s) {a b : 𝕜} (ha : 0 < a) (hb : 0 < b) (hab : a + b = 1) (hfy : f y < f (a • x + b • y)) : f (a • x + b • y) < f x := - not_le.1 fun h => - lt_irrefl (f (a • x + b • y)) <| - calc - f (a • x + b • y) ≤ a • f x + b • f y := hf.2 hx hy ha.le hb.le hab - _ < a • f (a • x + b • y) + b • f (a • x + b • y) := - (add_lt_add_of_le_of_lt (smul_le_smul_of_nonneg h ha.le) (smul_lt_smul_of_pos hfy hb)) - _ = f (a • x + b • y) := Convex.combo_self hab _ + not_le.1 fun h ↦ lt_irrefl (f (a • x + b • y)) <| + calc + f (a • x + b • y) ≤ a • f x + b • f y := hf.2 hx hy ha.le hb.le hab + _ < a • f (a • x + b • y) + b • f (a • x + b • y) := add_lt_add_of_le_of_lt + (smul_le_smul_of_nonneg_left h ha.le) (smul_lt_smul_of_pos_left hfy hb) + _ = f (a • x + b • y) := Convex.combo_self hab _ #align convex_on.lt_left_of_right_lt' ConvexOn.lt_left_of_right_lt' theorem ConcaveOn.left_lt_of_lt_right' (hf : ConcaveOn 𝕜 s f) {x y : E} (hx : x ∈ s) (hy : y ∈ s) @@ -980,7 +978,7 @@ theorem ConvexOn.smul {c : 𝕜} (hc : 0 ≤ c) (hf : ConvexOn 𝕜 s f) : Conve ⟨hf.1, fun x hx y hy a b ha hb hab => calc c • f (a • x + b • y) ≤ c • (a • f x + b • f y) := - smul_le_smul_of_nonneg (hf.2 hx hy ha hb hab) hc + smul_le_smul_of_nonneg_left (hf.2 hx hy ha hb hab) hc _ = a • c • f x + b • c • f y := by rw [smul_add, smul_comm c, smul_comm c]⟩ #align convex_on.smul ConvexOn.smul diff --git a/Mathlib/Analysis/Convex/Jensen.lean b/Mathlib/Analysis/Convex/Jensen.lean index bbfd6cae48d3c..db52abaf227ef 100644 --- a/Mathlib/Analysis/Convex/Jensen.lean +++ b/Mathlib/Analysis/Convex/Jensen.lean @@ -274,10 +274,10 @@ theorem ConvexOn.exists_ge_of_centerMass (h : ConvexOn 𝕜 s f) (hw₀ : ∀ i obtain ⟨i, hi, hfi⟩ : ∃ i ∈ t.filter fun i => w i ≠ 0, w i • f y ≤ w i • (f ∘ p) i rotate_left · rw [mem_filter] at hi - exact ⟨i, hi.1, (smul_le_smul_iff_of_pos <| (hw₀ i hi.1).lt_of_ne hi.2.symm).1 hfi⟩ + exact ⟨i, hi.1, (smul_le_smul_iff_of_pos_left <| (hw₀ i hi.1).lt_of_ne hi.2.symm).1 hfi⟩ have hw' : (0 : 𝕜) < ∑ i in filter (fun i => w i ≠ 0) t, w i := by rwa [sum_filter_ne_zero] refine' exists_le_of_sum_le (nonempty_of_sum_ne_zero hw'.ne') _ - rw [← sum_smul, ← smul_le_smul_iff_of_pos (inv_pos.2 hw'), inv_smul_smul₀ hw'.ne', ← + rw [← sum_smul, ← smul_le_smul_iff_of_pos_left (inv_pos.2 hw'), inv_smul_smul₀ hw'.ne', ← centerMass, centerMass_filter_ne_zero] exact h.map_centerMass_le hw₀ hw₁ hp #align convex_on.exists_ge_of_center_mass ConvexOn.exists_ge_of_centerMass diff --git a/Mathlib/Analysis/Convex/Segment.lean b/Mathlib/Analysis/Convex/Segment.lean index 860810871d8dc..dd6473474783d 100644 --- a/Mathlib/Analysis/Convex/Segment.lean +++ b/Mathlib/Analysis/Convex/Segment.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Alexander Bentkamp, Yury Kudryashov, Yaël Dillies -/ import Mathlib.Algebra.Order.Invertible -import Mathlib.Algebra.Order.SMul +import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.LinearAlgebra.AffineSpace.Midpoint import Mathlib.LinearAlgebra.Ray import Mathlib.Tactic.GCongr diff --git a/Mathlib/Analysis/Convex/Star.lean b/Mathlib/Analysis/Convex/Star.lean index bf6fb39a588e4..7c49f4010d7ef 100644 --- a/Mathlib/Analysis/Convex/Star.lean +++ b/Mathlib/Analysis/Convex/Star.lean @@ -385,7 +385,7 @@ lemma starConvex_compl_Iic (h : x < y) : StarConvex 𝕜 y (Iic x)ᶜ := by refine (starConvex_iff_forall_pos <| by simp [h.not_le]).mpr fun z hz a b ha hb hab ↦ ?_ rw [mem_compl_iff, mem_Iic] at hz ⊢ contrapose! hz - refine (lt_of_smul_lt_smul_of_nonneg ?_ hb.le).le + refine (lt_of_smul_lt_smul_of_nonneg_left ?_ hb.le).le calc b • z ≤ (a + b) • x - a • y := by rwa [le_sub_iff_add_le', hab, one_smul] _ < b • x := by diff --git a/Mathlib/Analysis/Normed/Group/Basic.lean b/Mathlib/Analysis/Normed/Group/Basic.lean index 89b92050366a9..3b0235511df7b 100644 --- a/Mathlib/Analysis/Normed/Group/Basic.lean +++ b/Mathlib/Analysis/Normed/Group/Basic.lean @@ -2079,6 +2079,9 @@ theorem nnnorm_ne_zero_iff' : ‖a‖₊ ≠ 0 ↔ a ≠ 1 := #align nnnorm_ne_zero_iff' nnnorm_ne_zero_iff' #align nnnorm_ne_zero_iff nnnorm_ne_zero_iff +@[to_additive (attr := simp) nnnorm_pos] +lemma nnnorm_pos' : 0 < ‖a‖₊ ↔ a ≠ 1 := pos_iff_ne_zero.trans nnnorm_ne_zero_iff' + @[to_additive] theorem tendsto_norm_div_self_punctured_nhds (a : E) : Tendsto (fun x => ‖x / a‖) (𝓝[≠] a) (𝓝[>] 0) := diff --git a/Mathlib/Analysis/NormedSpace/Pointwise.lean b/Mathlib/Analysis/NormedSpace/Pointwise.lean index 8f1d03ef1e0f4..93e2ec0918e0b 100644 --- a/Mathlib/Analysis/NormedSpace/Pointwise.lean +++ b/Mathlib/Analysis/NormedSpace/Pointwise.lean @@ -49,7 +49,7 @@ theorem ediam_smul₀ (c : 𝕜) (s : Set E) : EMetric.diam (c • s) = ‖c‖ simp [zero_smul_set hs, ← Set.singleton_zero] · have := (lipschitzWith_smul c⁻¹).ediam_image_le (c • s) rwa [← smul_eq_mul, ← ENNReal.smul_def, Set.image_smul, inv_smul_smul₀ hc s, nnnorm_inv, - ENNReal.le_inv_smul_iff (nnnorm_ne_zero_iff.mpr hc)] at this + le_inv_smul_iff_of_pos (nnnorm_pos.2 hc)] at this #align ediam_smul₀ ediam_smul₀ theorem diam_smul₀ (c : 𝕜) (x : Set E) : diam (c • x) = ‖c‖ * diam x := by diff --git a/Mathlib/Data/Complex/Module.lean b/Mathlib/Data/Complex/Module.lean index 6995bb51fd02a..7d850874f1faa 100644 --- a/Mathlib/Data/Complex/Module.lean +++ b/Mathlib/Data/Complex/Module.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Alexander Bentkamp, Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alexander Bentkamp, Sébastien Gouëzel, Eric Wieser -/ -import Mathlib.Algebra.Order.SMul +import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.Data.Complex.Cardinality import Mathlib.Data.Fin.VecNotation import Mathlib.FieldTheory.Tower diff --git a/Mathlib/Data/Real/ENNReal.lean b/Mathlib/Data/Real/ENNReal.lean index bee679539acb4..c716ea8f42e42 100644 --- a/Mathlib/Data/Real/ENNReal.lean +++ b/Mathlib/Data/Real/ENNReal.lean @@ -1717,15 +1717,14 @@ theorem mul_le_iff_le_inv {a b r : ℝ≥0∞} (hr₀ : r ≠ 0) (hr₁ : r ≠ one_mul] #align ennreal.mul_le_iff_le_inv ENNReal.mul_le_iff_le_inv -/-- A variant of `le_inv_smul_iff` that holds for `ENNReal`. -/ -protected theorem le_inv_smul_iff {a b : ℝ≥0∞} {r : ℝ≥0} (hr₀ : r ≠ 0) : a ≤ r⁻¹ • b ↔ r • a ≤ b := - by simpa [hr₀, ENNReal.smul_def] using (mul_le_iff_le_inv (coe_ne_zero.mpr hr₀) coe_ne_top).symm -#align ennreal.le_inv_smul_iff ENNReal.le_inv_smul_iff +instance : PosSMulStrictMono ℝ≥0 ℝ≥0∞ where + elim _r hr _a _b hab := ENNReal.mul_lt_mul_left' (coe_pos.2 hr).ne' coe_ne_top hab -/-- A variant of `inv_smul_le_iff` that holds for `ENNReal`. -/ -protected theorem inv_smul_le_iff {a b : ℝ≥0∞} {r : ℝ≥0} (hr₀ : r ≠ 0) : r⁻¹ • a ≤ b ↔ a ≤ r • b := - by simpa only [inv_inv] using (ENNReal.le_inv_smul_iff (inv_ne_zero hr₀)).symm -#align ennreal.inv_smul_le_iff ENNReal.inv_smul_le_iff +instance : SMulPosMono ℝ≥0 ℝ≥0∞ where + elim _r _ _a _b hab := mul_le_mul_right' (coe_le_coe.2 hab) _ + +#align ennreal.le_inv_smul_iff_of_pos le_inv_smul_iff_of_pos +#align ennreal.inv_smul_le_iff_of_pos inv_smul_le_iff_of_pos theorem le_of_forall_nnreal_lt {x y : ℝ≥0∞} (h : ∀ r : ℝ≥0, ↑r < x → ↑r ≤ y) : x ≤ y := by refine' le_of_forall_ge_of_dense fun r hr => _ @@ -2703,3 +2702,12 @@ def evalENNRealOfNNReal : PositivityExt where eval {_ _} _zα _pα e := do | _ => pure .none end Mathlib.Meta.Positivity + +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on the 2023/12/23. +-/ + +@[deprecated] protected alias ENNReal.le_inv_smul_iff_of_pos := le_inv_smul_iff_of_pos +@[deprecated] protected alias ENNReal.inv_smul_le_iff_of_pos := inv_smul_le_iff_of_pos diff --git a/Mathlib/Data/Real/Pointwise.lean b/Mathlib/Data/Real/Pointwise.lean index 082915967c323..a7e358f1267e2 100644 --- a/Mathlib/Data/Real/Pointwise.lean +++ b/Mathlib/Data/Real/Pointwise.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Eric Wieser -/ import Mathlib.Algebra.Order.Module +import Mathlib.Algebra.Order.Module.Pointwise import Mathlib.Data.Real.Archimedean #align_import data.real.pointwise from "leanprover-community/mathlib"@"dde670c9a3f503647fd5bfdf1037bad526d3397a" @@ -40,7 +41,7 @@ theorem Real.sInf_smul_of_nonneg (ha : 0 ≤ a) (s : Set ℝ) : sInf (a • s) = · rw [zero_smul_set hs, zero_smul] exact csInf_singleton 0 by_cases h : BddBelow s - · exact ((OrderIso.smulLeft ℝ ha').map_csInf' hs h).symm + · exact ((OrderIso.smulRight ha').map_csInf' hs h).symm · rw [Real.sInf_of_not_bddBelow (mt (bddBelow_smul_iff_of_pos ha').1 h), Real.sInf_of_not_bddBelow h, smul_zero] #align real.Inf_smul_of_nonneg Real.sInf_smul_of_nonneg @@ -56,7 +57,7 @@ theorem Real.sSup_smul_of_nonneg (ha : 0 ≤ a) (s : Set ℝ) : sSup (a • s) = · rw [zero_smul_set hs, zero_smul] exact csSup_singleton 0 by_cases h : BddAbove s - · exact ((OrderIso.smulLeft ℝ ha').map_csSup' hs h).symm + · exact ((OrderIso.smulRight ha').map_csSup' hs h).symm · rw [Real.sSup_of_not_bddAbove (mt (bddAbove_smul_iff_of_pos ha').1 h), Real.sSup_of_not_bddAbove h, smul_zero] #align real.Sup_smul_of_nonneg Real.sSup_smul_of_nonneg diff --git a/Mathlib/GroupTheory/GroupAction/Group.lean b/Mathlib/GroupTheory/GroupAction/Group.lean index dbc6d27aacad1..4a04482a7b66c 100644 --- a/Mathlib/GroupTheory/GroupAction/Group.lean +++ b/Mathlib/GroupTheory/GroupAction/Group.lean @@ -218,6 +218,13 @@ theorem Commute.smul_left_iff₀ [Mul β] [SMulCommClass α β β] [IsScalarTowe Commute.smul_left_iff (Units.mk0 c hc) #align commute.smul_left_iff₀ Commute.smul_left_iff₀ +/-- Right scalar multiplication as an order isomorphism. -/ +@[simps] def Equiv.smulRight (ha : a ≠ 0) : β ≃ β where + toFun b := a • b + invFun b := a⁻¹ • b + left_inv := inv_smul_smul₀ ha + right_inv := smul_inv_smul₀ ha + protected theorem MulAction.bijective₀ (ha : a ≠ 0) : Function.Bijective (a • · : β → β) := MulAction.bijective <| Units.mk0 a ha #align mul_action.bijective₀ MulAction.bijective₀ diff --git a/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean b/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean index e8f81a32e0819..d74b0b15cb839 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean @@ -50,22 +50,22 @@ variable {a a' b b' : E} {r r' : k} theorem lineMap_mono_left (ha : a ≤ a') (hr : r ≤ 1) : lineMap a b r ≤ lineMap a' b r := by simp only [lineMap_apply_module] - exact add_le_add_right (smul_le_smul_of_nonneg ha (sub_nonneg.2 hr)) _ + exact add_le_add_right (smul_le_smul_of_nonneg_left ha (sub_nonneg.2 hr)) _ #align line_map_mono_left lineMap_mono_left theorem lineMap_strict_mono_left (ha : a < a') (hr : r < 1) : lineMap a b r < lineMap a' b r := by simp only [lineMap_apply_module] - exact add_lt_add_right (smul_lt_smul_of_pos ha (sub_pos.2 hr)) _ + exact add_lt_add_right (smul_lt_smul_of_pos_left ha (sub_pos.2 hr)) _ #align line_map_strict_mono_left lineMap_strict_mono_left theorem lineMap_mono_right (hb : b ≤ b') (hr : 0 ≤ r) : lineMap a b r ≤ lineMap a b' r := by simp only [lineMap_apply_module] - exact add_le_add_left (smul_le_smul_of_nonneg hb hr) _ + exact add_le_add_left (smul_le_smul_of_nonneg_left hb hr) _ #align line_map_mono_right lineMap_mono_right theorem lineMap_strict_mono_right (hb : b < b') (hr : 0 < r) : lineMap a b r < lineMap a b' r := by simp only [lineMap_apply_module] - exact add_lt_add_left (smul_lt_smul_of_pos hb hr) _ + exact add_lt_add_left (smul_lt_smul_of_pos_left hb hr) _ #align line_map_strict_mono_right lineMap_strict_mono_right theorem lineMap_mono_endpoints (ha : a ≤ a') (hb : b ≤ b') (h₀ : 0 ≤ r) (h₁ : r ≤ 1) : @@ -82,7 +82,7 @@ theorem lineMap_strict_mono_endpoints (ha : a < a') (hb : b < b') (h₀ : 0 ≤ theorem lineMap_lt_lineMap_iff_of_lt (h : r < r') : lineMap a b r < lineMap a b r' ↔ a < b := by simp only [lineMap_apply_module] rw [← lt_sub_iff_add_lt, add_sub_assoc, ← sub_lt_iff_lt_add', ← sub_smul, ← sub_smul, - sub_sub_sub_cancel_left, smul_lt_smul_iff_of_pos (sub_pos.2 h)] + sub_sub_sub_cancel_left, smul_lt_smul_iff_of_pos_left (sub_pos.2 h)] #align line_map_lt_line_map_iff_of_lt lineMap_lt_lineMap_iff_of_lt theorem left_lt_lineMap_iff_lt (h : 0 < r) : a < lineMap a b r ↔ a < b := @@ -127,7 +127,7 @@ variable {a b : E} {r r' : k} theorem lineMap_le_lineMap_iff_of_lt (h : r < r') : lineMap a b r ≤ lineMap a b r' ↔ a ≤ b := by simp only [lineMap_apply_module] rw [← le_sub_iff_add_le, add_sub_assoc, ← sub_le_iff_le_add', ← sub_smul, ← sub_smul, - sub_sub_sub_cancel_left, smul_le_smul_iff_of_pos (sub_pos.2 h)] + sub_sub_sub_cancel_left, smul_le_smul_iff_of_pos_left (sub_pos.2 h)] #align line_map_le_line_map_iff_of_lt lineMap_le_lineMap_iff_of_lt theorem left_le_lineMap_iff_le (h : 0 < r) : a ≤ lineMap a b r ↔ a ≤ b := @@ -209,7 +209,7 @@ theorem map_le_lineMap_iff_slope_le_slope_left (h : 0 < r * (b - a)) : rw [lineMap_apply, lineMap_apply, slope, slope, vsub_eq_sub, vsub_eq_sub, vsub_eq_sub, vadd_eq_add, vadd_eq_add, smul_eq_mul, add_sub_cancel, smul_sub, smul_sub, smul_sub, sub_le_iff_le_add, mul_inv_rev, mul_smul, mul_smul, ← smul_sub, ← smul_sub, ← smul_add, - smul_smul, ← mul_inv_rev, inv_smul_le_iff h, smul_smul, + smul_smul, ← mul_inv_rev, inv_smul_le_iff_of_pos h, smul_smul, mul_inv_cancel_right₀ (right_ne_zero_of_mul h.ne'), smul_add, smul_inv_smul₀ (left_ne_zero_of_mul h.ne')] #align map_le_line_map_iff_slope_le_slope_left map_le_lineMap_iff_slope_le_slope_left @@ -243,8 +243,9 @@ theorem map_le_lineMap_iff_slope_le_slope_right (h : 0 < (1 - r) * (b - a)) : rw [← lineMap_apply_one_sub, ← lineMap_apply_one_sub _ _ r] revert h; generalize 1 - r = r'; clear! r; intro h simp_rw [lineMap_apply, slope, vsub_eq_sub, vadd_eq_add, smul_eq_mul] - rw [sub_add_eq_sub_sub_swap, sub_self, zero_sub, neg_mul_eq_mul_neg, neg_sub, le_inv_smul_iff h, - smul_smul, mul_inv_cancel_right₀, le_sub_comm, ← neg_sub (f b), smul_neg, neg_add_eq_sub] + rw [sub_add_eq_sub_sub_swap, sub_self, zero_sub, neg_mul_eq_mul_neg, neg_sub, + le_inv_smul_iff_of_pos h, smul_smul, mul_inv_cancel_right₀, le_sub_comm, ← neg_sub (f b), + smul_neg, neg_add_eq_sub] · exact right_ne_zero_of_mul h.ne' #align map_le_line_map_iff_slope_le_slope_right map_le_lineMap_iff_slope_le_slope_right diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm.lean b/Mathlib/MeasureTheory/Function/LpSeminorm.lean index 6a9a54643d89d..19bccb61537fc 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm.lean @@ -1574,7 +1574,7 @@ theorem snorm'_const_smul {f : α → F} (c : 𝕜) (hq_pos : 0 < q) : · simp [snorm', hq_pos] refine' le_antisymm (snorm'_const_smul_le _ _ hq_pos) _ have : snorm' _ q μ ≤ _ := snorm'_const_smul_le c⁻¹ (c • f) hq_pos - rwa [inv_smul_smul₀ hc, nnnorm_inv, ENNReal.le_inv_smul_iff (nnnorm_ne_zero_iff.mpr hc)] at this + rwa [inv_smul_smul₀ hc, nnnorm_inv, le_inv_smul_iff_of_pos (nnnorm_pos.2 hc)] at this #align measure_theory.snorm'_const_smul MeasureTheory.snorm'_const_smul theorem snormEssSup_const_smul (c : 𝕜) (f : α → F) : @@ -1588,7 +1588,7 @@ theorem snorm_const_smul (c : 𝕜) (f : α → F) : · simp refine' le_antisymm (snorm_const_smul_le _ _) _ have : snorm _ p μ ≤ _ := snorm_const_smul_le c⁻¹ (c • f) - rwa [inv_smul_smul₀ hc, nnnorm_inv, ENNReal.le_inv_smul_iff (nnnorm_ne_zero_iff.mpr hc)] at this + rwa [inv_smul_smul₀ hc, nnnorm_inv, le_inv_smul_iff_of_pos (nnnorm_pos.2 hc)] at this #align measure_theory.snorm_const_smul MeasureTheory.snorm_const_smul end NormedSpace diff --git a/Mathlib/MeasureTheory/Measure/Hausdorff.lean b/Mathlib/MeasureTheory/Measure/Hausdorff.lean index a01a11bffec8f..1ae18fd636374 100644 --- a/Mathlib/MeasureTheory/Measure/Hausdorff.lean +++ b/Mathlib/MeasureTheory/Measure/Hausdorff.lean @@ -805,12 +805,12 @@ theorem MeasureTheory.Measure.hausdorffMeasure_smul₀ {𝕜 E : Type*} [NormedA {r : 𝕜} (hr : r ≠ 0) (s : Set E) : μH[d] (r • s) = NNReal.rpow ‖r‖₊ d • μH[d] s := by suffices ∀ {r : 𝕜}, r ≠ 0 → ∀ s : Set E, μH[d] (r • s) ≤ NNReal.rpow ‖r‖₊ d • μH[d] s by refine' le_antisymm (this hr s) _ - rw [← ENNReal.le_inv_smul_iff] + rw [← le_inv_smul_iff_of_pos] dsimp rw [← NNReal.inv_rpow, ← nnnorm_inv] · refine' Eq.trans_le _ (this (inv_ne_zero hr) (r • s)) rw [inv_smul_smul₀ hr] - · simp [hr] + · simp [pos_iff_ne_zero, hr] intro r _ s simp only [NNReal.rpow_eq_pow, ENNReal.smul_def, ← ENNReal.coe_rpow_of_nonneg _ hd, smul_eq_mul] exact (lipschitzWith_smul (β := E) r).hausdorffMeasure_image_le hd s diff --git a/Mathlib/Probability/Martingale/Basic.lean b/Mathlib/Probability/Martingale/Basic.lean index b44486e038f30..852d9e1dba036 100644 --- a/Mathlib/Probability/Martingale/Basic.lean +++ b/Mathlib/Probability/Martingale/Basic.lean @@ -353,7 +353,7 @@ theorem smul_nonneg {f : ι → Ω → F} {c : ℝ} (hc : 0 ≤ c) (hf : Superma refine' (condexp_smul c (f j)).le.trans _ filter_upwards [hf.2.1 i j hij] with _ hle simp_rw [Pi.smul_apply] - exact smul_le_smul_of_nonneg hle hc + exact smul_le_smul_of_nonneg_left hle hc #align measure_theory.supermartingale.smul_nonneg MeasureTheory.Supermartingale.smul_nonneg theorem smul_nonpos {f : ι → Ω → F} {c : ℝ} (hc : c ≤ 0) (hf : Supermartingale f ℱ μ) : From 4a335977d31a2993f09064e9267fa169cdbf20ca Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 23 Dec 2023 18:42:55 +0000 Subject: [PATCH 156/353] chore(Data/Set/Pointwise): golf (#9205) --- Mathlib/Data/Set/Pointwise/Basic.lean | 35 ++++++++++----------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/Mathlib/Data/Set/Pointwise/Basic.lean b/Mathlib/Data/Set/Pointwise/Basic.lean index 207ccd9f79f16..02eba85d9c0c0 100644 --- a/Mathlib/Data/Set/Pointwise/Basic.lean +++ b/Mathlib/Data/Set/Pointwise/Basic.lean @@ -1311,13 +1311,10 @@ theorem preimage_mul_preimage_subset {s t : Set β} : m ⁻¹' s * m ⁻¹' t @[to_additive] lemma preimage_mul (hm : Injective m) {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) : - m ⁻¹' (s * t) = m ⁻¹' s * m ⁻¹' t := by - refine subset_antisymm ?_ (preimage_mul_preimage_subset m) - rintro a ⟨b, c, hb, hc, ha⟩ - obtain ⟨b, rfl⟩ := hs hb - obtain ⟨c, rfl⟩ := ht hc - simp only [← map_mul, hm.eq_iff] at ha - exact ⟨b, c, hb, hc, ha⟩ + m ⁻¹' (s * t) = m ⁻¹' s * m ⁻¹' t := + hm.image_injective <| by + rw [image_mul, image_preimage_eq_iff.2 hs, image_preimage_eq_iff.2 ht, + image_preimage_eq_iff.2 (mul_subset_range m hs ht)] end Mul @@ -1347,25 +1344,19 @@ theorem preimage_div_preimage_subset {s t : Set β} : m ⁻¹' s / m ⁻¹' t @[to_additive] lemma preimage_div (hm : Injective m) {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) : - m ⁻¹' (s / t) = m ⁻¹' s / m ⁻¹' t := by - refine subset_antisymm ?_ (preimage_div_preimage_subset m) - rintro a ⟨b, c, hb, hc, ha⟩ - obtain ⟨b, rfl⟩ := hs hb - obtain ⟨c, rfl⟩ := ht hc - simp only [← map_div, hm.eq_iff] at ha - exact ⟨b, c, hb, hc, ha⟩ + m ⁻¹' (s / t) = m ⁻¹' s / m ⁻¹' t := + hm.image_injective <| by + rw [image_div, image_preimage_eq_iff.2 hs, image_preimage_eq_iff.2 ht, + image_preimage_eq_iff.2 (div_subset_range m hs ht)] end Group @[to_additive] -theorem bddAbove_mul [OrderedCommMonoid α] {A B : Set α} : - BddAbove A → BddAbove B → BddAbove (A * B) := by - rintro ⟨bA, hbA⟩ ⟨bB, hbB⟩ - use bA * bB - rintro x ⟨xa, xb, hxa, hxb, rfl⟩ - exact mul_le_mul' (hbA hxa) (hbB hxb) -#align set.bdd_above_mul Set.bddAbove_mul -#align set.bdd_above_add Set.bddAbove_add +theorem BddAbove.mul [OrderedCommMonoid α] {A B : Set α} (hA : BddAbove A) (hB : BddAbove B) : + BddAbove (A * B) := + hA.image2 (fun _ _ _ h ↦ mul_le_mul_right' h _) (fun _ _ _ h ↦ mul_le_mul_left' h _) hB +#align set.bdd_above_mul Set.BddAbove.mul +#align set.bdd_above_add Set.BddAbove.add end Set From 9dd8f15a754d7da57db37b93200b9b25a3c664ad Mon Sep 17 00:00:00 2001 From: Michael Stoll Date: Sat, 23 Dec 2023 20:27:39 +0000 Subject: [PATCH 157/353] doc: Example use case of `Finset.filter` (#9239) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mention the spelling `s.filter (· ∈ t)` for the intersection of `s : Finset α` and `t : Set α` as a `Finset α` in the docstring of `Finset.filter`. See [here](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Intersection.20of.20a.20Finset.20and.20a.20Set.20as.20a.20Finset.3F/near/409632763) on Zulip. Co-authored-by: Michael Stoll <99838730+MichaelStollBayreuth@users.noreply.github.com> --- Mathlib/Data/Finset/Basic.lean | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mathlib/Data/Finset/Basic.lean b/Mathlib/Data/Finset/Basic.lean index 23e20a7b8c00b..a2f0ee4774396 100644 --- a/Mathlib/Data/Finset/Basic.lean +++ b/Mathlib/Data/Finset/Basic.lean @@ -2710,7 +2710,10 @@ section Filter variable (p q : α → Prop) [DecidablePred p] [DecidablePred q] {s : Finset α} -/-- `Finset.filter p s` is the set of elements of `s` that satisfy `p`. -/ +/-- `Finset.filter p s` is the set of elements of `s` that satisfy `p`. + +For example, one can use `s.filter (· ∈ t)` to get the intersection of `s` with `t : Set α` +as a `Finset α` (when a `DecidablePred (· ∈ t)` instance is available). -/ def filter (s : Finset α) : Finset α := ⟨_, s.2.filter p⟩ #align finset.filter Finset.filter From 4d1c265d88e183e9678897a5d575a7563553c3ad Mon Sep 17 00:00:00 2001 From: sven-manthe Date: Sat, 23 Dec 2023 21:23:08 +0000 Subject: [PATCH 158/353] fix: wrong links to (un)bundledHom (#9198) --- Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean b/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean index d264cd6d5b782..9319142866b45 100644 --- a/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean +++ b/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean @@ -15,9 +15,10 @@ import Mathlib.Mathport.Rename `Bundled c` provides a uniform structure for bundling a type equipped with a type class. -We provide `Category` instances for these in `CategoryTheory/UnbundledHom.lean` +We provide `Category` instances for these in `CategoryTheory/ConcreteCategory/UnbundledHom.lean` (for categories with unbundled homs, e.g. topological spaces) -and in `CategoryTheory/BundledHom.lean` (for categories with bundled homs, e.g. monoids). +and in `CategoryTheory/ConcreteCategory/BundledHom.lean` +(for categories with bundled homs, e.g. monoids). -/ universe u v From e9fb5b31bb918376a758dec1ff49931062deb8f4 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 23 Dec 2023 21:23:09 +0000 Subject: [PATCH 159/353] chore(Subfield): use `rintro` (#9230) Also explain why it can't be used in another field --- Mathlib/FieldTheory/Subfield.lean | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Mathlib/FieldTheory/Subfield.lean b/Mathlib/FieldTheory/Subfield.lean index 8b2acc302e4ad..d6b8b89dd0a7a 100644 --- a/Mathlib/FieldTheory/Subfield.lean +++ b/Mathlib/FieldTheory/Subfield.lean @@ -674,6 +674,7 @@ def closure (s : Set K) : Subfield K where exact ⟨-y, Subring.neg_mem _ hy, z, hz, x_eq ▸ neg_div _ _⟩ inv_mem' x := by rintro ⟨y, hy, z, hz, x_eq⟩; exact ⟨z, hz, y, hy, x_eq ▸ (inv_div _ _).symm ⟩ add_mem' x_mem y_mem := by + -- Use `id` in the next 2 `obtain`s so that assumptions stay there for the `rwa`s below obtain ⟨nx, hnx, dx, hdx, rfl⟩ := id x_mem obtain ⟨ny, hny, dy, hdy, rfl⟩ := id y_mem by_cases hx0 : dx = 0; · rwa [hx0, div_zero, zero_add] @@ -681,12 +682,10 @@ def closure (s : Set K) : Subfield K where exact ⟨nx * dy + dx * ny, Subring.add_mem _ (Subring.mul_mem _ hnx hdy) (Subring.mul_mem _ hdx hny), dx * dy, Subring.mul_mem _ hdx hdy, (div_add_div nx ny hx0 hy0).symm⟩ - mul_mem' x_mem y_mem := by - obtain ⟨nx, hnx, dx, hdx, rfl⟩ := id x_mem - obtain ⟨ny, hny, dy, hdy, rfl⟩ := id y_mem - exact - ⟨nx * ny, Subring.mul_mem _ hnx hny, dx * dy, Subring.mul_mem _ hdx hdy, - (div_mul_div_comm _ _ _ _).symm⟩ + mul_mem' := by + rintro _ _ ⟨nx, hnx, dx, hdx, rfl⟩ ⟨ny, hny, dy, hdy, rfl⟩ + exact ⟨nx * ny, Subring.mul_mem _ hnx hny, dx * dy, Subring.mul_mem _ hdx hdy, + (div_mul_div_comm _ _ _ _).symm⟩ #align subfield.closure Subfield.closure theorem mem_closure_iff {s : Set K} {x} : From 3be5400a94da9498852e57dc1703f1c2420a191b Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 24 Dec 2023 10:02:46 +0000 Subject: [PATCH 160/353] chore: bump to nightly-2023-12-24 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 214b445e62d53..400a8aac3fbbc 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-23 +leanprover/lean4:nightly-2023-12-24 From 86393c89527027210ac6eb681537b87b1c5840dc Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 24 Dec 2023 15:08:39 +0000 Subject: [PATCH 161/353] refactor: Use `Pairwise` wherever possible (#9236) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Performed with a regex search for `∀ (.) (.), \1 ≠ \2 →`, and a few variants to catch implicit binders and explicit types. I have deliberately avoided trying to make the analogous `Set.Pairwise` transformation (or any `Pairwise (foo on bar)` transformations) in this PR, to keep the diff small. Co-authored-by: Yaël Dillies --- Mathlib/Algebra/Lie/DirectSum.lean | 4 +-- Mathlib/Analysis/InnerProductSpace/Basic.lean | 8 ++--- .../Analysis/NormedSpace/FiniteDimension.lean | 8 ++--- .../Preadditive/HomOrthogonal.lean | 7 ++-- Mathlib/CategoryTheory/Sites/Preserves.lean | 4 +-- .../SimpleGraph/StronglyRegular.lean | 8 ++--- Mathlib/Data/Fintype/Basic.lean | 2 +- Mathlib/Data/Matrix/Basis.lean | 8 ++--- Mathlib/Data/Set/Lattice.lean | 10 +++--- Mathlib/Data/Setoid/Partition.lean | 6 ++-- Mathlib/Data/ZMod/Quotient.lean | 6 ++-- Mathlib/GroupTheory/NoncommPiCoprod.lean | 18 +++++----- Mathlib/GroupTheory/Perm/Sign.lean | 7 ++-- Mathlib/LinearAlgebra/Matrix/IsDiag.lean | 2 +- .../LinearAlgebra/Matrix/ToLinearEquiv.lean | 8 ++--- .../MeasureTheory/Covering/Besicovitch.lean | 5 +-- .../Covering/BesicovitchVectorSpace.lean | 32 +++++++++--------- Mathlib/MeasureTheory/Integral/SetToL1.lean | 5 +-- Mathlib/Order/Filter/Basic.lean | 6 ++-- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 9 ++--- Mathlib/RingTheory/Ideal/Operations.lean | 4 +-- .../RingTheory/Ideal/QuotientOperations.lean | 8 ++--- Mathlib/SetTheory/Cardinal/Basic.lean | 4 +-- Mathlib/Topology/ExtremallyDisconnected.lean | 2 +- Mathlib/Topology/SeparatedMap.lean | 2 +- Mathlib/Topology/Separation.lean | 33 ++++++++++--------- Mathlib/Topology/UniformSpace/Separation.lean | 2 +- 27 files changed, 112 insertions(+), 106 deletions(-) diff --git a/Mathlib/Algebra/Lie/DirectSum.lean b/Mathlib/Algebra/Lie/DirectSum.lean index 25fde115c0fd1..38e6851c3cf94 100644 --- a/Mathlib/Algebra/Lie/DirectSum.lean +++ b/Mathlib/Algebra/Lie/DirectSum.lean @@ -204,7 +204,7 @@ variable {R L ι} then this map is a morphism of Lie algebras. -/ @[simps] def toLieAlgebra [DecidableEq ι] (L' : Type w₁) [LieRing L'] [LieAlgebra R L'] - (f : ∀ i, L i →ₗ⁅R⁆ L') (hf : ∀ i j : ι, i ≠ j → ∀ (x : L i) (y : L j), ⁅f i x, f j y⁆ = 0) : + (f : ∀ i, L i →ₗ⁅R⁆ L') (hf : Pairwise fun i j => ∀ (x : L i) (y : L j), ⁅f i x, f j y⁆ = 0) : (⨁ i, L i) →ₗ⁅R⁆ L' := { toModule R ι L' fun i => (f i : L i →ₗ[R] L') with toFun := toModule R ι L' fun i => (f i : L i →ₗ[R] L') @@ -234,7 +234,7 @@ def toLieAlgebra [DecidableEq ι] (L' : Type w₁) [LieRing L'] [LieAlgebra R L' · simp_rw [lie_of_same, toAddMonoid_of, LinearMap.toAddMonoidHom_coe, LieHom.coe_toLinearMap, LieHom.map_lie] · simp_rw [lie_of_of_ne _ hij.symm, map_zero, LinearMap.toAddMonoidHom_coe, - LieHom.coe_toLinearMap, hf j i hij.symm x y] } + LieHom.coe_toLinearMap, hf hij.symm x y] } #align direct_sum.to_lie_algebra DirectSum.toLieAlgebra end Algebras diff --git a/Mathlib/Analysis/InnerProductSpace/Basic.lean b/Mathlib/Analysis/InnerProductSpace/Basic.lean index 4b9c1bf5d02a9..ad44efff83256 100644 --- a/Mathlib/Analysis/InnerProductSpace/Basic.lean +++ b/Mathlib/Analysis/InnerProductSpace/Basic.lean @@ -720,7 +720,7 @@ theorem real_inner_mul_inner_self_le (x y : F) : ⟪x, y⟫_ℝ * ⟪x, y⟫_ℝ /-- A family of vectors is linearly independent if they are nonzero and orthogonal. -/ theorem linearIndependent_of_ne_zero_of_inner_eq_zero {ι : Type*} {v : ι → E} (hz : ∀ i, v i ≠ 0) - (ho : ∀ i j, i ≠ j → ⟪v i, v j⟫ = 0) : LinearIndependent 𝕜 v := by + (ho : Pairwise fun i j => ⟪v i, v j⟫ = 0) : LinearIndependent 𝕜 v := by rw [linearIndependent_iff'] intro s g hg i hi have h' : g i * inner (v i) (v i) = inner (v i) (∑ j in s, g j • v j) := by @@ -729,7 +729,7 @@ theorem linearIndependent_of_ne_zero_of_inner_eq_zero {ι : Type*} {v : ι → E convert Finset.sum_eq_single (β := 𝕜) i ?_ ?_ · rw [inner_smul_right] · intro j _hj hji - rw [inner_smul_right, ho i j hji.symm, mul_zero] + rw [inner_smul_right, ho hji.symm, mul_zero] · exact fun h => False.elim (h hi) simpa [hg, hz] using h' #align linear_independent_of_ne_zero_of_inner_eq_zero linearIndependent_of_ne_zero_of_inner_eq_zero @@ -742,7 +742,7 @@ variable {ι : Type*} [dec_ι : DecidableEq ι] (𝕜) /-- An orthonormal set of vectors in an `InnerProductSpace` -/ def Orthonormal (v : ι → E) : Prop := - (∀ i, ‖v i‖ = 1) ∧ ∀ {i j}, i ≠ j → ⟪v i, v j⟫ = 0 + (∀ i, ‖v i‖ = 1) ∧ Pairwise fun i j => ⟪v i, v j⟫ = 0 #align orthonormal Orthonormal variable {𝕜} @@ -1990,7 +1990,7 @@ we have an associated orthogonal family of one-dimensional subspaces of `E`, whi to be able to discuss using `ι → 𝕜` rather than `Π i : ι, span 𝕜 (v i)`. -/ def OrthogonalFamily (G : ι → Type*) [∀ i, NormedAddCommGroup (G i)] [∀ i, InnerProductSpace 𝕜 (G i)] (V : ∀ i, G i →ₗᵢ[𝕜] E) : Prop := - ∀ ⦃i j⦄, i ≠ j → ∀ v : G i, ∀ w : G j, ⟪V i v, V j w⟫ = 0 + Pairwise fun i j => ∀ v : G i, ∀ w : G j, ⟪V i v, V j w⟫ = 0 #align orthogonal_family OrthogonalFamily variable {𝕜} diff --git a/Mathlib/Analysis/NormedSpace/FiniteDimension.lean b/Mathlib/Analysis/NormedSpace/FiniteDimension.lean index a904d1090e685..e759852b0180e 100644 --- a/Mathlib/Analysis/NormedSpace/FiniteDimension.lean +++ b/Mathlib/Analysis/NormedSpace/FiniteDimension.lean @@ -397,7 +397,7 @@ bounded by `R` and at distance at least `1`. For a version not assuming `c` and `exists_seq_norm_le_one_le_norm_sub`. -/ theorem exists_seq_norm_le_one_le_norm_sub' {c : 𝕜} (hc : 1 < ‖c‖) {R : ℝ} (hR : ‖c‖ < R) (h : ¬FiniteDimensional 𝕜 E) : - ∃ f : ℕ → E, (∀ n, ‖f n‖ ≤ R) ∧ ∀ m n, m ≠ n → 1 ≤ ‖f m - f n‖ := by + ∃ f : ℕ → E, (∀ n, ‖f n‖ ≤ R) ∧ Pairwise fun m n => 1 ≤ ‖f m - f n‖ := by have : IsSymm E fun x y : E => 1 ≤ ‖x - y‖ := by constructor intro x y hxy @@ -410,7 +410,7 @@ theorem exists_seq_norm_le_one_le_norm_sub' {c : 𝕜} (hc : 1 < ‖c‖) {R : #align exists_seq_norm_le_one_le_norm_sub' exists_seq_norm_le_one_le_norm_sub' theorem exists_seq_norm_le_one_le_norm_sub (h : ¬FiniteDimensional 𝕜 E) : - ∃ (R : ℝ) (f : ℕ → E), 1 < R ∧ (∀ n, ‖f n‖ ≤ R) ∧ ∀ m n, m ≠ n → 1 ≤ ‖f m - f n‖ := by + ∃ (R : ℝ) (f : ℕ → E), 1 < R ∧ (∀ n, ‖f n‖ ≤ R) ∧ Pairwise fun m n => 1 ≤ ‖f m - f n‖ := by obtain ⟨c, hc⟩ : ∃ c : 𝕜, 1 < ‖c‖ := NormedField.exists_one_lt_norm 𝕜 have A : ‖c‖ < ‖c‖ + 1 := by linarith rcases exists_seq_norm_le_one_le_norm_sub' hc A h with ⟨f, hf⟩ @@ -425,7 +425,7 @@ theorem finiteDimensional_of_isCompact_closedBall₀ {r : ℝ} (rpos : 0 < r) (h : IsCompact (Metric.closedBall (0 : E) r)) : FiniteDimensional 𝕜 E := by by_contra hfin obtain ⟨R, f, Rgt, fle, lef⟩ : - ∃ (R : ℝ) (f : ℕ → E), 1 < R ∧ (∀ n, ‖f n‖ ≤ R) ∧ ∀ m n, m ≠ n → 1 ≤ ‖f m - f n‖ := + ∃ (R : ℝ) (f : ℕ → E), 1 < R ∧ (∀ n, ‖f n‖ ≤ R) ∧ Pairwise fun m n => 1 ≤ ‖f m - f n‖ := exists_seq_norm_le_one_le_norm_sub hfin have rRpos : 0 < r / R := div_pos rpos (zero_lt_one.trans Rgt) obtain ⟨c, hc⟩ : ∃ c : 𝕜, 0 < ‖c‖ ∧ ‖c‖ < r / R := NormedField.exists_norm_lt _ rRpos @@ -448,7 +448,7 @@ theorem finiteDimensional_of_isCompact_closedBall₀ {r : ℝ} (rpos : 0 < r) conv_lhs => rw [← mul_one ‖c‖] simp only [dist_eq_norm, ← smul_sub, norm_smul] gcongr - apply lef _ _ (ne_of_gt _) + apply lef (ne_of_gt _) exact φmono (Nat.lt_succ_self N) _ < ‖c‖ := hN (N + 1) (Nat.le_succ N) #align finite_dimensional_of_is_compact_closed_ball₀ finiteDimensional_of_isCompact_closedBall₀ diff --git a/Mathlib/CategoryTheory/Preadditive/HomOrthogonal.lean b/Mathlib/CategoryTheory/Preadditive/HomOrthogonal.lean index 27b52d8608897..61d1449f1c76d 100644 --- a/Mathlib/CategoryTheory/Preadditive/HomOrthogonal.lean +++ b/Mathlib/CategoryTheory/Preadditive/HomOrthogonal.lean @@ -50,7 +50,7 @@ there is at most one morphism between distinct objects. (In a category with zero morphisms, that must be the zero morphism.) -/ def HomOrthogonal {ι : Type*} (s : ι → C) : Prop := - ∀ i j, i ≠ j → Subsingleton (s i ⟶ s j) + Pairwise fun i j => Subsingleton (s i ⟶ s j) #align category_theory.hom_orthogonal CategoryTheory.HomOrthogonal namespace HomOrthogonal @@ -58,9 +58,8 @@ namespace HomOrthogonal variable {ι : Type*} {s : ι → C} theorem eq_zero [HasZeroMorphisms C] (o : HomOrthogonal s) {i j : ι} (w : i ≠ j) (f : s i ⟶ s j) : - f = 0 := by - haveI := o i j w - apply Subsingleton.elim + f = 0 := + (o w).elim _ _ #align category_theory.hom_orthogonal.eq_zero CategoryTheory.HomOrthogonal.eq_zero section diff --git a/Mathlib/CategoryTheory/Sites/Preserves.lean b/Mathlib/CategoryTheory/Sites/Preserves.lean index 5e68e42eef7c5..db3579853c38c 100644 --- a/Mathlib/CategoryTheory/Sites/Preserves.lean +++ b/Mathlib/CategoryTheory/Sites/Preserves.lean @@ -74,7 +74,7 @@ variable (hI : IsInitial I) -- This is the data of a particular disjoint coproduct in `C`. variable {α : Type} {X : α → C} (c : Cofan X) (hc : IsColimit c) [(ofArrows X c.inj).hasPullbacks] [HasInitial C] [∀ i, Mono (c.inj i)] - (hd : ∀ i j, i ≠ j → IsPullback (initial.to _) (initial.to _) (c.inj i) (c.inj j)) + (hd : Pairwise fun i j => IsPullback (initial.to _) (initial.to _) (c.inj i) (c.inj j)) /-- The two parallel maps in the equalizer diagram for the sheaf condition corresponding to the @@ -88,7 +88,7 @@ theorem firstMap_eq_secondMap : Equalizer.Presieve.Arrows.firstMap F X c.inj = by_cases hi : i = j · rw [hi, Mono.right_cancellation _ _ pullback.condition] · have := preservesTerminalOfIsSheafForEmpty F hF hI - apply_fun (F.mapIso ((hd i j hi).isoPullback).op ≪≫ F.mapIso (terminalIsoIsTerminal + apply_fun (F.mapIso ((hd hi).isoPullback).op ≪≫ F.mapIso (terminalIsoIsTerminal (terminalOpOfInitial initialIsInitial)).symm ≪≫ (PreservesTerminal.iso F)).hom using injective_of_mono _ ext ⟨i⟩ diff --git a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean index 656e03e16d171..9cc0a4f495c4f 100644 --- a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean +++ b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean @@ -50,7 +50,7 @@ structure IsSRGWith (n k ℓ μ : ℕ) : Prop where card : Fintype.card V = n regular : G.IsRegularOfDegree k of_adj : ∀ v w : V, G.Adj v w → Fintype.card (G.commonNeighbors v w) = ℓ - of_not_adj : ∀ v w : V, v ≠ w → ¬G.Adj v w → Fintype.card (G.commonNeighbors v w) = μ + of_not_adj : Pairwise fun v w => ¬G.Adj v w → Fintype.card (G.commonNeighbors v w) = μ set_option linter.uppercaseLean3 false in #align simple_graph.is_SRG_with SimpleGraph.IsSRGWith @@ -102,7 +102,7 @@ adjacent to either `v` or `w` when `¬G.Adj v w`. So it's the cardinality of theorem IsSRGWith.card_neighborFinset_union_of_not_adj {v w : V} (h : G.IsSRGWith n k ℓ μ) (hne : v ≠ w) (ha : ¬G.Adj v w) : (G.neighborFinset v ∪ G.neighborFinset w).card = 2 * k - μ := by - rw [← h.of_not_adj v w hne ha] + rw [← h.of_not_adj hne ha] apply h.card_neighborFinset_union_eq set_option linter.uppercaseLean3 false in #align simple_graph.is_SRG_with.card_neighbor_finset_union_of_not_adj SimpleGraph.IsSRGWith.card_neighborFinset_union_of_not_adj @@ -206,7 +206,7 @@ theorem IsSRGWith.param_eq (h : G.IsSRGWith n k ℓ μ) (hn : 0 < n) : simp_rw [neighborFinset_compl, mem_sdiff, mem_compl, mem_singleton, mem_neighborFinset, ← Ne.def] at hw simp_rw [bipartiteBelow, adj_comm, ← mem_neighborFinset, filter_mem_eq_inter, - neighborFinset_def, ← Set.toFinset_inter, ← h.of_not_adj v w hw.2.symm hw.1, + neighborFinset_def, ← Set.toFinset_inter, ← h.of_not_adj hw.2.symm hw.1, ← Set.toFinset_card] congr! @@ -228,6 +228,6 @@ theorem IsSRGWith.matrix_eq {α : Type*} [Semiring α] (h : G.IsSRGWith n k ℓ simp only [ha, ite_true, ite_false, add_zero, zero_add, nsmul_eq_mul, smul_zero, mul_one, not_true_eq_false, not_false_eq_true, and_false, and_self] · rw [h.of_adj v w ha] - · rw [h.of_not_adj v w hn ha] + · rw [h.of_not_adj hn ha] end SimpleGraph diff --git a/Mathlib/Data/Fintype/Basic.lean b/Mathlib/Data/Fintype/Basic.lean index e2b0a9d38c4d7..53d4f755967f1 100644 --- a/Mathlib/Data/Fintype/Basic.lean +++ b/Mathlib/Data/Fintype/Basic.lean @@ -1299,7 +1299,7 @@ function `f : ℕ → α` such that `r (f m) (f n)` holds whenever `m ≠ n`. We also ensure that all constructed points satisfy a given predicate `P`. -/ theorem exists_seq_of_forall_finset_exists' {α : Type*} (P : α → Prop) (r : α → α → Prop) [IsSymm α r] (h : ∀ s : Finset α, (∀ x ∈ s, P x) → ∃ y, P y ∧ ∀ x ∈ s, r x y) : - ∃ f : ℕ → α, (∀ n, P (f n)) ∧ ∀ m n, m ≠ n → r (f m) (f n) := by + ∃ f : ℕ → α, (∀ n, P (f n)) ∧ Pairwise fun m n => r (f m) (f n) := by rcases exists_seq_of_forall_finset_exists P r h with ⟨f, hf, hf'⟩ refine' ⟨f, hf, fun m n hmn => _⟩ rcases lt_trichotomy m n with (h | rfl | h) diff --git a/Mathlib/Data/Matrix/Basis.lean b/Mathlib/Data/Matrix/Basis.lean index 40e9e7a798016..0017b658760ab 100644 --- a/Mathlib/Data/Matrix/Basis.lean +++ b/Mathlib/Data/Matrix/Basis.lean @@ -237,7 +237,7 @@ theorem diag_eq_of_commute_stdBasisMatrix {i j : n} {M : Matrix n n α} /-- `M` is a scalar matrix if it commutes with every non-diagonal `stdBasisMatrix`. ​-/ theorem mem_range_scalar_of_commute_stdBasisMatrix {M : Matrix n n α} - (hM : ∀ (i j : n), i ≠ j → Commute (stdBasisMatrix i j 1) M) : + (hM : Pairwise fun i j => Commute (stdBasisMatrix i j 1) M) : M ∈ Set.range (Matrix.scalar n) := by cases isEmpty_or_nonempty n · exact ⟨0, Subsingleton.elim _ _⟩ @@ -248,12 +248,12 @@ theorem mem_range_scalar_of_commute_stdBasisMatrix {M : Matrix n n α} · rw [diagonal_apply_eq] obtain rfl | hij := Decidable.eq_or_ne i j · rfl - · exact diag_eq_of_commute_stdBasisMatrix (hM _ _ hij) + · exact diag_eq_of_commute_stdBasisMatrix (hM hij) · push_neg at hkl rw [diagonal_apply_ne _ hkl] obtain rfl | hij := Decidable.eq_or_ne i j - · rw [col_eq_zero_of_commute_stdBasisMatrix (hM k i hkl.symm) hkl] - · rw [row_eq_zero_of_commute_stdBasisMatrix (hM i j hij) hkl.symm] + · rw [col_eq_zero_of_commute_stdBasisMatrix (hM hkl.symm) hkl] + · rw [row_eq_zero_of_commute_stdBasisMatrix (hM hij) hkl.symm] end Commute diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index c0677fbdf79ec..68cc9bac00df1 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -3,6 +3,7 @@ Copyright (c) 2014 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Johannes Hölzl, Mario Carneiro -/ +import Mathlib.Logic.Pairwise import Mathlib.Order.CompleteBooleanAlgebra import Mathlib.Order.Directed import Mathlib.Order.GaloisConnection @@ -2310,24 +2311,25 @@ theorem sigmaToiUnion_surjective : Surjective (sigmaToiUnion t) ⟨⟨a, b, hb⟩, rfl⟩ #align set.sigma_to_Union_surjective Set.sigmaToiUnion_surjective -theorem sigmaToiUnion_injective (h : ∀ i j, i ≠ j → Disjoint (t i) (t j)) : +theorem sigmaToiUnion_injective (h : Pairwise fun i j => Disjoint (t i) (t j)) : Injective (sigmaToiUnion t) | ⟨a₁, b₁, h₁⟩, ⟨a₂, b₂, h₂⟩, eq => have b_eq : b₁ = b₂ := congr_arg Subtype.val eq have a_eq : a₁ = a₂ := by_contradiction fun ne => have : b₁ ∈ t a₁ ∩ t a₂ := ⟨h₁, b_eq.symm ▸ h₂⟩ - (h _ _ ne).le_bot this + (h ne).le_bot this Sigma.eq a_eq <| Subtype.eq <| by subst b_eq; subst a_eq; rfl #align set.sigma_to_Union_injective Set.sigmaToiUnion_injective -theorem sigmaToiUnion_bijective (h : ∀ i j, i ≠ j → Disjoint (t i) (t j)) : +theorem sigmaToiUnion_bijective (h : Pairwise fun i j => Disjoint (t i) (t j)) : Bijective (sigmaToiUnion t) := ⟨sigmaToiUnion_injective t h, sigmaToiUnion_surjective t⟩ #align set.sigma_to_Union_bijective Set.sigmaToiUnion_bijective /-- Equivalence between a disjoint union and a dependent sum. -/ -noncomputable def unionEqSigmaOfDisjoint {t : α → Set β} (h : ∀ i j, i ≠ j → Disjoint (t i) (t j)) : +noncomputable def unionEqSigmaOfDisjoint {t : α → Set β} + (h : Pairwise fun i j => Disjoint (t i) (t j)) : (⋃ i, t i) ≃ Σi, t i := (Equiv.ofBijective _ <| sigmaToiUnion_bijective t h).symm #align set.Union_eq_sigma_of_disjoint Set.unionEqSigmaOfDisjoint diff --git a/Mathlib/Data/Setoid/Partition.lean b/Mathlib/Data/Setoid/Partition.lean index 144f049dd05ac..1aacd4decd9d5 100644 --- a/Mathlib/Data/Setoid/Partition.lean +++ b/Mathlib/Data/Setoid/Partition.lean @@ -363,10 +363,10 @@ structure IndexedPartition {ι α : Type*} (s : ι → Set α) where /-- The non-constructive constructor for `IndexedPartition`. -/ noncomputable def IndexedPartition.mk' {ι α : Type*} (s : ι → Set α) - (dis : ∀ i j, i ≠ j → Disjoint (s i) (s j)) (nonempty : ∀ i, (s i).Nonempty) + (dis : Pairwise fun i j => Disjoint (s i) (s j)) (nonempty : ∀ i, (s i).Nonempty) (ex : ∀ x, ∃ i, x ∈ s i) : IndexedPartition s where - eq_of_mem {_x _i _j} hxi hxj := by_contradiction fun h => (dis _ _ h).le_bot ⟨hxi, hxj⟩ + eq_of_mem {_x _i _j} hxi hxj := by_contradiction fun h => (dis h).le_bot ⟨hxi, hxj⟩ some i := (nonempty i).some some_mem i := (nonempty i).choose_spec index x := (ex x).choose @@ -399,7 +399,7 @@ theorem iUnion : ⋃ i, s i = univ := by simp [hs.exists_mem x] #align indexed_partition.Union IndexedPartition.iUnion -theorem disjoint : ∀ {i j}, i ≠ j → Disjoint (s i) (s j) := fun {_i _j} h => +theorem disjoint : Pairwise fun i j => Disjoint (s i) (s j) := fun {_i _j} h => disjoint_left.mpr fun {_x} hxi hxj => h (hs.eq_of_mem hxi hxj) #align indexed_partition.disjoint IndexedPartition.disjoint diff --git a/Mathlib/Data/ZMod/Quotient.lean b/Mathlib/Data/ZMod/Quotient.lean index 01b2b46b6e2aa..d7122d20761d5 100644 --- a/Mathlib/Data/ZMod/Quotient.lean +++ b/Mathlib/Data/ZMod/Quotient.lean @@ -70,9 +70,9 @@ open BigOperators Ideal /-- The **Chinese remainder theorem**, elementary version for `ZMod`. See also `Mathlib.Data.ZMod.Basic` for versions involving only two numbers. -/ def ZMod.prodEquivPi {ι : Type*} [Fintype ι] (a : ι → ℕ) - (coprime : ∀ i j, i ≠ j → Nat.Coprime (a i) (a j)) : ZMod (∏ i, a i) ≃+* ∀ i, ZMod (a i) := - have : ∀ (i j : ι), i ≠ j → IsCoprime (span {(a i : ℤ)}) (span {(a j : ℤ)}) := - fun i j h ↦ (isCoprime_span_singleton_iff _ _).mpr ((coprime i j h).cast (R := ℤ)) + (coprime : Pairwise fun i j => Nat.Coprime (a i) (a j)) : ZMod (∏ i, a i) ≃+* ∀ i, ZMod (a i) := + have : Pairwise fun i j => IsCoprime (span {(a i : ℤ)}) (span {(a j : ℤ)}) := + fun _i _j h ↦ (isCoprime_span_singleton_iff _ _).mpr ((coprime h).cast (R := ℤ)) Int.quotientSpanNatEquivZMod _ |>.symm.trans <| quotEquivOfEq (iInf_span_singleton_natCast (R := ℤ) coprime) |>.symm.trans <| quotientInfRingEquivPiQuotient _ this |>.trans <| diff --git a/Mathlib/GroupTheory/NoncommPiCoprod.lean b/Mathlib/GroupTheory/NoncommPiCoprod.lean index 385f16d85f7fc..8dad5c216d240 100644 --- a/Mathlib/GroupTheory/NoncommPiCoprod.lean +++ b/Mathlib/GroupTheory/NoncommPiCoprod.lean @@ -188,7 +188,7 @@ variable {H : ι → Type*} [∀ i, Group (H i)] variable (ϕ : ∀ i : ι, H i →* G) -variable {hcomm : ∀ i j : ι, i ≠ j → ∀ (x : H i) (y : H j), Commute (ϕ i x) (ϕ j y)} +variable {hcomm : Pairwise fun i j : ι => ∀ (x : H i) (y : H j), Commute (ϕ i x) (ϕ j y)} -- We use `f` and `g` to denote elements of `Π (i : ι), H i` variable (f g : ∀ i : ι, H i) @@ -201,7 +201,7 @@ theorem noncommPiCoprod_range : (noncommPiCoprod ϕ hcomm).range = ⨆ i : ι, ( classical apply le_antisymm · rintro x ⟨f, rfl⟩ - refine Subgroup.noncommProd_mem _ (fun _ _ _ _ h => hcomm _ _ h _ _) ?_ + refine Subgroup.noncommProd_mem _ (fun _ _ _ _ h => hcomm h _ _) ?_ intro i _hi apply Subgroup.mem_sSup_of_mem · use i @@ -221,7 +221,7 @@ theorem injective_noncommPiCoprod_of_independent apply eq_bot_iff.mpr intro f heq1 have : ∀ i, i ∈ Finset.univ → ϕ i (f i) = 1 := - Subgroup.eq_one_of_noncommProd_eq_one_of_independent _ _ (fun _ _ _ _ h => hcomm _ _ h _ _) + Subgroup.eq_one_of_noncommProd_eq_one_of_independent _ _ (fun _ _ _ _ h => hcomm h _ _) _ hind (by simp) heq1 ext i apply hinj @@ -233,7 +233,7 @@ variable (hcomm) @[to_additive] theorem independent_range_of_coprime_order [Finite ι] [∀ i, Fintype (H i)] - (hcoprime : ∀ i j, i ≠ j → Nat.Coprime (Fintype.card (H i)) (Fintype.card (H j))) : + (hcoprime : Pairwise fun i j => Nat.Coprime (Fintype.card (H i)) (Fintype.card (H j))) : CompleteLattice.Independent fun i => (ϕ i).range := by cases nonempty_fintype ι classical @@ -262,8 +262,8 @@ theorem independent_range_of_coprime_order [Finite ι] [∀ i, Fintype (H i)] rw [← hc] symm rw [← Nat.coprime_iff_gcd_eq_one, Nat.coprime_fintype_prod_left_iff, Subtype.forall] - intro j - exact hcoprime _ _ + intro j h + exact hcoprime h #align monoid_hom.independent_range_of_coprime_order MonoidHom.independent_range_of_coprime_order #align add_monoid_hom.independent_range_of_coprime_order AddMonoidHom.independent_range_of_coprime_order @@ -284,13 +284,13 @@ variable (f g : ∀ i : ι, H i) section CommutingSubgroups -- We assume that the elements of different subgroups commute -variable (hcomm : ∀ i j : ι, i ≠ j → ∀ x y : G, x ∈ H i → y ∈ H j → Commute x y) +variable (hcomm : Pairwise fun i j : ι => ∀ x y : G, x ∈ H i → y ∈ H j → Commute x y) @[to_additive] theorem commute_subtype_of_commute (i j : ι) (hne : i ≠ j) : ∀ (x : H i) (y : H j), Commute ((H i).subtype x) ((H j).subtype y) := by rintro ⟨x, hx⟩ ⟨y, hy⟩ - exact hcomm i j hne x y hx hy + exact hcomm hne x y hx hy #align subgroup.commute_subtype_of_commute Subgroup.commute_subtype_of_commute #align add_subgroup.commute_subtype_of_commute AddSubgroup.addCommute_subtype_of_addCommute @@ -331,7 +331,7 @@ variable (hcomm) @[to_additive] theorem independent_of_coprime_order [Finite ι] [∀ i, Fintype (H i)] - (hcoprime : ∀ i j, i ≠ j → Nat.Coprime (Fintype.card (H i)) (Fintype.card (H j))) : + (hcoprime : Pairwise fun i j => Nat.Coprime (Fintype.card (H i)) (Fintype.card (H j))) : CompleteLattice.Independent H := by simpa using MonoidHom.independent_range_of_coprime_order (fun i => (H i).subtype) diff --git a/Mathlib/GroupTheory/Perm/Sign.lean b/Mathlib/GroupTheory/Perm/Sign.lean index a123b22adcc08..5d00783df7b7a 100644 --- a/Mathlib/GroupTheory/Perm/Sign.lean +++ b/Mathlib/GroupTheory/Perm/Sign.lean @@ -517,13 +517,14 @@ def signAux3 [Fintype α] (f : Perm α) {s : Multiset α} : (∀ x, x ∈ s) → theorem signAux3_mul_and_swap [Fintype α] (f g : Perm α) (s : Multiset α) (hs : ∀ x, x ∈ s) : signAux3 (f * g) hs = signAux3 f hs * signAux3 g hs ∧ - ∀ x y, x ≠ y → signAux3 (swap x y) hs = -1 := by + Pairwise fun x y => signAux3 (swap x y) hs = -1 := by let ⟨l, hl⟩ := Quotient.exists_rep s let e := equivFin α --clear _let_match subst hl show - signAux2 l (f * g) = signAux2 l f * signAux2 l g ∧ ∀ x y, x ≠ y → signAux2 l (swap x y) = -1 + signAux2 l (f * g) = signAux2 l f * signAux2 l g ∧ + Pairwise fun x y => signAux2 l (swap x y) = -1 have hfg : (e.symm.trans (f * g)).trans e = (e.symm.trans f).trans e * (e.symm.trans g).trans e := Equiv.ext fun h => by simp [mul_apply] constructor @@ -577,7 +578,7 @@ theorem sign_symm (e : Perm α) : sign e.symm = sign e := #align equiv.perm.sign_symm Equiv.Perm.sign_symm theorem sign_swap {x y : α} (h : x ≠ y) : sign (swap x y) = -1 := - (signAux3_mul_and_swap 1 1 _ mem_univ).2 x y h + (signAux3_mul_and_swap 1 1 _ mem_univ).2 h #align equiv.perm.sign_swap Equiv.Perm.sign_swap @[simp] diff --git a/Mathlib/LinearAlgebra/Matrix/IsDiag.lean b/Mathlib/LinearAlgebra/Matrix/IsDiag.lean index db5fb577efe9f..0fe314acb5746 100644 --- a/Mathlib/LinearAlgebra/Matrix/IsDiag.lean +++ b/Mathlib/LinearAlgebra/Matrix/IsDiag.lean @@ -34,7 +34,7 @@ open Matrix Kronecker /-- `A.IsDiag` means square matrix `A` is a diagonal matrix. -/ def IsDiag [Zero α] (A : Matrix n n α) : Prop := - ∀ ⦃i j⦄, i ≠ j → A i j = 0 + Pairwise fun i j => A i j = 0 #align matrix.is_diag Matrix.IsDiag @[simp] diff --git a/Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean b/Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean index bebab512402ea..9af7edba13e7a 100644 --- a/Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean +++ b/Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean @@ -206,7 +206,7 @@ open BigOperators /-- A matrix whose nondiagonal entries are negative with the sum of the entries of each column positive has nonzero determinant. -/ lemma det_ne_zero_of_sum_col_pos [DecidableEq n] {S : Type*} [LinearOrderedCommRing S] - {A : Matrix n n S} (h1 : ∀ i j, i ≠ j → A i j < 0) (h2 : ∀ j, 0 < ∑ i, A i j) : + {A : Matrix n n S} (h1 : Pairwise fun i j => A i j < 0) (h2 : ∀ j, 0 < ∑ i, A i j) : A.det ≠ 0 := by cases isEmpty_or_nonempty n · simp @@ -229,17 +229,17 @@ lemma det_ne_zero_of_sum_col_pos [DecidableEq n] {S : Type*} [LinearOrderedCommR refine Finset.sum_le_sum (fun i hi => ?_) by_cases h : i = j₀ · rw [h] - · exact (mul_le_mul_right_of_neg (h1 i j₀ h)).mpr (h_j₀ ▸ Finset.le_sup' v hi) + · exact (mul_le_mul_right_of_neg (h1 h)).mpr (h_j₀ ▸ Finset.le_sup' v hi) /-- A matrix whose nondiagonal entries are negative with the sum of the entries of each row positive has nonzero determinant. -/ lemma det_ne_zero_of_sum_row_pos [DecidableEq n] {S : Type*} [LinearOrderedCommRing S] - {A : Matrix n n S} (h1 : ∀ i j, i ≠ j → A i j < 0) (h2 : ∀ i, 0 < ∑ j, A i j) : + {A : Matrix n n S} (h1 : Pairwise fun i j => A i j < 0) (h2 : ∀ i, 0 < ∑ j, A i j) : A.det ≠ 0 := by rw [← Matrix.det_transpose] refine det_ne_zero_of_sum_col_pos ?_ ?_ · simp_rw [Matrix.transpose_apply] - exact fun i j h => h1 j i h.symm + exact fun i j h => h1 h.symm · simp_rw [Matrix.transpose_apply] exact h2 diff --git a/Mathlib/MeasureTheory/Covering/Besicovitch.lean b/Mathlib/MeasureTheory/Covering/Besicovitch.lean index 7df00dc40b7fa..76fe1079012fa 100644 --- a/Mathlib/MeasureTheory/Covering/Besicovitch.lean +++ b/Mathlib/MeasureTheory/Covering/Besicovitch.lean @@ -128,7 +128,8 @@ structure Besicovitch.SatelliteConfig (α : Type*) [MetricSpace α] (N : ℕ) ( c : Fin N.succ → α r : Fin N.succ → ℝ rpos : ∀ i, 0 < r i - h : ∀ i j, i ≠ j → r i ≤ dist (c i) (c j) ∧ r j ≤ τ * r i ∨ r j ≤ dist (c j) (c i) ∧ r i ≤ τ * r j + h : Pairwise fun i j => + r i ≤ dist (c i) (c j) ∧ r j ≤ τ * r i ∨ r j ≤ dist (c j) (c i) ∧ r i ≤ τ * r j hlast : ∀ i < last N, r i ≤ dist (c i) (c (last N)) ∧ r (last N) ≤ τ * r i inter : ∀ i < last N, dist (c i) (c (last N)) ≤ r i + r (last N) #align besicovitch.satellite_config Besicovitch.SatelliteConfig @@ -440,7 +441,7 @@ theorem color_lt {i : Ordinal.{u}} (hi : i < p.lastStep) {N : ℕ} h := by intro a b a_ne_b wlog G_le : G a ≤ G b generalizing a b - · exact (this b a a_ne_b.symm (le_of_not_le G_le)).symm + · exact (this a_ne_b.symm (le_of_not_le G_le)).symm have G_lt : G a < G b := by rcases G_le.lt_or_eq with (H | H); · exact H have A : (a : ℕ) ≠ b := Fin.val_injective.ne a_ne_b diff --git a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean index 7ddcdff18db69..93902bf019e54 100644 --- a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean +++ b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean @@ -65,7 +65,7 @@ def centerAndRescale : SatelliteConfig E N τ where r i := (a.r (last N))⁻¹ * a.r i rpos i := mul_pos (inv_pos.2 (a.rpos _)) (a.rpos _) h i j hij := by - rcases a.h i j hij with (H | H) + rcases a.h hij with (H | H) · left constructor · rw [dist_eq_norm, ← smul_sub, norm_smul, Real.norm_eq_abs, @@ -215,7 +215,7 @@ theorem exists_goodδ : set N := multiplicity E + 1 with hN have : ∀ δ : ℝ, 0 < δ → ∃ f : Fin N → E, (∀ i : Fin N, ‖f i‖ ≤ 2) ∧ - ∀ i j, i ≠ j → 1 - δ ≤ ‖f i - f j‖ := by + Pairwise fun i j => 1 - δ ≤ ‖f i - f j‖ := by intro δ hδ rcases lt_or_le δ 1 with (hδ' | hδ') · rcases h δ hδ hδ' with ⟨s, hs, h's, s_card⟩ @@ -232,7 +232,7 @@ theorem exists_goodδ : -- in the image are separated by `1 - δ`. choose! F hF using this -- Choose a converging subsequence when `δ → 0`. - have : ∃ f : Fin N → E, (∀ i : Fin N, ‖f i‖ ≤ 2) ∧ ∀ i j, i ≠ j → 1 ≤ ‖f i - f j‖ := by + have : ∃ f : Fin N → E, (∀ i : Fin N, ‖f i‖ ≤ 2) ∧ Pairwise fun i j => 1 ≤ ‖f i - f j‖ := by obtain ⟨u, _, zero_lt_u, hu⟩ : ∃ u : ℕ → ℝ, (∀ m n : ℕ, m < n → u n < u m) ∧ (∀ n : ℕ, 0 < u n) ∧ Filter.Tendsto u Filter.atTop (𝓝 0) := @@ -253,13 +253,13 @@ theorem exists_goodδ : have B : Tendsto (fun n => 1 - u (φ n)) atTop (𝓝 (1 - 0)) := tendsto_const_nhds.sub (hu.comp φ_mono.tendsto_atTop) rw [sub_zero] at B - exact le_of_tendsto_of_tendsto' B A fun n => (hF (u (φ n)) (zero_lt_u _)).2 i j hij + exact le_of_tendsto_of_tendsto' B A fun n => (hF (u (φ n)) (zero_lt_u _)).2 hij rcases this with ⟨f, hf, h'f⟩ -- the range of `f` contradicts the definition of `multiplicity E`. have finj : Function.Injective f := by intro i j hij by_contra h - have : 1 ≤ ‖f i - f j‖ := h'f i j h + have : 1 ≤ ‖f i - f j‖ := h'f h simp only [hij, norm_zero, sub_self] at this exact lt_irrefl _ (this.trans_lt zero_lt_one) let s := Finset.image f Finset.univ @@ -272,7 +272,7 @@ theorem exists_goodδ : Ne.def, exists_true_left, forall_apply_eq_imp_iff, forall_true_left, true_and] intro i j hij have : i ≠ j := fun h => by rw [h] at hij; exact hij rfl - exact h'f i j this + exact h'f this have : s.card ≤ multiplicity E := card_le_multiplicity hs h's rw [s_card, hN] at this exact lt_irrefl _ ((Nat.lt_succ_self (multiplicity E)).trans_le this) @@ -307,12 +307,12 @@ theorem card_le_multiplicity_of_δ {s : Finset E} (hs : ∀ c ∈ s, ‖c‖ ≤ #align besicovitch.card_le_multiplicity_of_δ Besicovitch.card_le_multiplicity_of_δ theorem le_multiplicity_of_δ_of_fin {n : ℕ} (f : Fin n → E) (h : ∀ i, ‖f i‖ ≤ 2) - (h' : ∀ i j, i ≠ j → 1 - goodδ E ≤ ‖f i - f j‖) : n ≤ multiplicity E := by + (h' : Pairwise fun i j => 1 - goodδ E ≤ ‖f i - f j‖) : n ≤ multiplicity E := by classical have finj : Function.Injective f := by intro i j hij by_contra h - have : 1 - goodδ E ≤ ‖f i - f j‖ := h' i j h + have : 1 - goodδ E ≤ ‖f i - f j‖ := h' h simp only [hij, norm_zero, sub_self] at this linarith [goodδ_lt_one E] let s := Finset.image f Finset.univ @@ -325,7 +325,7 @@ theorem le_multiplicity_of_δ_of_fin {n : ℕ} (f : Fin n → E) (h : ∀ i, ‖ Ne.def, exists_true_left, forall_apply_eq_imp_iff, forall_true_left, true_and] intro i j hij have : i ≠ j := fun h => by rw [h] at hij; exact hij rfl - exact h' i j this + exact h' this have : s.card ≤ multiplicity E := card_le_multiplicity_of_δ hs h's rwa [s_card] at this #align besicovitch.le_multiplicity_of_δ_of_fin Besicovitch.le_multiplicity_of_δ_of_fin @@ -355,7 +355,7 @@ theorem exists_normalized_aux1 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) (lastr : a.r (last N) = 1) (hτ : 1 ≤ τ) (δ : ℝ) (hδ1 : τ ≤ 1 + δ / 4) (hδ2 : δ ≤ 1) (i j : Fin N.succ) (inej : i ≠ j) : 1 - δ ≤ ‖a.c i - a.c j‖ := by have ah : - ∀ i j, i ≠ j → a.r i ≤ ‖a.c i - a.c j‖ ∧ a.r j ≤ τ * a.r i ∨ + Pairwise fun i j => a.r i ≤ ‖a.c i - a.c j‖ ∧ a.r j ≤ τ * a.r i ∨ a.r j ≤ ‖a.c j - a.c i‖ ∧ a.r i ≤ τ * a.r j := by simpa only [dist_eq_norm] using a.h have δnonneg : 0 ≤ δ := by linarith only [hτ, hδ1] @@ -373,7 +373,7 @@ theorem exists_normalized_aux1 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) intro k rw [inv_eq_one_div, div_le_iff τpos, ← lastr, mul_comm] exact a.hlast' k hτ - rcases ah i j inej with (H | H) + rcases ah inej with (H | H) · apply le_trans _ H.1 exact hτ' i · rw [norm_sub_rev] @@ -388,7 +388,7 @@ theorem exists_normalized_aux2 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) (hδ2 : δ ≤ 1) (i j : Fin N.succ) (inej : i ≠ j) (hi : ‖a.c i‖ ≤ 2) (hj : 2 < ‖a.c j‖) : 1 - δ ≤ ‖a.c i - (2 / ‖a.c j‖) • a.c j‖ := by have ah : - ∀ i j, i ≠ j → a.r i ≤ ‖a.c i - a.c j‖ ∧ a.r j ≤ τ * a.r i ∨ + Pairwise fun i j => a.r i ≤ ‖a.c i - a.c j‖ ∧ a.r j ≤ τ * a.r i ∨ a.r j ≤ ‖a.c j - a.c i‖ ∧ a.r i ≤ τ * a.r j := by simpa only [dist_eq_norm] using a.h have δnonneg : 0 ≤ δ := by linarith only [hτ, hδ1] @@ -408,7 +408,7 @@ theorem exists_normalized_aux2 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) _ = (1 : ℝ) - δ ^ 2 / 16 := by ring _ ≤ 1 := by linarith only [sq_nonneg δ] have A : a.r j - δ ≤ ‖a.c i - a.c j‖ := by - rcases ah j i inej.symm with (H | H); · rw [norm_sub_rev]; linarith [H.1] + rcases ah inej.symm with (H | H); · rw [norm_sub_rev]; linarith [H.1] have C : a.r j ≤ 4 := calc a.r j ≤ τ * a.r i := H.2 @@ -444,7 +444,7 @@ theorem exists_normalized_aux3 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) (i j : Fin N.succ) (inej : i ≠ j) (hi : 2 < ‖a.c i‖) (hij : ‖a.c i‖ ≤ ‖a.c j‖) : 1 - δ ≤ ‖(2 / ‖a.c i‖) • a.c i - (2 / ‖a.c j‖) • a.c j‖ := by have ah : - ∀ i j, i ≠ j → a.r i ≤ ‖a.c i - a.c j‖ ∧ a.r j ≤ τ * a.r i ∨ + Pairwise fun i j => a.r i ≤ ‖a.c i - a.c j‖ ∧ a.r j ≤ τ * a.r i ∨ a.r j ≤ ‖a.c j - a.c i‖ ∧ a.r i ≤ τ * a.r j := by simpa only [dist_eq_norm] using a.h have δnonneg : 0 ≤ δ := by linarith only [hτ, hδ1] @@ -473,7 +473,7 @@ theorem exists_normalized_aux3 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) have J : a.r j - ‖a.c j - a.c i‖ ≤ s / 2 * δ := calc a.r j - ‖a.c j - a.c i‖ ≤ s * (τ - 1) := by - rcases ah j i inej.symm with (H | H) + rcases ah inej.symm with (H | H) · calc a.r j - ‖a.c j - a.c i‖ ≤ 0 := sub_nonpos.2 H.1 _ ≤ s * (τ - 1) := mul_nonneg spos.le (sub_nonneg.2 hτ) @@ -498,7 +498,7 @@ theorem exists_normalized_aux3 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) theorem exists_normalized {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) (lastc : a.c (last N) = 0) (lastr : a.r (last N) = 1) (hτ : 1 ≤ τ) (δ : ℝ) (hδ1 : τ ≤ 1 + δ / 4) (hδ2 : δ ≤ 1) : - ∃ c' : Fin N.succ → E, (∀ n, ‖c' n‖ ≤ 2) ∧ ∀ i j, i ≠ j → 1 - δ ≤ ‖c' i - c' j‖ := by + ∃ c' : Fin N.succ → E, (∀ n, ‖c' n‖ ≤ 2) ∧ Pairwise fun i j => 1 - δ ≤ ‖c' i - c' j‖ := by let c' : Fin N.succ → E := fun i => if ‖a.c i‖ ≤ 2 then a.c i else (2 / ‖a.c i‖) • a.c i have norm_c'_le : ∀ i, ‖c' i‖ ≤ 2 := by intro i diff --git a/Mathlib/MeasureTheory/Integral/SetToL1.lean b/Mathlib/MeasureTheory/Integral/SetToL1.lean index 573afc7088656..a6468c2c05e87 100644 --- a/Mathlib/MeasureTheory/Integral/SetToL1.lean +++ b/Mathlib/MeasureTheory/Integral/SetToL1.lean @@ -359,7 +359,8 @@ theorem map_setToSimpleFunc (T : Set α → F →L[ℝ] F') (h_add : FinMeasAddi #align measure_theory.simple_func.map_set_to_simple_func MeasureTheory.SimpleFunc.map_setToSimpleFunc theorem setToSimpleFunc_congr' (T : Set α → E →L[ℝ] F) (h_add : FinMeasAdditive μ T) {f g : α →ₛ E} - (hf : Integrable f μ) (hg : Integrable g μ) (h : ∀ x y, x ≠ y → T (f ⁻¹' {x} ∩ g ⁻¹' {y}) = 0) : + (hf : Integrable f μ) (hg : Integrable g μ) + (h : Pairwise fun x y => T (f ⁻¹' {x} ∩ g ⁻¹' {y}) = 0) : f.setToSimpleFunc T = g.setToSimpleFunc T := show ((pair f g).map Prod.fst).setToSimpleFunc T = ((pair f g).map Prod.snd).setToSimpleFunc T by have h_pair : Integrable (f.pair g) μ := integrable_pair hf hg @@ -373,7 +374,7 @@ theorem setToSimpleFunc_congr' (T : Set α → E →L[ℝ] F) (h_add : FinMeasAd have h_eq : T ((⇑(f.pair g)) ⁻¹' {(f a, g a)}) = T (f ⁻¹' {f a} ∩ g ⁻¹' {g a}) := by congr; rw [pair_preimage_singleton f g] rw [h_eq] - exact h (f a) (g a) eq + exact h eq simp only [this, ContinuousLinearMap.zero_apply, pair_apply] #align measure_theory.simple_func.set_to_simple_func_congr' MeasureTheory.SimpleFunc.setToSimpleFunc_congr' diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index 3b635d1d87aa4..239ab82453851 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -751,12 +751,12 @@ theorem inf_eq_bot_iff {f g : Filter α} : f ⊓ g = ⊥ ↔ ∃ U ∈ f, ∃ V theorem _root_.Pairwise.exists_mem_filter_of_disjoint {ι : Type*} [Finite ι] {l : ι → Filter α} (hd : Pairwise (Disjoint on l)) : ∃ s : ι → Set α, (∀ i, s i ∈ l i) ∧ Pairwise (Disjoint on s) := by - have : ∀ i j, i ≠ j → ∃ (s : {s // s ∈ l i}) (t : {t // t ∈ l j}), Disjoint s.1 t.1 := by + have : Pairwise fun i j => ∃ (s : {s // s ∈ l i}) (t : {t // t ∈ l j}), Disjoint s.1 t.1 := by simpa only [Pairwise, Function.onFun, Filter.disjoint_iff, exists_prop, Subtype.exists] using hd choose! s t hst using this - refine' ⟨fun i => ⋂ j, s i j ∩ t j i, fun i => _, fun i j hij => _⟩ + refine' ⟨fun i => ⋂ j, @s i j ∩ @t j i, fun i => _, fun i j hij => _⟩ exacts [iInter_mem.2 fun j => inter_mem (@s i j).2 (@t j i).2, - (hst _ _ hij).mono ((iInter_subset _ j).trans (inter_subset_left _ _)) + (hst hij).mono ((iInter_subset _ j).trans (inter_subset_left _ _)) ((iInter_subset _ i).trans (inter_subset_right _ _))] #align pairwise.exists_mem_filter_of_disjoint Pairwise.exists_mem_filter_of_disjoint diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 0735503cab567..e65d929db4123 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -1308,18 +1308,19 @@ theorem IsDedekindDomain.inf_prime_pow_eq_prod {ι : Type*} (s : Finset ι) (f : /-- **Chinese remainder theorem** for a Dedekind domain: if the ideal `I` factors as `∏ i, P i ^ e i`, then `R ⧸ I` factors as `Π i, R ⧸ (P i ^ e i)`. -/ noncomputable def IsDedekindDomain.quotientEquivPiOfProdEq {ι : Type*} [Fintype ι] (I : Ideal R) - (P : ι → Ideal R) (e : ι → ℕ) (prime : ∀ i, Prime (P i)) (coprime : ∀ i j, i ≠ j → P i ≠ P j) + (P : ι → Ideal R) (e : ι → ℕ) (prime : ∀ i, Prime (P i)) + (coprime : Pairwise fun i j => P i ≠ P j) (prod_eq : ∏ i, P i ^ e i = I) : R ⧸ I ≃+* ∀ i, R ⧸ P i ^ e i := (Ideal.quotEquivOfEq (by simp only [← prod_eq, Finset.inf_eq_iInf, Finset.mem_univ, ciInf_pos, - ← IsDedekindDomain.inf_prime_pow_eq_prod _ _ _ (fun i _ => prime i) fun i _ j _ => - coprime i j])).trans <| + ← IsDedekindDomain.inf_prime_pow_eq_prod _ _ _ (fun i _ => prime i) + (coprime.set_pairwise _)])).trans <| Ideal.quotientInfRingEquivPiQuotient _ fun i j hij => Ideal.coprime_of_no_prime_ge (by intro P hPi hPj hPp haveI := Ideal.isPrime_of_prime (prime i) haveI := Ideal.isPrime_of_prime (prime j) - refine coprime i j hij ?_ + refine coprime hij ?_ refine ((Ring.DimensionLeOne.prime_le_prime_iff_eq ?_).mp (Ideal.le_of_pow_le_prime hPi)).trans ((Ring.DimensionLeOne.prime_le_prime_iff_eq ?_).mp diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 16b95872f7ee9..39c0d075a1d5a 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -640,10 +640,10 @@ theorem iInf_span_singleton {ι : Type*} [Fintype ι] {I : ι → R} #align ideal.infi_span_singleton Ideal.iInf_span_singleton theorem iInf_span_singleton_natCast {R : Type*} [CommRing R] {ι : Type*} [Fintype ι] - {I : ι → ℕ} (hI : ∀ (i j : ι), i ≠ j → (I i).Coprime (I j)) : + {I : ι → ℕ} (hI : Pairwise fun i j => (I i).Coprime (I j)) : ⨅ (i : ι), span {(I i : R)} = span {((∏ i : ι, I i : ℕ) : R)} := by rw [iInf_span_singleton, Nat.cast_prod] - exact fun i j h ↦ (hI i j h).cast + exact fun i j h ↦ (hI h).cast theorem sup_eq_top_iff_isCoprime {R : Type*} [CommSemiring R] (x y : R) : span ({x} : Set R) ⊔ span {y} = ⊤ ↔ IsCoprime x y := by diff --git a/Mathlib/RingTheory/Ideal/QuotientOperations.lean b/Mathlib/RingTheory/Ideal/QuotientOperations.lean index 4e84f80f12237..cb0f1b1d75627 100644 --- a/Mathlib/RingTheory/Ideal/QuotientOperations.lean +++ b/Mathlib/RingTheory/Ideal/QuotientOperations.lean @@ -198,7 +198,7 @@ lemma quotientInfToPiQuotient_inj (I : ι → Ideal R) : Injective (quotientInfT rw [quotientInfToPiQuotient, injective_lift_iff, ker_Pi_Quotient_mk] lemma quotientInfToPiQuotient_surj [Fintype ι] {I : ι → Ideal R} - (hI : ∀ i j, i ≠ j → IsCoprime (I i) (I j)) : Surjective (quotientInfToPiQuotient I) := by + (hI : Pairwise fun i j => IsCoprime (I i) (I j)) : Surjective (quotientInfToPiQuotient I) := by classical intro g choose f hf using fun i ↦ mk_surjective (g i) @@ -206,7 +206,7 @@ lemma quotientInfToPiQuotient_surj [Fintype ι] {I : ι → Ideal R} intro i have hI' : ∀ j ∈ ({i} : Finset ι)ᶜ, IsCoprime (I i) (I j) := by intros j hj - exact hI _ _ (by simpa [ne_comm, isCoprime_iff_add] using hj) + exact hI (by simpa [ne_comm, isCoprime_iff_add] using hj) rcases isCoprime_iff_exists.mp (isCoprime_biInf hI') with ⟨u, hu, e, he, hue⟩ replace he : ∀ j, j ≠ i → e ∈ I j := by simpa using he refine ⟨e, ?_, ?_⟩ @@ -223,7 +223,7 @@ lemma quotientInfToPiQuotient_surj [Fintype ι] {I : ι → Ideal R} /-- Chinese Remainder Theorem. Eisenbud Ex.2.6. Similar to Atiyah-Macdonald 1.10 and Stacks 00DT -/ noncomputable def quotientInfRingEquivPiQuotient [Fintype ι] (f : ι → Ideal R) - (hf : ∀ i j, i ≠ j → IsCoprime (f i) (f j)) : (R ⧸ ⨅ i, f i) ≃+* ∀ i, R ⧸ f i := + (hf : Pairwise fun i j => IsCoprime (f i) (f j)) : (R ⧸ ⨅ i, f i) ≃+* ∀ i, R ⧸ f i := { Equiv.ofBijective _ ⟨quotientInfToPiQuotient_inj f, quotientInfToPiQuotient_surj hf⟩, quotientInfToPiQuotient f with } #align ideal.quotient_inf_ring_equiv_pi_quotient Ideal.quotientInfRingEquivPiQuotient @@ -232,7 +232,7 @@ noncomputable def quotientInfRingEquivPiQuotient [Fintype ι] (f : ι → Ideal noncomputable def quotientInfEquivQuotientProd (I J : Ideal R) (coprime : IsCoprime I J) : R ⧸ I ⊓ J ≃+* (R ⧸ I) × R ⧸ J := let f : Fin 2 → Ideal R := ![I, J] - have hf : ∀ i j : Fin 2, i ≠ j → IsCoprime (f i) (f j) := by + have hf : Pairwise fun i j => IsCoprime (f i) (f j) := by intro i j h fin_cases i <;> fin_cases j <;> try contradiction · assumption diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index 94c0f5b2086c9..b88a9421a9a2e 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -2215,14 +2215,14 @@ theorem mk_iUnion_le_sum_mk_lift {α : Type u} {ι : Type v} {f : ι → Set α} _ = sum fun i => #(f i) := mk_sigma _ theorem mk_iUnion_eq_sum_mk {α ι : Type u} {f : ι → Set α} - (h : ∀ i j, i ≠ j → Disjoint (f i) (f j)) : #(⋃ i, f i) = sum fun i => #(f i) := + (h : Pairwise fun i j => Disjoint (f i) (f j)) : #(⋃ i, f i) = sum fun i => #(f i) := calc #(⋃ i, f i) = #(Σi, f i) := mk_congr (Set.unionEqSigmaOfDisjoint h) _ = sum fun i => #(f i) := mk_sigma _ #align cardinal.mk_Union_eq_sum_mk Cardinal.mk_iUnion_eq_sum_mk theorem mk_iUnion_eq_sum_mk_lift {α : Type u} {ι : Type v} {f : ι → Set α} - (h : ∀ i j, i ≠ j → Disjoint (f i) (f j)) : + (h : Pairwise fun i j => Disjoint (f i) (f j)) : lift.{v} #(⋃ i, f i) = sum fun i => #(f i) := calc lift.{v} #(⋃ i, f i) = #(Σi, f i) := diff --git a/Mathlib/Topology/ExtremallyDisconnected.lean b/Mathlib/Topology/ExtremallyDisconnected.lean index 8ebfbb00cb076..5d622bca84f94 100644 --- a/Mathlib/Topology/ExtremallyDisconnected.lean +++ b/Mathlib/Topology/ExtremallyDisconnected.lean @@ -55,7 +55,7 @@ section TotallySeparated instance [ExtremallyDisconnected X] [T2Space X] : TotallySeparatedSpace X := { isTotallySeparated_univ := by intro x _ y _ hxy - obtain ⟨U, V, hUV⟩ := T2Space.t2 x y hxy + obtain ⟨U, V, hUV⟩ := T2Space.t2 hxy refine ⟨closure U, (closure U)ᶜ, ExtremallyDisconnected.open_closure U hUV.1, by simp only [isOpen_compl_iff, isClosed_closure], subset_closure hUV.2.2.1, ?_, by simp only [Set.union_compl_self, Set.subset_univ], disjoint_compl_right⟩ diff --git a/Mathlib/Topology/SeparatedMap.lean b/Mathlib/Topology/SeparatedMap.lean index 0b3befa648bab..7a443a1e101d2 100644 --- a/Mathlib/Topology/SeparatedMap.lean +++ b/Mathlib/Topology/SeparatedMap.lean @@ -59,7 +59,7 @@ def IsSeparatedMap (f : X → Y) : Prop := ∀ x₁ x₂, f x₁ = f x₂ → x₁ ≠ x₂ → ∃ s₁ s₂, IsOpen s₁ ∧ IsOpen s₂ ∧ x₁ ∈ s₁ ∧ x₂ ∈ s₂ ∧ Disjoint s₁ s₂ lemma t2space_iff_isSeparatedMap (y : Y) : T2Space X ↔ IsSeparatedMap fun _ : X ↦ y := - ⟨fun ⟨t2⟩ x₁ x₂ _ hne ↦ t2 x₁ x₂ hne, fun sep ↦ ⟨fun x₁ x₂ hne ↦ sep x₁ x₂ rfl hne⟩⟩ + ⟨fun ⟨t2⟩ _ _ _ hne ↦ t2 hne, fun sep ↦ ⟨fun x₁ x₂ hne ↦ sep x₁ x₂ rfl hne⟩⟩ lemma T2Space.isSeparatedMap [T2Space X] (f : X → Y) : IsSeparatedMap f := fun _ _ _ ↦ t2_separation diff --git a/Mathlib/Topology/Separation.lean b/Mathlib/Topology/Separation.lean index 2be4ca20a9a76..792e8fd7b27b4 100644 --- a/Mathlib/Topology/Separation.lean +++ b/Mathlib/Topology/Separation.lean @@ -186,8 +186,8 @@ theorem t0Space_iff_inseparable (X : Type u) [TopologicalSpace X] : #align t0_space_iff_inseparable t0Space_iff_inseparable theorem t0Space_iff_not_inseparable (X : Type u) [TopologicalSpace X] : - T0Space X ↔ ∀ x y : X, x ≠ y → ¬Inseparable x y := by - simp only [t0Space_iff_inseparable, Ne.def, not_imp_not] + T0Space X ↔ Pairwise fun x y : X => ¬Inseparable x y := by + simp only [t0Space_iff_inseparable, Ne.def, not_imp_not, Pairwise] #align t0_space_iff_not_inseparable t0Space_iff_not_inseparable theorem Inseparable.eq [T0Space X] {x y : X} (h : Inseparable x y) : x = y := @@ -246,14 +246,14 @@ theorem TopologicalSpace.IsTopologicalBasis.eq_iff [T0Space X] {b : Set (Set X)} inseparable_iff_eq.symm.trans hb.inseparable_iff theorem t0Space_iff_exists_isOpen_xor'_mem (X : Type u) [TopologicalSpace X] : - T0Space X ↔ ∀ x y, x ≠ y → ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) := by + T0Space X ↔ Pairwise fun x y => ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) := by simp only [t0Space_iff_not_inseparable, xor_iff_not_iff, not_forall, exists_prop, - inseparable_iff_forall_open] + inseparable_iff_forall_open, Pairwise] #align t0_space_iff_exists_is_open_xor_mem t0Space_iff_exists_isOpen_xor'_mem theorem exists_isOpen_xor'_mem [T0Space X] {x y : X} (h : x ≠ y) : ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) := - (t0Space_iff_exists_isOpen_xor'_mem X).1 ‹_› x y h + (t0Space_iff_exists_isOpen_xor'_mem X).1 ‹_› h #align exists_is_open_xor_mem exists_isOpen_xor'_mem /-- Specialization forms a partial order on a t0 topological space. -/ @@ -349,7 +349,7 @@ instance Subtype.t0Space [T0Space X] {p : X → Prop} : T0Space (Subtype p) := #align subtype.t0_space Subtype.t0Space theorem t0Space_iff_or_not_mem_closure (X : Type u) [TopologicalSpace X] : - T0Space X ↔ ∀ a b : X, a ≠ b → a ∉ closure ({b} : Set X) ∨ b ∉ closure ({a} : Set X) := by + T0Space X ↔ Pairwise fun a b : X => a ∉ closure ({b} : Set X) ∨ b ∉ closure ({a} : Set X) := by simp only [t0Space_iff_not_inseparable, inseparable_iff_mem_closure, not_and_or] #align t0_space_iff_or_not_mem_closure t0Space_iff_or_not_mem_closure @@ -525,7 +525,7 @@ theorem CofiniteTopology.continuous_of [T1Space X] : Continuous (@CofiniteTopolo #align cofinite_topology.continuous_of CofiniteTopology.continuous_of theorem t1Space_iff_exists_open : - T1Space X ↔ ∀ x y, x ≠ y → ∃ U : Set X, IsOpen U ∧ x ∈ U ∧ y ∉ U := + T1Space X ↔ Pairwise fun x y => ∃ U : Set X, IsOpen U ∧ x ∈ U ∧ y ∉ U := (t1Space_TFAE X).out 0 6 #align t1_space_iff_exists_open t1Space_iff_exists_open @@ -919,17 +919,17 @@ theorem TopologicalSpace.subset_trans {s t : Set X} (ts : t ⊆ s) : @[mk_iff t2Space_iff] class T2Space (X : Type u) [TopologicalSpace X] : Prop where /-- Every two points in a Hausdorff space admit disjoint open neighbourhoods. -/ - t2 : ∀ x y, x ≠ y → ∃ u v : Set X, IsOpen u ∧ IsOpen v ∧ x ∈ u ∧ y ∈ v ∧ Disjoint u v + t2 : Pairwise fun x y => ∃ u v : Set X, IsOpen u ∧ IsOpen v ∧ x ∈ u ∧ y ∈ v ∧ Disjoint u v #align t2_space T2Space /-- Two different points can be separated by open sets. -/ theorem t2_separation [T2Space X] {x y : X} (h : x ≠ y) : ∃ u v : Set X, IsOpen u ∧ IsOpen v ∧ x ∈ u ∧ y ∈ v ∧ Disjoint u v := - T2Space.t2 x y h + T2Space.t2 h #align t2_separation t2_separation -- todo: use this as a definition? -theorem t2Space_iff_disjoint_nhds : T2Space X ↔ ∀ x y : X, x ≠ y → Disjoint (𝓝 x) (𝓝 y) := by +theorem t2Space_iff_disjoint_nhds : T2Space X ↔ Pairwise fun x y : X => Disjoint (𝓝 x) (𝓝 y) := by refine (t2Space_iff X).trans (forall₃_congr fun x y _ => ?_) simp only [(nhds_basis_opens x).disjoint_iff (nhds_basis_opens y), exists_prop, ← exists_and_left, and_assoc, and_comm, and_left_comm] @@ -937,7 +937,7 @@ theorem t2Space_iff_disjoint_nhds : T2Space X ↔ ∀ x y : X, x ≠ y → Disjo @[simp] theorem disjoint_nhds_nhds [T2Space X] {x y : X} : Disjoint (𝓝 x) (𝓝 y) ↔ x ≠ y := - ⟨fun hd he => by simp [he, nhds_neBot.ne] at hd, t2Space_iff_disjoint_nhds.mp ‹_› x y⟩ + ⟨fun hd he => by simp [he, nhds_neBot.ne] at hd, (t2Space_iff_disjoint_nhds.mp ‹_› ·)⟩ #align disjoint_nhds_nhds disjoint_nhds_nhds theorem pairwise_disjoint_nhds [T2Space X] : Pairwise (Disjoint on (𝓝 : X → Filter X)) := fun _ _ => @@ -972,15 +972,16 @@ instance (priority := 100) T2Space.t1Space [T2Space X] : T1Space X := /-- A space is T₂ iff the neighbourhoods of distinct points generate the bottom filter. -/ theorem t2_iff_nhds : T2Space X ↔ ∀ {x y : X}, NeBot (𝓝 x ⊓ 𝓝 y) → x = y := by - simp only [t2Space_iff_disjoint_nhds, disjoint_iff, neBot_iff, Ne.def, not_imp_comm] + simp only [t2Space_iff_disjoint_nhds, disjoint_iff, neBot_iff, Ne.def, not_imp_comm, Pairwise] #align t2_iff_nhds t2_iff_nhds theorem eq_of_nhds_neBot [T2Space X] {x y : X} (h : NeBot (𝓝 x ⊓ 𝓝 y)) : x = y := t2_iff_nhds.mp ‹_› h #align eq_of_nhds_ne_bot eq_of_nhds_neBot -theorem t2Space_iff_nhds : T2Space X ↔ ∀ {x y : X}, x ≠ y → ∃ U ∈ 𝓝 x, ∃ V ∈ 𝓝 y, Disjoint U V := by - simp only [t2Space_iff_disjoint_nhds, Filter.disjoint_iff] +theorem t2Space_iff_nhds : + T2Space X ↔ Pairwise fun x y : X => ∃ U ∈ 𝓝 x, ∃ V ∈ 𝓝 y, Disjoint U V := by + simp only [t2Space_iff_disjoint_nhds, Filter.disjoint_iff, Pairwise] #align t2_space_iff_nhds t2Space_iff_nhds theorem t2_separation_nhds [T2Space X] {x y : X} (h : x ≠ y) : @@ -1002,7 +1003,7 @@ theorem t2_iff_ultrafilter : theorem t2_iff_isClosed_diagonal : T2Space X ↔ IsClosed (diagonal X) := by simp only [t2Space_iff_disjoint_nhds, ← isOpen_compl_iff, isOpen_iff_mem_nhds, Prod.forall, - nhds_prod_eq, compl_diagonal_mem_prod, mem_compl_iff, mem_diagonal_iff] + nhds_prod_eq, compl_diagonal_mem_prod, mem_compl_iff, mem_diagonal_iff, Pairwise] #align t2_iff_is_closed_diagonal t2_iff_isClosed_diagonal theorem isClosed_diagonal [T2Space X] : IsClosed (diagonal X) := @@ -1831,7 +1832,7 @@ instance (priority := 100) T3Space.t25Space [T3Space X] : T25Space X := by refine' ⟨fun x y hne => _⟩ rw [lift'_nhds_closure, lift'_nhds_closure] have : x ∉ closure {y} ∨ y ∉ closure {x} := - (t0Space_iff_or_not_mem_closure X).mp inferInstance x y hne + (t0Space_iff_or_not_mem_closure X).mp inferInstance hne simp only [← disjoint_nhds_nhdsSet, nhdsSet_singleton] at this exact this.elim id fun h => h.symm #align t3_space.t2_5_space T3Space.t25Space diff --git a/Mathlib/Topology/UniformSpace/Separation.lean b/Mathlib/Topology/UniformSpace/Separation.lean index f719763500116..807a31e430cfe 100644 --- a/Mathlib/Topology/UniformSpace/Separation.lean +++ b/Mathlib/Topology/UniformSpace/Separation.lean @@ -137,7 +137,7 @@ theorem separated_def {α : Type u} [UniformSpace α] : #align separated_def separated_def theorem separated_def' {α : Type u} [UniformSpace α] : - SeparatedSpace α ↔ ∀ x y, x ≠ y → ∃ r ∈ 𝓤 α, (x, y) ∉ r := + SeparatedSpace α ↔ Pairwise fun x y => ∃ r ∈ 𝓤 α, (x, y) ∉ r := separated_def.trans <| forall₂_congr fun x y => by rw [← not_imp_not]; simp [not_forall] #align separated_def' separated_def' From 640097f125a0e966c4624a50b0b853af7a529d68 Mon Sep 17 00:00:00 2001 From: sgouezel Date: Sun, 24 Dec 2023 16:01:17 +0000 Subject: [PATCH 162/353] feat: the volume in a MeasureSpace over an empty index is the Dirac mass (#8799) --- Mathlib/MeasureTheory/Constructions/Pi.lean | 5 +++++ Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/Mathlib/MeasureTheory/Constructions/Pi.lean b/Mathlib/MeasureTheory/Constructions/Pi.lean index f516a4398ddd0..e6944af86af8e 100644 --- a/Mathlib/MeasureTheory/Constructions/Pi.lean +++ b/Mathlib/MeasureTheory/Constructions/Pi.lean @@ -421,6 +421,11 @@ theorem pi_of_empty {α : Type*} [Fintype α] [IsEmpty α] {β : α → Type*} exact isEmptyElim (α := α) #align measure_theory.measure.pi_of_empty MeasureTheory.Measure.pi_of_empty +lemma volume_pi_eq_dirac {ι : Type*} [Fintype ι] [IsEmpty ι] + {α : ι → Type*} [∀ i, MeasureSpace (α i)] (x : ∀ a, α a := isEmptyElim) : + (volume : Measure (∀ i, α i)) = Measure.dirac x := + Measure.pi_of_empty _ _ + @[simp] theorem pi_empty_univ {α : Type*} [Fintype α] [IsEmpty α] {β : α → Type*} {m : ∀ α, MeasurableSpace (β α)} (μ : ∀ a : α, Measure (β a)) : diff --git a/Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean b/Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean index 20e9d73183634..6de56e379a67b 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/InnerProductSpace.lean @@ -120,4 +120,12 @@ theorem PiLp.volume_preserving_equiv : MeasurePreserving (WithLp.equiv 2 (ι → theorem PiLp.volume_preserving_equiv_symm : MeasurePreserving (WithLp.equiv 2 (ι → ℝ)).symm := (EuclideanSpace.volume_preserving_measurableEquiv ι).symm +lemma volume_euclideanSpace_eq_dirac [IsEmpty ι] : + (volume : Measure (EuclideanSpace ℝ ι)) = Measure.dirac 0 := by + ext s hs + simp only [← ((EuclideanSpace.volume_preserving_measurableEquiv ι).symm).measure_preimage hs, + volume_pi_eq_dirac 0, MeasurableEquiv.measurableSet_preimage, hs, dirac_apply', indicator, + mem_preimage, Pi.one_apply] + rfl + end PiLp From dd0886f429862c93eec21ba4740b222a96f4f23d Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sun, 24 Dec 2023 16:01:18 +0000 Subject: [PATCH 163/353] =?UTF-8?q?chore(Measure/Hausdorff):=20use=20`?= =?UTF-8?q?=C2=B7=20^=20=C2=B7`=20instead=20of=20`NNReal.rpow`=20(#9255)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also reflow some newlines --- Mathlib/MeasureTheory/Measure/Hausdorff.lean | 35 ++++++++------------ 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/Mathlib/MeasureTheory/Measure/Hausdorff.lean b/Mathlib/MeasureTheory/Measure/Hausdorff.lean index 1ae18fd636374..119d8d03cadef 100644 --- a/Mathlib/MeasureTheory/Measure/Hausdorff.lean +++ b/Mathlib/MeasureTheory/Measure/Hausdorff.lean @@ -736,7 +736,7 @@ theorem hausdorffMeasure_image_le (h : HolderOnWith C r f s) (hr : 0 < r) {d : · rcases eq_empty_or_nonempty s with (rfl | ⟨x, hx⟩) · simp only [measure_empty, nonpos_iff_eq_zero, mul_zero, image_empty] have : f '' s = {f x} := - haveI : (f '' s).Subsingleton := by simpa [diam_eq_zero_iff] using h.ediam_image_le + have : (f '' s).Subsingleton := by simpa [diam_eq_zero_iff] using h.ediam_image_le (subsingleton_iff_singleton (mem_image_of_mem f hx)).1 this rw [this] rcases eq_or_lt_of_le hd with (rfl | h'd) @@ -755,12 +755,9 @@ theorem hausdorffMeasure_image_le (h : HolderOnWith C r f s) (hr : 0 < r) {d : ENNReal.tendsto_const_mul_rpow_nhds_zero_of_pos ENNReal.coe_ne_top hr rcases ENNReal.nhds_zero_basis_Iic.eventually_iff.1 (this.eventually (gt_mem_nhds hR)) with ⟨δ, δ0, H⟩ - refine' - le_iSup₂_of_le δ δ0 - (iInf₂_mono' fun t hst => - ⟨fun n => f '' (t n ∩ s), _, - iInf_mono' fun htδ => - ⟨fun n => (h.ediam_image_inter_le (t n)).trans (H (htδ n)).le, _⟩⟩) + refine le_iSup₂_of_le δ δ0 <| iInf₂_mono' fun t hst ↦ + ⟨fun n => f '' (t n ∩ s), ?_, iInf_mono' fun htδ ↦ + ⟨fun n => (h.ediam_image_inter_le (t n)).trans (H (htδ n)).le, ?_⟩⟩ · rw [← image_iUnion, ← iUnion_inter] exact image_subset _ (subset_inter hst Subset.rfl) · refine' ENNReal.tsum_le_tsum fun n => _ @@ -802,8 +799,8 @@ open scoped Pointwise theorem MeasureTheory.Measure.hausdorffMeasure_smul₀ {𝕜 E : Type*} [NormedAddCommGroup E] [NormedField 𝕜] [NormedSpace 𝕜 E] [MeasurableSpace E] [BorelSpace E] {d : ℝ} (hd : 0 ≤ d) - {r : 𝕜} (hr : r ≠ 0) (s : Set E) : μH[d] (r • s) = NNReal.rpow ‖r‖₊ d • μH[d] s := by - suffices ∀ {r : 𝕜}, r ≠ 0 → ∀ s : Set E, μH[d] (r • s) ≤ NNReal.rpow ‖r‖₊ d • μH[d] s by + {r : 𝕜} (hr : r ≠ 0) (s : Set E) : μH[d] (r • s) = ‖r‖₊ ^ d • μH[d] s := by + suffices ∀ {r : 𝕜}, r ≠ 0 → ∀ s : Set E, μH[d] (r • s) ≤ ‖r‖₊ ^ d • μH[d] s by refine' le_antisymm (this hr s) _ rw [← le_inv_smul_iff_of_pos] dsimp @@ -820,7 +817,6 @@ theorem MeasureTheory.Measure.hausdorffMeasure_smul₀ {𝕜 E : Type*} [NormedA ### Antilipschitz maps do not decrease Hausdorff measures and dimension -/ - namespace AntilipschitzWith variable {f : X → Y} {K : ℝ≥0} {d : ℝ} @@ -951,15 +947,13 @@ theorem hausdorffMeasure_pi_real {ι : Type*} [Fintype ι] : (μH[Fintype.card ι] : Measure (ι → ℝ)) = volume := by classical -- it suffices to check that the two measures coincide on products of rational intervals - refine' - (pi_eq_generateFrom (fun _ => Real.borel_eq_generateFrom_Ioo_rat.symm) - (fun _ => Real.isPiSystem_Ioo_rat) (fun _ => Real.finiteSpanningSetsInIooRat _) _).symm + refine (pi_eq_generateFrom (fun _ => Real.borel_eq_generateFrom_Ioo_rat.symm) + (fun _ => Real.isPiSystem_Ioo_rat) (fun _ => Real.finiteSpanningSetsInIooRat _) ?_).symm simp only [mem_iUnion, mem_singleton_iff] -- fix such a product `s` of rational intervals, of the form `Π (a i, b i)`. intro s hs choose a b H using hs - obtain rfl : s = fun i => Ioo (α := ℝ) (a i) (b i) - exact funext fun i => (H i).2 + obtain rfl : s = fun i => Ioo (α := ℝ) (a i) (b i) := funext fun i => (H i).2 replace H := fun i => (H i).1 apply le_antisymm _ -- first check that `volume s ≤ μH s` @@ -1072,10 +1066,10 @@ theorem hausdorffMeasure_prod_real : (μH[2] : Measure (ℝ × ℝ)) = volume := /-! ### Geometric results in affine spaces -/ - section Geometric variable {𝕜 E P : Type*} + theorem hausdorffMeasure_smul_right_image [NormedAddCommGroup E] [NormedSpace ℝ E] [MeasurableSpace E] [BorelSpace E] (v : E) (s : Set ℝ) : μH[1] ((fun r => r • v) '' s) = ‖v‖₊ • μH[1] s := by @@ -1104,8 +1098,7 @@ theorem hausdorffMeasure_smul_right_image [NormedAddCommGroup E] [NormedSpace refine' AddMonoidHomClass.isometry_of_norm _ fun x => (norm_smul _ _).trans _ rw [norm_smul, norm_inv, norm_norm, inv_mul_cancel hn, mul_one, LinearMap.id_apply] rw [Set.image_smul, Measure.hausdorffMeasure_smul₀ zero_le_one hn, nnnorm_norm, - NNReal.rpow_eq_pow, NNReal.rpow_one, - iso_smul.hausdorffMeasure_image (Or.inl <| zero_le_one' ℝ)] + NNReal.rpow_one, iso_smul.hausdorffMeasure_image (Or.inl <| zero_le_one' ℝ)] #align measure_theory.hausdorff_measure_smul_right_image MeasureTheory.hausdorffMeasure_smul_right_image section NormedFieldAffine @@ -1116,10 +1109,10 @@ variable [MetricSpace P] [NormedAddTorsor E P] [BorelSpace P] /-- Scaling by `c` around `x` scales the measure by `‖c‖₊ ^ d`. -/ theorem hausdorffMeasure_homothety_image {d : ℝ} (hd : 0 ≤ d) (x : P) {c : 𝕜} (hc : c ≠ 0) - (s : Set P) : μH[d] (AffineMap.homothety x c '' s) = NNReal.rpow ‖c‖₊ d • μH[d] s := by + (s : Set P) : μH[d] (AffineMap.homothety x c '' s) = ‖c‖₊ ^ d • μH[d] s := by suffices μH[d] (IsometryEquiv.vaddConst x '' ((c • ·) '' ((IsometryEquiv.vaddConst x).symm '' s))) = - NNReal.rpow ‖c‖₊ d • μH[d] s by + ‖c‖₊ ^ d • μH[d] s by simpa only [Set.image_image] borelize E rw [IsometryEquiv.hausdorffMeasure_image, Set.image_smul, Measure.hausdorffMeasure_smul₀ hd hc, @@ -1127,7 +1120,7 @@ theorem hausdorffMeasure_homothety_image {d : ℝ} (hd : 0 ≤ d) (x : P) {c : #align measure_theory.hausdorff_measure_homothety_image MeasureTheory.hausdorffMeasure_homothety_image theorem hausdorffMeasure_homothety_preimage {d : ℝ} (hd : 0 ≤ d) (x : P) {c : 𝕜} (hc : c ≠ 0) - (s : Set P) : μH[d] (AffineMap.homothety x c ⁻¹' s) = NNReal.rpow ‖c‖₊⁻¹ d • μH[d] s := by + (s : Set P) : μH[d] (AffineMap.homothety x c ⁻¹' s) = ‖c‖₊⁻¹ ^ d • μH[d] s := by change μH[d] (AffineEquiv.homothetyUnitsMulHom x (Units.mk0 c hc) ⁻¹' s) = _ rw [← AffineEquiv.image_symm, AffineEquiv.coe_homothetyUnitsMulHom_apply_symm, hausdorffMeasure_homothety_image hd x (_ : 𝕜ˣ).isUnit.ne_zero, Units.val_inv_eq_inv_val, From 8919646c667738d920bf43c8e8d5df0063a9d22e Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Dec 2023 00:48:40 +0000 Subject: [PATCH 164/353] chore(Data/Set/Function): rename some lemmas (#9257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `Set.maps_image_to` → `Set.mapsTo_image_iff`; - `Set.maps_univ_to` → `Set.mapsTo_univ_iff`; - `Set.maps_range_to` → `Set.mapsTo_range_iff`. In all cases, use implicit arguments instead of explicit arguments. In the last case, also generalize from `Type*` to `Sort*` and replace the RHS with its `simp`-normal form. Old lemmas stay there but are now deprecated. --- Mathlib/Algebra/Module/Zlattice.lean | 2 +- Mathlib/Data/Set/Finite.lean | 2 +- Mathlib/Data/Set/Function.lean | 21 +++++++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Mathlib/Algebra/Module/Zlattice.lean b/Mathlib/Algebra/Module/Zlattice.lean index add3590eb674c..ca92331e58b2d 100644 --- a/Mathlib/Algebra/Module/Zlattice.lean +++ b/Mathlib/Algebra/Module/Zlattice.lean @@ -480,7 +480,7 @@ theorem Zlattice.rank : finrank ℤ L = finrank K E := by -- takes value into the finite set `fundamentalDomain e ∩ L` have h_mapsto : Set.MapsTo (fun n : ℤ => Zspan.fract e (n • v)) Set.univ (Metric.closedBall 0 (∑ i, ‖e i‖) ∩ (L : Set E)) := by - rw [Set.mapsTo_inter, Set.maps_univ_to, Set.maps_univ_to] + rw [Set.mapsTo_inter, Set.mapsTo_univ_iff, Set.mapsTo_univ_iff] refine ⟨fun _ => mem_closedBall_zero_iff.mpr (Zspan.norm_fract_le e _), fun _ => ?_⟩ · change _ ∈ AddSubgroup.toIntSubmodule L rw [← h_spanL] diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index 70a84f80d331f..14fd58c7716c1 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -1497,7 +1497,7 @@ theorem Infinite.exists_lt_map_eq_of_mapsTo [LinearOrder α] {s : Set α} {t : S theorem Finite.exists_lt_map_eq_of_forall_mem [LinearOrder α] [Infinite α] {t : Set β} {f : α → β} (hf : ∀ a, f a ∈ t) (ht : t.Finite) : ∃ a b, a < b ∧ f a = f b := by - rw [← maps_univ_to] at hf + rw [← mapsTo_univ_iff] at hf obtain ⟨a, -, b, -, h⟩ := infinite_univ.exists_lt_map_eq_of_mapsTo hf ht exact ⟨a, b, h⟩ #align set.finite.exists_lt_map_eq_of_forall_mem Set.Finite.exists_lt_map_eq_of_forall_mem diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean index 3a3ba016b48b3..e97c5aa518e65 100644 --- a/Mathlib/Data/Set/Function.lean +++ b/Mathlib/Data/Set/Function.lean @@ -538,10 +538,15 @@ theorem mapsTo_range (f : α → β) (s : Set α) : MapsTo f s (range f) := #align set.maps_to_range Set.mapsTo_range @[simp] -theorem maps_image_to (f : α → β) (g : γ → α) (s : Set γ) (t : Set β) : +theorem mapsTo_image_iff {f : α → β} {g : γ → α} {s : Set γ} {t : Set β} : MapsTo f (g '' s) t ↔ MapsTo (f ∘ g) s t := ⟨fun h c hc => h ⟨c, hc, rfl⟩, fun h _ ⟨_, hc⟩ => hc.2 ▸ h hc.1⟩ -#align set.maps_image_to Set.maps_image_to +#align set.maps_image_to Set.mapsTo_image_iff + +@[deprecated] +lemma maps_image_to (f : α → β) (g : γ → α) (s : Set γ) (t : Set β) : + MapsTo f (g '' s) t ↔ MapsTo (f ∘ g) s t := + mapsTo_image_iff lemma MapsTo.comp_left (g : β → γ) (hf : MapsTo f s t) : MapsTo (g ∘ f) s (g '' t) := fun x hx ↦ ⟨f x, hf hx, rfl⟩ @@ -552,13 +557,21 @@ lemma MapsTo.comp_right {s : Set β} {t : Set γ} (hg : MapsTo g s t) (f : α #align set.maps_to.comp_right Set.MapsTo.comp_right @[simp] -theorem maps_univ_to (f : α → β) (s : Set β) : MapsTo f univ s ↔ ∀ a, f a ∈ s := +lemma mapsTo_univ_iff : MapsTo f univ t ↔ ∀ x, f x ∈ t := ⟨fun h _ => h (mem_univ _), fun h x _ => h x⟩ + +@[deprecated] +theorem maps_univ_to (f : α → β) (s : Set β) : MapsTo f univ s ↔ ∀ a, f a ∈ s := + mapsTo_univ_iff #align set.maps_univ_to Set.maps_univ_to @[simp] +lemma mapsTo_range_iff {g : ι → α} : MapsTo f (range g) t ↔ ∀ i, f (g i) ∈ t := + forall_range_iff + +@[deprecated mapsTo_range_iff] theorem maps_range_to (f : α → β) (g : γ → α) (s : Set β) : - MapsTo f (range g) s ↔ MapsTo (f ∘ g) univ s := by rw [← image_univ, maps_image_to] + MapsTo f (range g) s ↔ MapsTo (f ∘ g) univ s := by rw [← image_univ, mapsTo_image_iff] #align set.maps_range_to Set.maps_range_to theorem surjective_mapsTo_image_restrict (f : α → β) (s : Set α) : From db487f117f40af7eaa922c3cb9e1e97b44f37e05 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Dec 2023 01:16:24 +0000 Subject: [PATCH 165/353] feat(Topology/Order): upgrade `continuous_generateFrom` to an `iff` (#9259) Similarly, upgrade `tendsto_nhds_generateFrom`, `IsTopologicalBasis.continuous`, `Topology.IsLower.continuous_of_Ici`, and `Topology.IsUpper.continuous_iff_Iic`. The old lemmas are now deprecated, and the new ones have `_iff` in their names. Once we remove the old lemmas, we can drop the `_iff` suffixes. --- .../GammaSpecAdjunction.lean | 2 +- .../ProjectiveSpectrum/Scheme.lean | 2 +- Mathlib/Combinatorics/Hindman.lean | 4 +-- .../MeasureTheory/Constructions/Polish.lean | 2 +- .../Algebra/Order/MonotoneContinuity.lean | 5 ++- Mathlib/Topology/Bases.lean | 10 ++++-- Mathlib/Topology/CompactOpen.lean | 8 ++--- Mathlib/Topology/Order.lean | 23 +++++++------ .../Topology/Order/LowerUpperTopology.lean | 34 +++++++++++-------- 9 files changed, 52 insertions(+), 38 deletions(-) diff --git a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean index 5c0c54363c4e1..d554bcfc2dd88 100644 --- a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean +++ b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean @@ -87,7 +87,7 @@ theorem toΓSpec_preim_basicOpen_eq (r : Γ.obj (op X)) : /-- `toΓSpecFun` is continuous. -/ theorem toΓSpec_continuous : Continuous X.toΓSpecFun := by - apply isTopologicalBasis_basic_opens.continuous + rw [isTopologicalBasis_basic_opens.continuous_iff] rintro _ ⟨r, rfl⟩ erw [X.toΓSpec_preim_basicOpen_eq r] exact (X.toRingedSpace.basicOpen r).2 diff --git a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean index 7f43e8d3c3f0a..2f2a92cafb46d 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean @@ -334,7 +334,7 @@ open set in `Spec A⁰_f`. def toSpec {f : A} : (Proj.T| pbo f) ⟶ Spec.T A⁰_ f where toFun := ToSpec.toFun f continuous_toFun := by - apply IsTopologicalBasis.continuous PrimeSpectrum.isTopologicalBasis_basic_opens + rw [PrimeSpectrum.isTopologicalBasis_basic_opens.continuous_iff] rintro _ ⟨⟨k, ⟨a, ha⟩, ⟨b, hb1⟩, ⟨k', hb2⟩⟩, rfl⟩; dsimp erw [ToSpec.preimage_eq f a b k ha hb1 ⟨k', hb2⟩] refine' isOpen_induced_iff.mpr ⟨(pbo f).1 ⊓ (pbo a).1, IsOpen.inter (pbo f).2 (pbo a).2, _⟩ diff --git a/Mathlib/Combinatorics/Hindman.lean b/Mathlib/Combinatorics/Hindman.lean index 1301cd870999a..a39ec2c8675d3 100644 --- a/Mathlib/Combinatorics/Hindman.lean +++ b/Mathlib/Combinatorics/Hindman.lean @@ -82,8 +82,8 @@ attribute [local instance] Ultrafilter.semigroup Ultrafilter.addSemigroup @[to_additive] theorem Ultrafilter.continuous_mul_left {M} [Semigroup M] (V : Ultrafilter M) : Continuous (· * V) := - TopologicalSpace.IsTopologicalBasis.continuous ultrafilterBasis_is_basis _ <| - Set.forall_range_iff.mpr fun s => ultrafilter_isOpen_basic { m : M | ∀ᶠ m' in V, m * m' ∈ s } + ultrafilterBasis_is_basis.continuous_iff.2 <| Set.forall_range_iff.mpr fun s ↦ + ultrafilter_isOpen_basic { m : M | ∀ᶠ m' in V, m * m' ∈ s } #align ultrafilter.continuous_mul_left Ultrafilter.continuous_mul_left #align ultrafilter.continuous_add_left Ultrafilter.continuous_add_left diff --git a/Mathlib/MeasureTheory/Constructions/Polish.lean b/Mathlib/MeasureTheory/Constructions/Polish.lean index 790346d33b0d7..ef4908a785719 100644 --- a/Mathlib/MeasureTheory/Constructions/Polish.lean +++ b/Mathlib/MeasureTheory/Constructions/Polish.lean @@ -338,7 +338,7 @@ theorem _root_.Measurable.exists_continuous {α β : Type*} [t : TopologicalSpac exists_polishSpace_forall_le T Tt Tpolish refine' ⟨t', t't, _, t'_polish⟩ have : Continuous[t', _] (rangeFactorization f) := - hb.continuous _ fun s hs => t'T ⟨s, hs⟩ _ (Topen ⟨s, hs⟩) + hb.continuous_iff.2 fun s hs => t'T ⟨s, hs⟩ _ (Topen ⟨s, hs⟩) exact continuous_subtype_val.comp this #align measurable.exists_continuous Measurable.exists_continuous diff --git a/Mathlib/Topology/Algebra/Order/MonotoneContinuity.lean b/Mathlib/Topology/Algebra/Order/MonotoneContinuity.lean index 875f971026d8d..029ebb2153320 100644 --- a/Mathlib/Topology/Algebra/Order/MonotoneContinuity.lean +++ b/Mathlib/Topology/Algebra/Order/MonotoneContinuity.lean @@ -303,9 +303,8 @@ variable {α β : Type*} [PartialOrder α] [PartialOrder β] [TopologicalSpace [OrderTopology α] [OrderTopology β] protected theorem continuous (e : α ≃o β) : Continuous e := by - rw [‹OrderTopology β›.topology_eq_generate_intervals] - refine' continuous_generateFrom fun s hs => _ - rcases hs with ⟨a, rfl | rfl⟩ + rw [‹OrderTopology β›.topology_eq_generate_intervals, continuous_generateFrom_iff] + rintro s ⟨a, rfl | rfl⟩ · rw [e.preimage_Ioi] apply isOpen_lt' · rw [e.preimage_Iio] diff --git a/Mathlib/Topology/Bases.lean b/Mathlib/Topology/Bases.lean index c47794f8172ca..2643fbea748ed 100644 --- a/Mathlib/Topology/Bases.lean +++ b/Mathlib/Topology/Bases.lean @@ -290,9 +290,15 @@ theorem isTopologicalBasis_of_cover {ι} {U : ι → Set α} (Uo : ∀ i, IsOpen image_subset_iff.2 hvu⟩ #align topological_space.is_topological_basis_of_cover TopologicalSpace.isTopologicalBasis_of_cover +protected theorem IsTopologicalBasis.continuous_iff {β : Type*} [TopologicalSpace β] + {B : Set (Set β)} (hB : IsTopologicalBasis B) {f : α → β} : + Continuous f ↔ ∀ s ∈ B, IsOpen (f ⁻¹' s) := by + rw [hB.eq_generateFrom, continuous_generateFrom_iff] + +@[deprecated] protected theorem IsTopologicalBasis.continuous {β : Type*} [TopologicalSpace β] {B : Set (Set β)} - (hB : IsTopologicalBasis B) (f : α → β) (hf : ∀ s ∈ B, IsOpen (f ⁻¹' s)) : Continuous f := by - rw [hB.eq_generateFrom]; exact continuous_generateFrom hf + (hB : IsTopologicalBasis B) (f : α → β) (hf : ∀ s ∈ B, IsOpen (f ⁻¹' s)) : Continuous f := + hB.continuous_iff.2 hf #align topological_space.is_topological_basis.continuous TopologicalSpace.IsTopologicalBasis.continuous variable (α) diff --git a/Mathlib/Topology/CompactOpen.lean b/Mathlib/Topology/CompactOpen.lean index a93db22d0a20e..b10e139049afd 100644 --- a/Mathlib/Topology/CompactOpen.lean +++ b/Mathlib/Topology/CompactOpen.lean @@ -103,7 +103,7 @@ private theorem preimage_gen {s : Set α} {u : Set γ} : /-- C(α, -) is a functor. -/ theorem continuous_comp : Continuous (ContinuousMap.comp g : C(α, β) → C(α, γ)) := - continuous_generateFrom fun m ⟨s, hs, u, hu, hm⟩ => by + continuous_generateFrom_iff.2 fun m ⟨s, hs, u, hu, hm⟩ => by rw [hm, preimage_gen g]; exact ContinuousMap.isOpen_gen hs (hu.preimage g.2) #align continuous_map.continuous_comp ContinuousMap.continuous_comp @@ -129,7 +129,7 @@ private theorem image_gen {s : Set α} (_ : IsCompact s) {u : Set γ} (_ : IsOpe /-- C(-, γ) is a functor. -/ theorem continuous_comp_left : Continuous (fun g => g.comp f : C(β, γ) → C(α, γ)) := - continuous_generateFrom fun m ⟨s, hs, u, hu, hm⟩ => by + continuous_generateFrom_iff.2 fun m ⟨s, hs, u, hu, hm⟩ => by rw [hm, image_gen f hs hu] exact ContinuousMap.isOpen_gen (hs.image f.2) hu #align continuous_map.continuous_comp_left ContinuousMap.continuous_comp_left @@ -138,7 +138,7 @@ theorem continuous_comp_left : Continuous (fun g => g.comp f : C(β, γ) → C( locally compact. This is Prop. 9 of Chap. X, §3, №. 4 of Bourbaki's *Topologie Générale*. -/ theorem continuous_comp' [LocallyCompactSpace β] : Continuous fun x : C(α, β) × C(β, γ) => x.2.comp x.1 := - continuous_generateFrom + continuous_generateFrom_iff.2 (by rintro M ⟨K, hK, U, hU, rfl⟩ conv => @@ -338,7 +338,7 @@ theorem image_coev {y : β} (s : Set α) : coev α β y '' s = ({y} : Set β) × -- The coevaluation map β → C(α, β × α) is continuous (always). theorem continuous_coev : Continuous (coev α β) := - continuous_generateFrom <| by + continuous_generateFrom_iff.2 <| by rintro _ ⟨s, sc, u, uo, rfl⟩ rw [isOpen_iff_forall_mem_open] intro y hy diff --git a/Mathlib/Topology/Order.lean b/Mathlib/Topology/Order.lean index c0d430b56df61..7b057b93e9edd 100644 --- a/Mathlib/Topology/Order.lean +++ b/Mathlib/Topology/Order.lean @@ -81,8 +81,8 @@ theorem nhds_generateFrom {g : Set (Set α)} {a : α} : @nhds α (generateFrom g) a = ⨅ s ∈ { s | a ∈ s ∧ s ∈ g }, 𝓟 s := by letI := generateFrom g rw [nhds_def] - refine le_antisymm (biInf_mono fun s ⟨as, sg⟩ => ⟨as, .basic _ sg⟩) ?_ - refine le_iInf₂ fun s ⟨ha, hs⟩ => ?_; clear ‹s ∈ { s | a ∈ s ∧ IsOpen s }› + refine le_antisymm (biInf_mono fun s ⟨as, sg⟩ => ⟨as, .basic _ sg⟩) <| le_iInf₂ ?_ + rintro s ⟨ha, hs⟩ induction hs with | basic _ hs => exact iInf₂_le _ ⟨ha, hs⟩ | univ => exact le_top.trans_eq principal_univ.symm @@ -92,10 +92,12 @@ theorem nhds_generateFrom {g : Set (Set α)} {a : α} : exact (hS t htS hat).trans (principal_mono.2 <| subset_sUnion_of_mem htS) #align topological_space.nhds_generate_from TopologicalSpace.nhds_generateFrom -theorem tendsto_nhds_generateFrom {β : Type*} {m : α → β} {f : Filter α} {g : Set (Set β)} {b : β} - (h : ∀ s ∈ g, b ∈ s → m ⁻¹' s ∈ f) : Tendsto m f (@nhds β (generateFrom g) b) := by - rw [nhds_generateFrom] - exact tendsto_iInf.2 fun s => tendsto_iInf.2 fun ⟨hbs, hsg⟩ => tendsto_principal.2 <| h s hsg hbs +lemma tendsto_nhds_generateFrom_iff {β : Type*} {m : α → β} {f : Filter α} {g : Set (Set β)} + {b : β} : Tendsto m f (@nhds β (generateFrom g) b) ↔ ∀ s ∈ g, b ∈ s → m ⁻¹' s ∈ f := by + simp only [nhds_generateFrom, @forall_swap (b ∈ _), tendsto_iInf, mem_setOf_eq, and_imp, + tendsto_principal]; rfl + +@[deprecated] alias ⟨_, tendsto_nhds_generateFrom⟩ := tendsto_nhds_generateFrom_iff #align topological_space.tendsto_nhds_generate_from TopologicalSpace.tendsto_nhds_generateFrom /-- Construct a topology on α given the filter of neighborhoods of each point of α. -/ @@ -720,10 +722,11 @@ theorem continuous_iff_le_induced {t₁ : TopologicalSpace α} {t₂ : Topologic Iff.trans continuous_iff_coinduced_le (gc_coinduced_induced f _ _) #align continuous_iff_le_induced continuous_iff_le_induced -theorem continuous_generateFrom {t : TopologicalSpace α} {b : Set (Set β)} - (h : ∀ s ∈ b, IsOpen (f ⁻¹' s)) : - Continuous[t, generateFrom b] f := - continuous_iff_coinduced_le.2 <| le_generateFrom h +lemma continuous_generateFrom_iff {t : TopologicalSpace α} {b : Set (Set β)} : + Continuous[t, generateFrom b] f ↔ ∀ s ∈ b, IsOpen (f ⁻¹' s) := by + rw [continuous_iff_coinduced_le, le_generateFrom_iff_subset_isOpen]; rfl + +@[deprecated] alias ⟨_, continuous_generateFrom⟩ := continuous_generateFrom_iff #align continuous_generated_from continuous_generateFrom @[continuity] diff --git a/Mathlib/Topology/Order/LowerUpperTopology.lean b/Mathlib/Topology/Order/LowerUpperTopology.lean index b484799e02edb..7bfb62fc347cb 100644 --- a/Mathlib/Topology/Order/LowerUpperTopology.lean +++ b/Mathlib/Topology/Order/LowerUpperTopology.lean @@ -277,16 +277,17 @@ protected theorem isTopologicalBasis : IsTopologicalBasis (lowerBasis α) := by exact ⟨_, finite_range f, by simp_rw [biInter_range, hf, sInter_eq_iInter]⟩ #align lower_topology.is_topological_basis Topology.IsLower.isTopologicalBasis -/-- A function `f : β → α` with lower topology in the codomain is continuous provided that the -preimage of every interval `Set.Ici a` is a closed set. - -TODO: upgrade to an `iff`. -/ -lemma continuous_of_Ici [TopologicalSpace β] {f : β → α} (h : ∀ a, IsClosed (f ⁻¹' (Ici a))) : - Continuous f := by +/-- A function `f : β → α` with lower topology in the codomain is continuous +if and only if the preimage of every interval `Set.Ici a` is a closed set. +-/ +lemma continuous_iff_Ici [TopologicalSpace β] {f : β → α} : + Continuous f ↔ ∀ a, IsClosed (f ⁻¹' (Ici a)) := by obtain rfl := IsLower.topology_eq α - refine continuous_generateFrom ?_ - rintro _ ⟨a, rfl⟩ - exact (h a).isOpen_compl + simp [continuous_generateFrom_iff] + +/-- A function `f : β → α` with lower topology in the codomain is continuous provided that the +preimage of every interval `Set.Ici a` is a closed set. -/ +@[deprecated] alias ⟨_, continuous_of_Ici⟩ := continuous_iff_Ici end Preorder @@ -359,13 +360,18 @@ theorem closure_singleton (a : α) : closure {a} = Iic a := protected theorem isTopologicalBasis : IsTopologicalBasis (upperBasis α) := IsLower.isTopologicalBasis (α := αᵒᵈ) -/-- A function `f : β → α` with upper topology in the codomain is continuous provided that the -preimage of every interval `Set.Iic a` is a closed set. +/-- A function `f : β → α` with upper topology in the codomain is continuous +if and only if the preimage of every interval `Set.Iic a` is a closed set. -/ +lemma continuous_iff_Iic [TopologicalSpace β] {f : β → α} : + Continuous f ↔ ∀ a, IsClosed (f ⁻¹' (Iic a)) := + IsLower.continuous_iff_Ici (α := αᵒᵈ) -TODO: upgrade to an `iff`. -/ +/-- A function `f : β → α` with upper topology in the codomain is continuous +provided that the preimage of every interval `Set.Iic a` is a closed set. -/ +@[deprecated] lemma continuous_of_Iic [TopologicalSpace β] {f : β → α} (h : ∀ a, IsClosed (f ⁻¹' (Iic a))) : Continuous f := - IsLower.continuous_of_Ici (α := αᵒᵈ) h + continuous_iff_Iic.2 h end Preorder @@ -416,7 +422,7 @@ variable [CompleteLattice α] [CompleteLattice β] [TopologicalSpace α] [IsLowe [TopologicalSpace β] [IsLower β] protected lemma _root_.sInfHom.continuous (f : sInfHom α β) : Continuous f := by - refine IsLower.continuous_of_Ici fun b => ?_ + refine IsLower.continuous_iff_Ici.2 fun b => ?_ convert isClosed_Ici (a := sInf <| f ⁻¹' Ici b) refine' Subset.antisymm (fun a => sInf_le) fun a ha => le_trans _ <| OrderHomClass.mono (f : α →o β) ha From de998ec5efecfd02da10d832018622a6488a6565 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Dec 2023 02:03:07 +0000 Subject: [PATCH 166/353] chore(Algebra/Operations): golf a proof (#9201) Golf the proof of `Submodule.smul_singleton` and rename it to `Submodule.singleton_smul`. --- Mathlib/Algebra/Algebra/Operations.lean | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Mathlib/Algebra/Algebra/Operations.lean b/Mathlib/Algebra/Algebra/Operations.lean index 4b6ddcd580de4..b21a322ed6707 100644 --- a/Mathlib/Algebra/Algebra/Operations.lean +++ b/Mathlib/Algebra/Algebra/Operations.lean @@ -670,19 +670,12 @@ theorem smul_le_smul {s t : SetSemiring A} {M N : Submodule R A} mul_le_mul (span_mono h₁) h₂ #align submodule.smul_le_smul Submodule.smul_le_smul -theorem smul_singleton (a : A) (M : Submodule R A) : +theorem singleton_smul (a : A) (M : Submodule R A) : Set.up ({a} : Set A) • M = M.map (LinearMap.mulLeft R a) := by conv_lhs => rw [← span_eq M] - change span _ _ * span _ _ = _ - rw [span_mul_span] - apply le_antisymm - · rw [span_le] - rintro _ ⟨b, m, hb, hm, rfl⟩ - rw [SetLike.mem_coe, mem_map, Set.mem_singleton_iff.mp hb] - exact ⟨m, hm, rfl⟩ - · rintro _ ⟨m, hm, rfl⟩ - exact subset_span ⟨a, m, Set.mem_singleton a, hm, rfl⟩ -#align submodule.smul_singleton Submodule.smul_singleton + rw [smul_def, SetSemiring.down_up, span_mul_span, singleton_mul] + exact (map (LinearMap.mulLeft R a) M).span_eq +#align submodule.smul_singleton Submodule.singleton_smul section Quotient From 60af8c9a5a62728c41542c4fb5b472807bbb45c6 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Mon, 25 Dec 2023 12:41:35 +0000 Subject: [PATCH 167/353] feat: add some missing API lemmas about `Nat.properDivisors` and `Nat.primeFactors` (#8858) Co-authored-by: Yury G. Kudryashov --- Mathlib/Data/Nat/PrimeFin.lean | 5 +++++ Mathlib/NumberTheory/Divisors.lean | 34 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/Mathlib/Data/Nat/PrimeFin.lean b/Mathlib/Data/Nat/PrimeFin.lean index 1a2efccc29f54..50f85ef00af29 100644 --- a/Mathlib/Data/Nat/PrimeFin.lean +++ b/Mathlib/Data/Nat/PrimeFin.lean @@ -67,6 +67,11 @@ lemma le_of_mem_primeFactors (h : p ∈ n.primeFactors) : p ≤ n := exact Nonempty.ne_empty $ ⟨_, mem_primeFactors.2 ⟨hp, hpn, hn.1⟩⟩ · rintro (rfl | rfl) <;> simp +@[simp] +lemma nonempty_primeFactors {n : ℕ} : n.primeFactors.Nonempty ↔ 1 < n := by + rw [← not_iff_not, Finset.not_nonempty_iff_eq_empty, primeFactors_eq_empty, not_lt, + Nat.le_one_iff_eq_zero_or_eq_one] + @[simp] protected lemma Prime.primeFactors (hp : p.Prime) : p.primeFactors = {p} := by simp [Nat.primeFactors, factors_prime hp] diff --git a/Mathlib/NumberTheory/Divisors.lean b/Mathlib/NumberTheory/Divisors.lean index 6aaf80c8eab22..cff3ebc327baa 100644 --- a/Mathlib/NumberTheory/Divisors.lean +++ b/Mathlib/NumberTheory/Divisors.lean @@ -172,6 +172,14 @@ theorem properDivisors_zero : properDivisors 0 = ∅ := by simp #align nat.proper_divisors_zero Nat.properDivisors_zero +@[simp] +lemma nonempty_divisors : (divisors n).Nonempty ↔ n ≠ 0 := + ⟨fun ⟨m, hm⟩ hn ↦ by simp [hn] at hm, fun hn ↦ ⟨1, one_mem_divisors.2 hn⟩⟩ + +@[simp] +lemma divisors_eq_empty : divisors n = ∅ ↔ n = 0 := + not_nonempty_iff_eq_empty.symm.trans nonempty_divisors.not_left + theorem properDivisors_subset_divisors : properDivisors n ⊆ divisors n := filter_subset_filter _ <| Ico_subset_Ico_right n.le_succ #align nat.proper_divisors_subset_divisors Nat.properDivisors_subset_divisors @@ -208,6 +216,32 @@ lemma sup_divisors_id (n : ℕ) : n.divisors.sup id = n := by · apply zero_le · exact Finset.le_sup (f := id) <| mem_divisors_self n hn +lemma one_lt_of_mem_properDivisors {m n : ℕ} (h : m ∈ n.properDivisors) : 1 < n := + lt_of_le_of_lt (pos_of_mem_properDivisors h) (mem_properDivisors.1 h).2 + +lemma one_lt_div_of_mem_properDivisors {m n : ℕ} (h : m ∈ n.properDivisors) : + 1 < n / m := by + obtain ⟨h_dvd, h_lt⟩ := mem_properDivisors.mp h + rwa [Nat.lt_div_iff_mul_lt h_dvd, mul_one] + +/-- See also `Nat.mem_properDivisors`. -/ +lemma mem_properDivisors_iff_exists {m n : ℕ} (hn : n ≠ 0) : + m ∈ n.properDivisors ↔ ∃ k > 1, n = m * k := by + refine ⟨fun h ↦ ⟨n / m, one_lt_div_of_mem_properDivisors h, ?_⟩, ?_⟩ + · exact (Nat.mul_div_cancel' (mem_properDivisors.mp h).1).symm + · rintro ⟨k, hk, rfl⟩ + rw [mul_ne_zero_iff] at hn + exact mem_properDivisors.mpr ⟨⟨k, rfl⟩, lt_mul_of_one_lt_right (Nat.pos_of_ne_zero hn.1) hk⟩ + +@[simp] +lemma nonempty_properDivisors : n.properDivisors.Nonempty ↔ 1 < n := + ⟨fun ⟨_m, hm⟩ ↦ one_lt_of_mem_properDivisors hm, fun hn ↦ + ⟨1, one_mem_properDivisors_iff_one_lt.2 hn⟩⟩ + +@[simp] +lemma properDivisors_eq_empty : n.properDivisors = ∅ ↔ n ≤ 1 := by + rw [← not_nonempty_iff_eq_empty, nonempty_properDivisors, not_lt] + @[simp] theorem divisorsAntidiagonal_zero : divisorsAntidiagonal 0 = ∅ := by ext From ef974f8646c0e311a0099369431445e66aff22d5 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Dec 2023 13:26:04 +0000 Subject: [PATCH 168/353] =?UTF-8?q?chore(*):=20use=20`=E2=88=83=20x=20?= =?UTF-8?q?=E2=88=88=20s,=20=5F`=20instead=20of=20`=E2=88=83=20(x)=20(=5F?= =?UTF-8?q?=20:=20x=20=E2=88=88=20s),=20=5F`=20(#9215)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up #9184 --- Archive/Imo/Imo2021Q1.lean | 6 ++-- Mathlib/Algebra/Order/Interval.lean | 2 +- .../BumpFunction/FiniteDimension.lean | 7 ++-- Mathlib/Analysis/Calculus/ContDiff/Defs.lean | 4 +-- Mathlib/Analysis/Calculus/TangentCone.lean | 3 +- Mathlib/Analysis/Complex/OpenMapping.lean | 2 +- .../Analysis/Distribution/SchwartzSpace.lean | 3 +- Mathlib/Analysis/InnerProductSpace/Basic.lean | 8 ++--- .../SpecialFunctions/ImproperIntegrals.lean | 4 +-- .../Analysis/SpecialFunctions/Stirling.lean | 8 ++--- .../Trigonometric/Bounds.lean | 2 +- .../Trigonometric/Complex.lean | 2 +- Mathlib/Data/DFinsupp/Basic.lean | 5 +-- Mathlib/Data/Finset/PiInduction.lean | 4 +-- Mathlib/Data/Finset/Powerset.lean | 16 ++++----- Mathlib/Data/Finsupp/BigOperators.lean | 6 ++-- Mathlib/Data/Finsupp/Defs.lean | 6 ++-- Mathlib/Data/Fintype/BigOperators.lean | 4 +-- Mathlib/Data/Fintype/Perm.lean | 2 +- Mathlib/Data/Int/Order/Basic.lean | 2 +- Mathlib/Data/Nat/EvenOddRec.lean | 4 +-- Mathlib/Data/Nat/Factorization/PrimePow.lean | 2 +- Mathlib/Data/Nat/Pow.lean | 2 +- Mathlib/Data/Part.lean | 2 +- Mathlib/GroupTheory/SchurZassenhaus.lean | 7 ++-- .../AffineSpace/Combination.lean | 34 +++++++++---------- Mathlib/LinearAlgebra/Finsupp.lean | 4 +-- Mathlib/LinearAlgebra/Span.lean | 4 +-- Mathlib/MeasureTheory/Covering/Vitali.lean | 8 ++--- .../ConditionalExpectation/AEMeasurable.lean | 2 +- .../Function/ConvergenceInMeasure.lean | 4 +-- Mathlib/MeasureTheory/Function/LpSpace.lean | 2 +- .../Function/StronglyMeasurable/Basic.lean | 2 +- .../Group/FundamentalDomain.lean | 2 +- .../MeasureTheory/Measure/MeasureSpace.lean | 2 +- .../MeasureTheory/Measure/OuterMeasure.lean | 2 +- .../MeasureTheory/Measure/VectorMeasure.lean | 2 +- .../LegendreSymbol/JacobiSymbol.lean | 4 +-- Mathlib/NumberTheory/Padics/PadicNumbers.lean | 2 +- Mathlib/NumberTheory/ZetaFunction.lean | 4 +-- Mathlib/Order/CountableDenseLinearOrder.lean | 2 +- Mathlib/Order/Extension/Linear.lean | 12 +++---- Mathlib/Order/Filter/Basic.lean | 4 +-- Mathlib/Order/GaloisConnection.lean | 2 +- Mathlib/Order/Monotone/Basic.lean | 8 ++--- .../DedekindDomain/IntegralClosure.lean | 2 +- Mathlib/RingTheory/Ideal/Operations.lean | 2 +- Mathlib/RingTheory/Ideal/Over.lean | 4 +-- Mathlib/RingTheory/IntegralDomain.lean | 2 +- Mathlib/Topology/Algebra/UniformGroup.lean | 6 ++-- Mathlib/Topology/PartitionOfUnity.lean | 8 ++--- .../UniformSpace/CompactConvergence.lean | 13 ++++--- 52 files changed, 119 insertions(+), 137 deletions(-) diff --git a/Archive/Imo/Imo2021Q1.lean b/Archive/Imo/Imo2021Q1.lean index 5ed4d28285d37..dbb1f65c63224 100644 --- a/Archive/Imo/Imo2021Q1.lean +++ b/Archive/Imo/Imo2021Q1.lean @@ -82,7 +82,7 @@ theorem exists_triplet_summing_to_squares (n : ℕ) (hn : 100 ≤ n) : theorem exists_finset_3_le_card_with_pairs_summing_to_squares (n : ℕ) (hn : 100 ≤ n) : ∃ B : Finset ℕ, 2 * 1 + 1 ≤ B.card ∧ - (∀ (a) (_ : a ∈ B) (b) (_ : b ∈ B), a ≠ b → ∃ k, a + b = k ^ 2) ∧ + (∀ a ∈ B, ∀ b ∈ B, a ≠ b → ∃ k, a + b = k ^ 2) ∧ ∀ c ∈ B, n ≤ c ∧ c ≤ 2 * n := by obtain ⟨a, b, c, hna, hab, hbc, hcn, h₁, h₂, h₃⟩ := exists_triplet_summing_to_squares n hn refine' ⟨{a, b, c}, _, _, _⟩ @@ -111,8 +111,8 @@ open Imo2021Q1 theorem imo2021_q1 : ∀ n : ℕ, 100 ≤ n → ∀ (A) (_ : A ⊆ Finset.Icc n (2 * n)), - (∃ (a : _) (_ : a ∈ A) (b : _) (_ : b ∈ A), a ≠ b ∧ ∃ k : ℕ, a + b = k ^ 2) ∨ - ∃ (a : _) (_ : a ∈ Finset.Icc n (2 * n) \ A) (b : _) (_ : b ∈ Finset.Icc n (2 * n) \ A), + (∃ a ∈ A, ∃ b ∈ A, a ≠ b ∧ ∃ k : ℕ, a + b = k ^ 2) ∨ + ∃ a ∈ Finset.Icc n (2 * n) \ A, ∃ b ∈ Finset.Icc n (2 * n) \ A, a ≠ b ∧ ∃ k : ℕ, a + b = k ^ 2 := by intro n hn A hA -- For each n ∈ ℕ such that 100 ≤ n, there exists a pairwise unequal triplet {a, b, c} ⊆ [n, 2n] diff --git a/Mathlib/Algebra/Order/Interval.lean b/Mathlib/Algebra/Order/Interval.lean index f314bb0db2ab0..f28c994d162d5 100644 --- a/Mathlib/Algebra/Order/Interval.lean +++ b/Mathlib/Algebra/Order/Interval.lean @@ -319,7 +319,7 @@ namespace Interval variable [OrderedCommMonoid α] (s : Interval α) {n : ℕ} @[to_additive] -theorem bot_pow : ∀ {n : ℕ} (_ : n ≠ 0), (⊥ : Interval α) ^ n = ⊥ +theorem bot_pow : ∀ {n : ℕ}, n ≠ 0 → (⊥ : Interval α) ^ n = ⊥ | 0, h => (h rfl).elim | Nat.succ n, _ => bot_mul (⊥ ^ n) #align interval.bot_pow Interval.bot_pow diff --git a/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean b/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean index 5675c4aa664ed..8d18ddf3b6070 100644 --- a/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean +++ b/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean @@ -110,11 +110,10 @@ theorem IsOpen.exists_smooth_support_eq {s : Set E} (hs : IsOpen s) : · exact hT let g : ℕ → E → ℝ := fun n => (g0 n).1 have g_s : ∀ n, support (g n) ⊆ s := fun n => (g0 n).2.1 - have s_g : ∀ x ∈ s, ∃ n, x ∈ support (g n) := by - intro x hx + have s_g : ∀ x ∈ s, ∃ n, x ∈ support (g n) := fun x hx ↦ by rw [← hT] at hx - obtain ⟨i, iT, hi⟩ : ∃ (i : ι) (_ : i ∈ T), x ∈ support (i : E → ℝ) := by - simpa only [mem_iUnion] using hx + obtain ⟨i, iT, hi⟩ : ∃ i ∈ T, x ∈ support (i : E → ℝ) := by + simpa only [mem_iUnion, exists_prop] using hx rw [hg, mem_range] at iT rcases iT with ⟨n, hn⟩ rw [← hn] at hi diff --git a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean index 837554e04ecad..afb0c159cfd80 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean @@ -1222,8 +1222,8 @@ derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a pred structure HasFTaylorSeriesUpTo (n : ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F) : Prop where zero_eq : ∀ x, (p x 0).uncurry0 = f x - fderiv : ∀ (m : ℕ) (_ : (m : ℕ∞) < n), ∀ x, HasFDerivAt (fun y => p y m) (p x m.succ).curryLeft x - cont : ∀ (m : ℕ) (_ : (m : ℕ∞) ≤ n), Continuous fun x => p x m + fderiv : ∀ m : ℕ, (m : ℕ∞) < n → ∀ x, HasFDerivAt (fun y => p y m) (p x m.succ).curryLeft x + cont : ∀ m : ℕ, (m : ℕ∞) ≤ n → Continuous fun x => p x m #align has_ftaylor_series_up_to HasFTaylorSeriesUpTo theorem HasFTaylorSeriesUpTo.zero_eq' (h : HasFTaylorSeriesUpTo n f p) (x : E) : diff --git a/Mathlib/Analysis/Calculus/TangentCone.lean b/Mathlib/Analysis/Calculus/TangentCone.lean index dc2fc3f2b1f12..f78ccdb03a5bd 100644 --- a/Mathlib/Analysis/Calculus/TangentCone.lean +++ b/Mathlib/Analysis/Calculus/TangentCone.lean @@ -188,8 +188,7 @@ theorem mapsTo_tangentCone_pi {ι : Type*} [DecidableEq ι] {E : ι → Type*} MapsTo (LinearMap.single i : E i →ₗ[𝕜] ∀ j, E j) (tangentConeAt 𝕜 (s i) (x i)) (tangentConeAt 𝕜 (Set.pi univ s) x) := by rintro w ⟨c, d, hd, hc, hy⟩ - have : ∀ (n) (j) (_ : j ≠ i), ∃ d', x j + d' ∈ s j ∧ ‖c n • d'‖ < (1 / 2 : ℝ) ^ n := by - intro n j hj + have : ∀ n, ∀ j ≠ i, ∃ d', x j + d' ∈ s j ∧ ‖c n • d'‖ < (1 / 2 : ℝ) ^ n := fun n j hj ↦ by rcases mem_closure_iff_nhds.1 (hi j hj) _ (eventually_nhds_norm_smul_sub_lt (c n) (x j) (pow_pos one_half_pos n)) with ⟨z, hz, hzs⟩ diff --git a/Mathlib/Analysis/Complex/OpenMapping.lean b/Mathlib/Analysis/Complex/OpenMapping.lean index e4582680ef778..0b09631c6f9ce 100644 --- a/Mathlib/Analysis/Complex/OpenMapping.lean +++ b/Mathlib/Analysis/Complex/OpenMapping.lean @@ -161,7 +161,7 @@ theorem AnalyticAt.eventually_constant_or_nhds_le_map_nhds {z₀ : E} (hg : Anal is analytic on a connected set `U`, then either it is constant on `U`, or it is open on `U` (in the sense that it maps any open set contained in `U` to an open set in `ℂ`). -/ theorem AnalyticOn.is_constant_or_isOpen (hg : AnalyticOn ℂ g U) (hU : IsPreconnected U) : - (∃ w, ∀ z ∈ U, g z = w) ∨ ∀ (s) (_ : s ⊆ U), IsOpen s → IsOpen (g '' s) := by + (∃ w, ∀ z ∈ U, g z = w) ∨ ∀ s ⊆ U, IsOpen s → IsOpen (g '' s) := by by_cases h : ∃ z₀ ∈ U, ∀ᶠ z in 𝓝 z₀, g z = g z₀ · obtain ⟨z₀, hz₀, h⟩ := h exact Or.inl ⟨g z₀, hg.eqOn_of_preconnected_of_eventuallyEq analyticOn_const hU hz₀ h⟩ diff --git a/Mathlib/Analysis/Distribution/SchwartzSpace.lean b/Mathlib/Analysis/Distribution/SchwartzSpace.lean index 87a3d62095514..6ae4730f62e0f 100644 --- a/Mathlib/Analysis/Distribution/SchwartzSpace.lean +++ b/Mathlib/Analysis/Distribution/SchwartzSpace.lean @@ -616,8 +616,7 @@ def _root_.Function.HasTemperateGrowth (f : E → F) : Prop := theorem _root_.Function.HasTemperateGrowth.norm_iteratedFDeriv_le_uniform_aux {f : E → F} (hf_temperate : f.HasTemperateGrowth) (n : ℕ) : - ∃ (k : ℕ) (C : ℝ) (_ : 0 ≤ C), ∀ (N : ℕ) (_ : N ≤ n) (x : E), - ‖iteratedFDeriv ℝ N f x‖ ≤ C * (1 + ‖x‖) ^ k := by + ∃ (k : ℕ) (C : ℝ), 0 ≤ C ∧ ∀ N ≤ n, ∀ x : E, ‖iteratedFDeriv ℝ N f x‖ ≤ C * (1 + ‖x‖) ^ k := by choose k C f using hf_temperate.2 use (Finset.range (n + 1)).sup k let C' := max (0 : ℝ) ((Finset.range (n + 1)).sup' (by simp) C) diff --git a/Mathlib/Analysis/InnerProductSpace/Basic.lean b/Mathlib/Analysis/InnerProductSpace/Basic.lean index ad44efff83256..15dea535bc5e5 100644 --- a/Mathlib/Analysis/InnerProductSpace/Basic.lean +++ b/Mathlib/Analysis/InnerProductSpace/Basic.lean @@ -952,11 +952,11 @@ theorem orthonormal_sUnion_of_directed {s : Set (Set E)} (hs : DirectedOn (· /-- Given an orthonormal set `v` of vectors in `E`, there exists a maximal orthonormal set containing it. -/ theorem exists_maximal_orthonormal {s : Set E} (hs : Orthonormal 𝕜 (Subtype.val : s → E)) : - ∃ (w : _) (_hw : w ⊇ s), Orthonormal 𝕜 (Subtype.val : w → E) ∧ - ∀ (u) (_hu : u ⊇ w), Orthonormal 𝕜 (Subtype.val : u → E) → u = w := by + ∃ w ⊇ s, Orthonormal 𝕜 (Subtype.val : w → E) ∧ + ∀ u ⊇ w, Orthonormal 𝕜 (Subtype.val : u → E) → u = w := by have := zorn_subset_nonempty { b | Orthonormal 𝕜 (Subtype.val : b → E) } ?_ _ hs - obtain ⟨b, bi, sb, h⟩ := this - · refine' ⟨b, sb, bi, _⟩ + · obtain ⟨b, bi, sb, h⟩ := this + refine' ⟨b, sb, bi, _⟩ exact fun u hus hu => h u hu hus · refine' fun c hc cc _c0 => ⟨⋃₀ c, _, _⟩ · exact orthonormal_sUnion_of_directed cc.directedOn fun x xc => hc xc diff --git a/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean b/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean index 3eebe992bab84..c145ba886127f 100644 --- a/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean @@ -61,7 +61,7 @@ theorem integral_exp_neg_Ioi_zero : (∫ x : ℝ in Ioi 0, exp (-x)) = 1 := by /-- If `0 < c`, then `(λ t : ℝ, t ^ a)` is integrable on `(c, ∞)` for all `a < -1`. -/ theorem integrableOn_Ioi_rpow_of_lt {a : ℝ} (ha : a < -1) {c : ℝ} (hc : 0 < c) : IntegrableOn (fun t : ℝ => t ^ a) (Ioi c) := by - have hd : ∀ (x : ℝ) (_ : x ∈ Ici c), HasDerivAt (fun t => t ^ (a + 1) / (a + 1)) (x ^ a) x := by + have hd : ∀ x ∈ Ici c, HasDerivAt (fun t => t ^ (a + 1) / (a + 1)) (x ^ a) x := by intro x hx -- Porting note: helped `convert` with explicit arguments convert (hasDerivAt_rpow_const (p := a + 1) (Or.inl (hc.trans_le hx).ne')).div_const _ using 1 @@ -105,7 +105,7 @@ theorem setIntegral_Ioi_zero_rpow (s : ℝ) : ∫ x in Ioi (0 : ℝ), x ^ s = 0 theorem integral_Ioi_rpow_of_lt {a : ℝ} (ha : a < -1) {c : ℝ} (hc : 0 < c) : ∫ t : ℝ in Ioi c, t ^ a = -c ^ (a + 1) / (a + 1) := by - have hd : ∀ (x : ℝ) (_ : x ∈ Ici c), HasDerivAt (fun t => t ^ (a + 1) / (a + 1)) (x ^ a) x := by + have hd : ∀ x ∈ Ici c, HasDerivAt (fun t => t ^ (a + 1) / (a + 1)) (x ^ a) x := by intro x hx convert (hasDerivAt_rpow_const (p := a + 1) (Or.inl (hc.trans_le hx).ne')).div_const _ using 1 field_simp [show a + 1 ≠ 0 from ne_of_lt (by linarith), mul_comm] diff --git a/Mathlib/Analysis/SpecialFunctions/Stirling.lean b/Mathlib/Analysis/SpecialFunctions/Stirling.lean index 695e5114d1e7c..cc0e9e7df53c8 100644 --- a/Mathlib/Analysis/SpecialFunctions/Stirling.lean +++ b/Mathlib/Analysis/SpecialFunctions/Stirling.lean @@ -88,11 +88,9 @@ theorem log_stirlingSeq_diff_hasSum (m : ℕ) : push_cast field_simp ring - · have h : ∀ (x : ℝ) (_ : x ≠ 0), 1 + x⁻¹ = (x + 1) / x := by - intro x hx; rw [_root_.add_div, div_self hx, inv_eq_one_div] - simp (disch := norm_cast <;> apply_rules [mul_ne_zero, succ_ne_zero, factorial_ne_zero, - exp_ne_zero]) only [log_stirlingSeq_formula, log_div, log_mul, log_exp, factorial_succ, - cast_mul, cast_succ, cast_zero, range_one, sum_singleton, h] + · have h : ∀ x ≠ (0 : ℝ), 1 + x⁻¹ = (x + 1) / x := fun x hx ↦ by field_simp [hx] + simp (disch := positivity) only [log_stirlingSeq_formula, log_div, log_mul, log_exp, + factorial_succ, cast_mul, cast_succ, cast_zero, range_one, sum_singleton, h] ring #align stirling.log_stirling_seq_diff_has_sum Stirling.log_stirlingSeq_diff_hasSum diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean index f14557d73a791..f2787742531fd 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean @@ -123,7 +123,7 @@ theorem le_tan {x : ℝ} (h1 : 0 ≤ x) (h2 : x < π / 2) : x ≤ tan x := by theorem cos_lt_one_div_sqrt_sq_add_one {x : ℝ} (hx1 : -(3 * π / 2) ≤ x) (hx2 : x ≤ 3 * π / 2) (hx3 : x ≠ 0) : cos x < ↑1 / sqrt (x ^ 2 + 1) := by - suffices ∀ {y : ℝ} (_ : 0 < y) (_ : y ≤ 3 * π / 2), cos y < ↑1 / sqrt (y ^ 2 + 1) by + suffices ∀ {y : ℝ}, 0 < y → y ≤ 3 * π / 2 → cos y < ↑1 / sqrt (y ^ 2 + 1) by rcases lt_or_lt_iff_ne.mpr hx3.symm with ⟨h⟩ · exact this h hx2 · convert this (by linarith : 0 < -x) (by linarith) using 1 diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean index 65f6b99dba6b4..11ce2a52ad88a 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean @@ -168,7 +168,7 @@ theorem cos_eq_iff_quadratic {z w : ℂ} : theorem cos_surjective : Function.Surjective cos := by intro x - obtain ⟨w, w₀, hw⟩ : ∃ (w : _) (_ : w ≠ 0), 1 * w * w + -2 * x * w + 1 = 0 := by + obtain ⟨w, w₀, hw⟩ : ∃ w ≠ 0, 1 * w * w + -2 * x * w + 1 = 0 := by rcases exists_quadratic_eq_zero one_ne_zero ⟨_, (cpow_nat_inv_pow _ two_ne_zero).symm.trans <| pow_two _⟩ with ⟨w, hw⟩ diff --git a/Mathlib/Data/DFinsupp/Basic.lean b/Mathlib/Data/DFinsupp/Basic.lean index e371a7622f798..ab6ca2fbb9707 100644 --- a/Mathlib/Data/DFinsupp/Basic.lean +++ b/Mathlib/Data/DFinsupp/Basic.lean @@ -1190,10 +1190,7 @@ instance decidableZero : DecidablePred (Eq (0 : Π₀ i, β i)) := fun _ => decidable_of_iff _ <| support_eq_empty.trans eq_comm #align dfinsupp.decidable_zero DFinsupp.decidableZero -/- ./././Mathport/Syntax/Translate/Basic.lean:632:2: - warning: expanding binder collection (i «expr ∉ » s) -/ -theorem support_subset_iff {s : Set ι} {f : Π₀ i, β i} : - ↑f.support ⊆ s ↔ ∀ (i) (_ : i ∉ s), f i = 0 := by +theorem support_subset_iff {s : Set ι} {f : Π₀ i, β i} : ↑f.support ⊆ s ↔ ∀ i ∉ s, f i = 0 := by simp [Set.subset_def]; exact forall_congr' fun i => not_imp_comm #align dfinsupp.support_subset_iff DFinsupp.support_subset_iff diff --git a/Mathlib/Data/Finset/PiInduction.lean b/Mathlib/Data/Finset/PiInduction.lean index 053908fcc912a..89d485a353e17 100644 --- a/Mathlib/Data/Finset/PiInduction.lean +++ b/Mathlib/Data/Finset/PiInduction.lean @@ -71,9 +71,7 @@ maps provided that it is true on `fun _ ↦ ∅` and for any function `g : ∀ i See also `Finset.induction_on_pi_max` and `Finset.induction_on_pi_min` for specialized versions that require `∀ i, LinearOrder (α i)`. -/ theorem induction_on_pi {p : (∀ i, Finset (α i)) → Prop} (f : ∀ i, Finset (α i)) (h0 : p fun _ ↦ ∅) - (step : - ∀ (g : ∀ i, Finset (α i)) (i : ι) (x : α i) (_ : x ∉ g i), - p g → p (update g i (insert x (g i)))) : + (step : ∀ (g : ∀ i, Finset (α i)) (i : ι), ∀ x ∉ g i, p g → p (update g i (insert x (g i)))) : p f := induction_on_pi_of_choice (fun _ x s ↦ x ∉ s) (fun _ s ⟨x, hx⟩ ↦ ⟨x, hx, not_mem_erase x s⟩) f h0 step diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean index 2415b0408eb2a..5ab8d4832e8ab 100644 --- a/Mathlib/Data/Finset/Powerset.lean +++ b/Mathlib/Data/Finset/Powerset.lean @@ -129,14 +129,14 @@ instance decidableForallOfDecidableSubsets {s : Finset α} {p : ∀ t ⊆ s, Pro /-- A version of `Finset.decidableExistsOfDecidableSubsets` with a non-dependent `p`. Typeclass inference cannot find `hu` here, so this is not an instance. -/ def decidableExistsOfDecidableSubsets' {s : Finset α} {p : Finset α → Prop} - (hu : ∀ (t) (_h : t ⊆ s), Decidable (p t)) : Decidable (∃ (t : _) (_h : t ⊆ s), p t) := + (hu : ∀ t ⊆ s, Decidable (p t)) : Decidable (∃ (t : _) (_h : t ⊆ s), p t) := @Finset.decidableExistsOfDecidableSubsets _ _ _ hu #align finset.decidable_exists_of_decidable_subsets' Finset.decidableExistsOfDecidableSubsets' /-- A version of `Finset.decidableForallOfDecidableSubsets` with a non-dependent `p`. Typeclass inference cannot find `hu` here, so this is not an instance. -/ def decidableForallOfDecidableSubsets' {s : Finset α} {p : Finset α → Prop} - (hu : ∀ (t) (_h : t ⊆ s), Decidable (p t)) : Decidable (∀ (t) (_h : t ⊆ s), p t) := + (hu : ∀ t ⊆ s, Decidable (p t)) : Decidable (∀ t ⊆ s, p t) := @Finset.decidableForallOfDecidableSubsets _ _ _ hu #align finset.decidable_forall_of_decidable_subsets' Finset.decidableForallOfDecidableSubsets' @@ -161,15 +161,15 @@ theorem empty_mem_ssubsets {s : Finset α} (h : s.Nonempty) : ∅ ∈ s.ssubsets exact ⟨empty_subset s, h.ne_empty.symm⟩ #align finset.empty_mem_ssubsets Finset.empty_mem_ssubsets /-- For predicate `p` decidable on ssubsets, it is decidable whether `p` holds for any ssubset. -/ -instance decidableExistsOfDecidableSSubsets {s : Finset α} {p : ∀ (t) (_ : t ⊂ s), Prop} - [∀ (t) (h : t ⊂ s), Decidable (p t h)] : Decidable (∃ t h, p t h) := +instance decidableExistsOfDecidableSSubsets {s : Finset α} {p : ∀ t ⊂ s, Prop} + [∀ t h, Decidable (p t h)] : Decidable (∃ t h, p t h) := decidable_of_iff (∃ (t : _) (hs : t ∈ s.ssubsets), p t (mem_ssubsets.1 hs)) ⟨fun ⟨t, _, hp⟩ => ⟨t, _, hp⟩, fun ⟨t, hs, hp⟩ => ⟨t, mem_ssubsets.2 hs, hp⟩⟩ #align finset.decidable_exists_of_decidable_ssubsets Finset.decidableExistsOfDecidableSSubsets /-- For predicate `p` decidable on ssubsets, it is decidable whether `p` holds for every ssubset. -/ -instance decidableForallOfDecidableSSubsets {s : Finset α} {p : ∀ (t) (_ : t ⊂ s), Prop} - [∀ (t) (h : t ⊂ s), Decidable (p t h)] : Decidable (∀ t h, p t h) := +instance decidableForallOfDecidableSSubsets {s : Finset α} {p : ∀ t ⊂ s, Prop} + [∀ t h, Decidable (p t h)] : Decidable (∀ t h, p t h) := decidable_of_iff (∀ (t) (h : t ∈ s.ssubsets), p t (mem_ssubsets.1 h)) ⟨fun h t hs => h t (mem_ssubsets.2 hs), fun h _ _ => h _ _⟩ #align finset.decidable_forall_of_decidable_ssubsets Finset.decidableForallOfDecidableSSubsets @@ -177,14 +177,14 @@ instance decidableForallOfDecidableSSubsets {s : Finset α} {p : ∀ (t) (_ : t /-- A version of `Finset.decidableExistsOfDecidableSSubsets` with a non-dependent `p`. Typeclass inference cannot find `hu` here, so this is not an instance. -/ def decidableExistsOfDecidableSSubsets' {s : Finset α} {p : Finset α → Prop} - (hu : ∀ (t) (_h : t ⊂ s), Decidable (p t)) : Decidable (∃ (t : _) (_h : t ⊂ s), p t) := + (hu : ∀ t ⊂ s, Decidable (p t)) : Decidable (∃ (t : _) (_h : t ⊂ s), p t) := @Finset.decidableExistsOfDecidableSSubsets _ _ _ _ hu #align finset.decidable_exists_of_decidable_ssubsets' Finset.decidableExistsOfDecidableSSubsets' /-- A version of `Finset.decidableForallOfDecidableSSubsets` with a non-dependent `p`. Typeclass inference cannot find `hu` here, so this is not an instance. -/ def decidableForallOfDecidableSSubsets' {s : Finset α} {p : Finset α → Prop} - (hu : ∀ (t) (_h : t ⊂ s), Decidable (p t)) : Decidable (∀ (t) (_h : t ⊂ s), p t) := + (hu : ∀ t ⊂ s, Decidable (p t)) : Decidable (∀ t ⊂ s, p t) := @Finset.decidableForallOfDecidableSSubsets _ _ _ _ hu #align finset.decidable_forall_of_decidable_ssubsets' Finset.decidableForallOfDecidableSSubsets' diff --git a/Mathlib/Data/Finsupp/BigOperators.lean b/Mathlib/Data/Finsupp/BigOperators.lean index fe21c6fd43723..71e10eb0d3dba 100644 --- a/Mathlib/Data/Finsupp/BigOperators.lean +++ b/Mathlib/Data/Finsupp/BigOperators.lean @@ -57,7 +57,7 @@ theorem Finset.support_sum_subset [AddCommMonoid M] (s : Finset (ι →₀ M)) : #align finset.support_sum_subset Finset.support_sum_subset theorem List.mem_foldr_sup_support_iff [Zero M] {l : List (ι →₀ M)} {x : ι} : - x ∈ l.foldr (Finsupp.support · ⊔ ·) ∅ ↔ ∃ (f : ι →₀ M) (_ : f ∈ l), x ∈ f.support := by + x ∈ l.foldr (Finsupp.support · ⊔ ·) ∅ ↔ ∃ f ∈ l, x ∈ f.support := by simp only [Finset.sup_eq_union, List.foldr_map, Finsupp.mem_support_iff, exists_prop] induction' l with hd tl IH · simp @@ -66,14 +66,14 @@ theorem List.mem_foldr_sup_support_iff [Zero M] {l : List (ι →₀ M)} {x : ι #align list.mem_foldr_sup_support_iff List.mem_foldr_sup_support_iff theorem Multiset.mem_sup_map_support_iff [Zero M] {s : Multiset (ι →₀ M)} {x : ι} : - x ∈ (s.map Finsupp.support).sup ↔ ∃ (f : ι →₀ M) (_ : f ∈ s), x ∈ f.support := + x ∈ (s.map Finsupp.support).sup ↔ ∃ f ∈ s, x ∈ f.support := Quot.inductionOn s fun _ ↦ by simpa only [Multiset.quot_mk_to_coe'', Multiset.coe_map, Multiset.sup_coe, List.foldr_map] using List.mem_foldr_sup_support_iff #align multiset.mem_sup_map_support_iff Multiset.mem_sup_map_support_iff theorem Finset.mem_sup_support_iff [Zero M] {s : Finset (ι →₀ M)} {x : ι} : - x ∈ s.sup Finsupp.support ↔ ∃ (f : ι →₀ M) (_ : f ∈ s), x ∈ f.support := + x ∈ s.sup Finsupp.support ↔ ∃ f ∈ s, x ∈ f.support := Multiset.mem_sup_map_support_iff #align finset.mem_sup_support_iff Finset.mem_sup_support_iff diff --git a/Mathlib/Data/Finsupp/Defs.lean b/Mathlib/Data/Finsupp/Defs.lean index aa394fb687f5c..0e254c3be2776 100644 --- a/Mathlib/Data/Finsupp/Defs.lean +++ b/Mathlib/Data/Finsupp/Defs.lean @@ -236,7 +236,7 @@ theorem finite_support (f : α →₀ M) : Set.Finite (Function.support f) := /- ./././Mathport/Syntax/Translate/Basic.lean:632:2: warning: expanding binder collection (a «expr ∉ » s) -/ theorem support_subset_iff {s : Set α} {f : α →₀ M} : - ↑f.support ⊆ s ↔ ∀ (a) (_ : a ∉ s), f a = 0 := by + ↑f.support ⊆ s ↔ ∀ a ∉ s, f a = 0 := by simp only [Set.subset_def, mem_coe, mem_support_iff]; exact forall_congr' fun a => not_imp_comm #align finsupp.support_subset_iff Finsupp.support_subset_iff @@ -468,7 +468,7 @@ theorem support_eq_singleton {f : α →₀ M} {a : α} : /- ./././Mathport/Syntax/Translate/Basic.lean:632:2: warning: expanding binder collection (b «expr ≠ » 0) -/ theorem support_eq_singleton' {f : α →₀ M} {a : α} : - f.support = {a} ↔ ∃ (b : _) (_ : b ≠ 0), f = single a b := + f.support = {a} ↔ ∃ b ≠ 0, f = single a b := ⟨fun h => let h := support_eq_singleton.1 h ⟨_, h.1, h.2⟩, @@ -482,7 +482,7 @@ theorem card_support_eq_one {f : α →₀ M} : card f.support = 1 ↔ ∃ a, f /- ./././Mathport/Syntax/Translate/Basic.lean:632:2: warning: expanding binder collection (b «expr ≠ » 0) -/ theorem card_support_eq_one' {f : α →₀ M} : - card f.support = 1 ↔ ∃ (a : _) (b : _) (_ : b ≠ 0), f = single a b := by + card f.support = 1 ↔ ∃ a, ∃ b ≠ 0, f = single a b := by simp only [card_eq_one, support_eq_singleton'] #align finsupp.card_support_eq_one' Finsupp.card_support_eq_one' diff --git a/Mathlib/Data/Fintype/BigOperators.lean b/Mathlib/Data/Fintype/BigOperators.lean index 7466691f6c9a2..da93fd27a5c40 100644 --- a/Mathlib/Data/Fintype/BigOperators.lean +++ b/Mathlib/Data/Fintype/BigOperators.lean @@ -77,7 +77,7 @@ theorem prod_congr (f g : α → M) (h : ∀ a, f a = g a) : ∏ a, f a = ∏ a, #align fintype.sum_congr Fintype.sum_congr @[to_additive] -theorem prod_eq_single {f : α → M} (a : α) (h : ∀ (x) (_ : x ≠ a), f x = 1) : ∏ x, f x = f a := +theorem prod_eq_single {f : α → M} (a : α) (h : ∀ x ≠ a, f x = 1) : ∏ x, f x = f a := Finset.prod_eq_single a (fun x _ hx => h x hx) fun ha => (ha (Finset.mem_univ a)).elim #align fintype.prod_eq_single Fintype.prod_eq_single #align fintype.sum_eq_single Fintype.sum_eq_single @@ -267,7 +267,7 @@ theorem Fintype.prod_fiberwise [Fintype α] [DecidableEq β] [Fintype β] [CommM #align fintype.sum_fiberwise Fintype.sum_fiberwise nonrec theorem Fintype.prod_dite [Fintype α] {p : α → Prop} [DecidablePred p] [CommMonoid β] - (f : ∀ (a : α) (_ha : p a), β) (g : ∀ (a : α) (_ha : ¬p a), β) : + (f : ∀ a, p a → β) (g : ∀ a, ¬p a → β) : (∏ a, dite (p a) (f a) (g a)) = (∏ a : { a // p a }, f a a.2) * ∏ a : { a // ¬p a }, g a a.2 := by simp only [prod_dite, attach_eq_univ] diff --git a/Mathlib/Data/Fintype/Perm.lean b/Mathlib/Data/Fintype/Perm.lean index 3f65c03373565..f667de918bc68 100644 --- a/Mathlib/Data/Fintype/Perm.lean +++ b/Mathlib/Data/Fintype/Perm.lean @@ -99,7 +99,7 @@ theorem mem_permsOfList_iff {l : List α} {f : Perm α} : ⟨mem_of_mem_permsOfList, mem_permsOfList_of_mem⟩ #align mem_perms_of_list_iff mem_permsOfList_iff -theorem nodup_permsOfList : ∀ {l : List α} (_ : l.Nodup), (permsOfList l).Nodup +theorem nodup_permsOfList : ∀ {l : List α}, l.Nodup → (permsOfList l).Nodup | [], _ => by simp [permsOfList] | a :: l, hl => by have hl' : l.Nodup := hl.of_cons diff --git a/Mathlib/Data/Int/Order/Basic.lean b/Mathlib/Data/Int/Order/Basic.lean index 16546f32a5770..1af07234505af 100644 --- a/Mathlib/Data/Int/Order/Basic.lean +++ b/Mathlib/Data/Int/Order/Basic.lean @@ -347,7 +347,7 @@ theorem emod_two_eq_zero_or_one (n : ℤ) : n % 2 = 0 ∨ n % 2 = 1 := #align int.mul_div_cancel' Int.mul_ediv_cancel' -theorem ediv_dvd_ediv : ∀ {a b c : ℤ} (_ : a ∣ b) (_ : b ∣ c), b / a ∣ c / a +theorem ediv_dvd_ediv : ∀ {a b c : ℤ}, a ∣ b → b ∣ c → b / a ∣ c / a | a, _, _, ⟨b, rfl⟩, ⟨c, rfl⟩ => if az : a = 0 then by simp [az] else by diff --git a/Mathlib/Data/Nat/EvenOddRec.lean b/Mathlib/Data/Nat/EvenOddRec.lean index a87e3148955f9..6036ef01b99e4 100644 --- a/Mathlib/Data/Nat/EvenOddRec.lean +++ b/Mathlib/Data/Nat/EvenOddRec.lean @@ -21,8 +21,8 @@ This is nothing more than a wrapper around `Nat.binaryRec`, to avoid having to s dealing with `bit0` and `bit1`. -/ @[elab_as_elim] -def evenOddRec {P : ℕ → Sort*} (h0 : P 0) (h_even : ∀ (n) (_ : P n), P (2 * n)) - (h_odd : ∀ (n) (_ : P n), P (2 * n + 1)) (n : ℕ) : P n := +def evenOddRec {P : ℕ → Sort*} (h0 : P 0) (h_even : ∀ n, P n → P (2 * n)) + (h_odd : ∀ n, P n → P (2 * n + 1)) (n : ℕ) : P n := binaryRec h0 (fun | false, i, hi => (bit0_val i ▸ h_even i hi : P (bit0 i)) | true, i, hi => (bit1_val i ▸ h_odd i hi : P (bit1 i))) n diff --git a/Mathlib/Data/Nat/Factorization/PrimePow.lean b/Mathlib/Data/Nat/Factorization/PrimePow.lean index b0243819d2132..4a076491ff7d8 100644 --- a/Mathlib/Data/Nat/Factorization/PrimePow.lean +++ b/Mathlib/Data/Nat/Factorization/PrimePow.lean @@ -57,7 +57,7 @@ theorem isPrimePow_iff_factorization_eq_single {n : ℕ} : theorem isPrimePow_iff_card_primeFactors_eq_one {n : ℕ} : IsPrimePow n ↔ n.primeFactors.card = 1 := by simp_rw [isPrimePow_iff_factorization_eq_single, ← Nat.support_factorization, - Finsupp.card_support_eq_one', exists_prop, pos_iff_ne_zero] + Finsupp.card_support_eq_one', pos_iff_ne_zero] #align is_prime_pow_iff_card_support_factorization_eq_one isPrimePow_iff_card_primeFactors_eq_one theorem IsPrimePow.exists_ord_compl_eq_one {n : ℕ} (h : IsPrimePow n) : diff --git a/Mathlib/Data/Nat/Pow.lean b/Mathlib/Data/Nat/Pow.lean index 8b23728b822ad..41d571b67e98a 100644 --- a/Mathlib/Data/Nat/Pow.lean +++ b/Mathlib/Data/Nat/Pow.lean @@ -176,7 +176,7 @@ theorem mod_pow_succ {b : ℕ} (w m : ℕ) : m % b ^ succ w = b * (m / b % b ^ w rw [Eq.symm (mod_eq_sub_mod p_b_ge)] #align nat.mod_pow_succ Nat.mod_pow_succ -theorem pow_dvd_pow_iff_pow_le_pow {k l : ℕ} : ∀ {x : ℕ} (_ : 0 < x), x ^ k ∣ x ^ l ↔ x ^ k ≤ x ^ l +theorem pow_dvd_pow_iff_pow_le_pow {k l : ℕ} : ∀ {x : ℕ}, 0 < x → (x ^ k ∣ x ^ l ↔ x ^ k ≤ x ^ l) | x + 1, w => by constructor · intro a diff --git a/Mathlib/Data/Part.lean b/Mathlib/Data/Part.lean index b02f45ab74744..58e7448331311 100644 --- a/Mathlib/Data/Part.lean +++ b/Mathlib/Data/Part.lean @@ -74,7 +74,7 @@ def toOption (o : Part α) [Decidable o.Dom] : Option α := #align part.to_option_is_none Part.toOption_isNone /-- `Part` extensionality -/ -theorem ext' : ∀ {o p : Part α} (_ : o.Dom ↔ p.Dom) (_ : ∀ h₁ h₂, o.get h₁ = p.get h₂), o = p +theorem ext' : ∀ {o p : Part α}, (o.Dom ↔ p.Dom) → (∀ h₁ h₂, o.get h₁ = p.get h₂) → o = p | ⟨od, o⟩, ⟨pd, p⟩, H1, H2 => by have t : od = pd := propext H1 cases t; rw [show o = p from funext fun p => H2 p p] diff --git a/Mathlib/GroupTheory/SchurZassenhaus.lean b/Mathlib/GroupTheory/SchurZassenhaus.lean index c81606164c27f..30095bd8c7498 100644 --- a/Mathlib/GroupTheory/SchurZassenhaus.lean +++ b/Mathlib/GroupTheory/SchurZassenhaus.lean @@ -146,10 +146,9 @@ The proof is by contradiction. We assume that `G` is a minimal counterexample to variable {G : Type u} [Group G] [Fintype G] {N : Subgroup G} [Normal N] (h1 : Nat.Coprime (Fintype.card N) N.index) - (h2 : - ∀ (G' : Type u) [Group G'] [Fintype G'], - ∀ (_ : Fintype.card G' < Fintype.card G) {N' : Subgroup G'} [N'.Normal] - (_ : Nat.Coprime (Fintype.card N') N'.index), ∃ H' : Subgroup G', IsComplement' N' H') + (h2 : ∀ (G' : Type u) [Group G'] [Fintype G'], + Fintype.card G' < Fintype.card G → ∀ {N' : Subgroup G'} [N'.Normal], + Nat.Coprime (Fintype.card N') N'.index → ∃ H' : Subgroup G', IsComplement' N' H') (h3 : ∀ H : Subgroup G, ¬IsComplement' N H) /-! We will arrive at a contradiction via the following steps: diff --git a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean index 1321c9dbb7924..8708ce5c517a6 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean @@ -575,9 +575,9 @@ corresponding indexed family whose index type is the subtype corresponding to that subset. -/ theorem eq_weightedVSubOfPoint_subset_iff_eq_weightedVSubOfPoint_subtype {v : V} {x : k} {s : Set ι} {p : ι → P} {b : P} : - (∃ (fs : Finset ι) (_ : ↑fs ⊆ s) (w : ι → k) (_ : ∑ i in fs, w i = x), + (∃ fs : Finset ι, ↑fs ⊆ s ∧ ∃ w : ι → k, ∑ i in fs, w i = x ∧ v = fs.weightedVSubOfPoint p b w) ↔ - ∃ (fs : Finset s) (w : s → k) (_ : ∑ i in fs, w i = x), + ∃ (fs : Finset s) (w : s → k), ∑ i in fs, w i = x ∧ v = fs.weightedVSubOfPoint (fun i : s => p i) b w := by classical simp_rw [weightedVSubOfPoint_apply] @@ -600,9 +600,9 @@ only if it can be expressed as `weightedVSub` with sum of weights 0 for the corresponding indexed family whose index type is the subtype corresponding to that subset. -/ theorem eq_weightedVSub_subset_iff_eq_weightedVSub_subtype {v : V} {s : Set ι} {p : ι → P} : - (∃ (fs : Finset ι) (_ : ↑fs ⊆ s) (w : ι → k) (_ : ∑ i in fs, w i = 0), + (∃ fs : Finset ι, ↑fs ⊆ s ∧ ∃ w : ι → k, ∑ i in fs, w i = 0 ∧ v = fs.weightedVSub p w) ↔ - ∃ (fs : Finset s) (w : s → k) (_ : ∑ i in fs, w i = 0), + ∃ (fs : Finset s) (w : s → k), ∑ i in fs, w i = 0 ∧ v = fs.weightedVSub (fun i : s => p i) w := eq_weightedVSubOfPoint_subset_iff_eq_weightedVSubOfPoint_subtype #align finset.eq_weighted_vsub_subset_iff_eq_weighted_vsub_subtype Finset.eq_weightedVSub_subset_iff_eq_weightedVSub_subtype @@ -618,9 +618,9 @@ indexed family whose index type is the subtype corresponding to that subset. -/ theorem eq_affineCombination_subset_iff_eq_affineCombination_subtype {p0 : P} {s : Set ι} {p : ι → P} : - (∃ (fs : Finset ι) (_ : ↑fs ⊆ s) (w : ι → k) (_ : ∑ i in fs, w i = 1), + (∃ fs : Finset ι, ↑fs ⊆ s ∧ ∃ w : ι → k, ∑ i in fs, w i = 1 ∧ p0 = fs.affineCombination k p w) ↔ - ∃ (fs : Finset s) (w : s → k) (_ : ∑ i in fs, w i = 1), + ∃ (fs : Finset s) (w : s → k), ∑ i in fs, w i = 1 ∧ p0 = fs.affineCombination k (fun i : s => p i) w := by simp_rw [affineCombination_apply, eq_vadd_iff_vsub_eq] exact eq_weightedVSubOfPoint_subset_iff_eq_weightedVSubOfPoint_subtype @@ -942,7 +942,7 @@ stated in terms of a set equal to the image to provide control of definitional equality for the index type used for the centroid of the image. -/ theorem centroid_eq_centroid_image_of_inj_on {p : ι → P} - (hi : ∀ (i) (_ : i ∈ s) (j) (_ : j ∈ s), p i = p j → i = j) {ps : Set P} [Fintype ps] + (hi : ∀ i ∈ s, ∀ j ∈ s, p i = p j → i = j) {ps : Set P} [Fintype ps] (hps : ps = p '' ↑s) : s.centroid k p = (univ : Finset ps).centroid k fun x => (x : P) := by let f : p '' ↑s → ι := fun x => x.property.choose have hf : ∀ x, f x ∈ s ∧ p (f x) = x := fun x => x.property.choose_spec @@ -972,8 +972,8 @@ theorem centroid_eq_centroid_image_of_inj_on {p : ι → P} `Finset`s and with the same points in the image of those `Finset`s have the same centroid. -/ theorem centroid_eq_of_inj_on_of_image_eq {p : ι → P} - (hi : ∀ (i) (_ : i ∈ s) (j) (_ : j ∈ s), p i = p j → i = j) {p₂ : ι₂ → P} - (hi₂ : ∀ (i) (_ : i ∈ s₂) (j) (_ : j ∈ s₂), p₂ i = p₂ j → i = j) (he : p '' ↑s = p₂ '' ↑s₂) : + (hi : ∀ i ∈ s, ∀ j ∈ s, p i = p j → i = j) {p₂ : ι₂ → P} + (hi₂ : ∀ i ∈ s₂, ∀ j ∈ s₂, p₂ i = p₂ j → i = j) (he : p '' ↑s = p₂ '' ↑s₂) : s.centroid k p = s₂.centroid k p₂ := by classical rw [s.centroid_eq_centroid_image_of_inj_on k hi rfl, s₂.centroid_eq_centroid_image_of_inj_on k hi₂ he] @@ -1040,7 +1040,7 @@ variable (k) if it is a `weightedVSub` with sum of weights 0. -/ theorem mem_vectorSpan_iff_eq_weightedVSub {v : V} {p : ι → P} : v ∈ vectorSpan k (Set.range p) ↔ - ∃ (s : Finset ι) (w : ι → k) (_ : ∑ i in s, w i = 0), v = s.weightedVSub p w := by + ∃ (s : Finset ι) (w : ι → k), ∑ i in s, w i = 0 ∧ v = s.weightedVSub p w := by classical constructor · rcases isEmpty_or_nonempty ι with (hι | ⟨⟨i0⟩⟩) @@ -1086,7 +1086,7 @@ variable {k} `eq_affineCombination_of_mem_affineSpan_of_fintype`. -/ theorem eq_affineCombination_of_mem_affineSpan {p1 : P} {p : ι → P} (h : p1 ∈ affineSpan k (Set.range p)) : - ∃ (s : Finset ι) (w : ι → k) (_ : ∑ i in s, w i = 1), p1 = s.affineCombination k p w := by + ∃ (s : Finset ι) (w : ι → k), ∑ i in s, w i = 1 ∧ p1 = s.affineCombination k p w := by classical have hn : (affineSpan k (Set.range p) : Set P).Nonempty := ⟨p1, h⟩ rw [affineSpan_nonempty, Set.range_nonempty_iff_nonempty] at hn @@ -1111,17 +1111,15 @@ theorem eq_affineCombination_of_mem_affineSpan {p1 : P} {p : ι → P} have hw0s : s'.affineCombination k p w0 = p i0 := s'.affineCombination_of_eq_one_of_eq_zero w0 p (Finset.mem_insert_self _ _) (Function.update_same _ _ _) fun _ _ hne => Function.update_noteq hne _ _ - use s', w0 + w' - constructor - · rw [add_comm, ← Finset.weightedVSub_vadd_affineCombination, hw0s, hs', vsub_vadd] + refine ⟨s', w0 + w', ?_, ?_⟩ · -- Porting note: proof was `simp [Pi.add_apply, Finset.sum_add_distrib, hw0, h']` - change (Finset.sum s' fun i => w0 i + w' i) = 1 - simp only [Finset.sum_add_distrib, hw0, h', add_zero] + simp only [Pi.add_apply, Finset.sum_add_distrib, hw0, h', add_zero] + · rw [add_comm, ← Finset.weightedVSub_vadd_affineCombination, hw0s, hs', vsub_vadd] #align eq_affine_combination_of_mem_affine_span eq_affineCombination_of_mem_affineSpan theorem eq_affineCombination_of_mem_affineSpan_of_fintype [Fintype ι] {p1 : P} {p : ι → P} (h : p1 ∈ affineSpan k (Set.range p)) : - ∃ (w : ι → k) (_ : ∑ i, w i = 1), p1 = Finset.univ.affineCombination k p w := by + ∃ w : ι → k, ∑ i, w i = 1 ∧ p1 = Finset.univ.affineCombination k p w := by classical obtain ⟨s, w, hw, rfl⟩ := eq_affineCombination_of_mem_affineSpan h refine' @@ -1137,7 +1135,7 @@ if it is an `affineCombination` with sum of weights 1, provided the underlying ring is nontrivial. -/ theorem mem_affineSpan_iff_eq_affineCombination [Nontrivial k] {p1 : P} {p : ι → P} : p1 ∈ affineSpan k (Set.range p) ↔ - ∃ (s : Finset ι) (w : ι → k) (_ : ∑ i in s, w i = 1), p1 = s.affineCombination k p w := by + ∃ (s : Finset ι) (w : ι → k), ∑ i in s, w i = 1 ∧ p1 = s.affineCombination k p w := by constructor · exact eq_affineCombination_of_mem_affineSpan · rintro ⟨s, w, hw, rfl⟩ diff --git a/Mathlib/LinearAlgebra/Finsupp.lean b/Mathlib/LinearAlgebra/Finsupp.lean index d744c6c65652d..49de2c6a75bfb 100644 --- a/Mathlib/LinearAlgebra/Finsupp.lean +++ b/Mathlib/LinearAlgebra/Finsupp.lean @@ -295,7 +295,7 @@ theorem mem_supported {s : Set α} (p : α →₀ M) : p ∈ supported M R s ↔ #align finsupp.mem_supported Finsupp.mem_supported theorem mem_supported' {s : Set α} (p : α →₀ M) : - p ∈ supported M R s ↔ ∀ (x) (_ : x ∉ s), p x = 0 := by + p ∈ supported M R s ↔ ∀ x ∉ s, p x = 0 := by haveI := Classical.decPred fun x : α => x ∈ s; simp [mem_supported, Set.subset_def, not_imp_comm] #align finsupp.mem_supported' Finsupp.mem_supported' @@ -590,7 +590,7 @@ theorem lmapDomain_supported (f : α → α') (s : Set α) : #align finsupp.lmap_domain_supported Finsupp.lmapDomain_supported theorem lmapDomain_disjoint_ker (f : α → α') {s : Set α} - (H : ∀ (a) (_ : a ∈ s) (b) (_ : b ∈ s), f a = f b → a = b) : + (H : ∀ a ∈ s, ∀ b ∈ s, f a = f b → a = b) : Disjoint (supported M R s) (ker (lmapDomain M R f)) := by rw [disjoint_iff_inf_le] rintro l ⟨h₁, h₂⟩ diff --git a/Mathlib/LinearAlgebra/Span.lean b/Mathlib/LinearAlgebra/Span.lean index 9da5117bab683..35003246b01aa 100644 --- a/Mathlib/LinearAlgebra/Span.lean +++ b/Mathlib/LinearAlgebra/Span.lean @@ -692,8 +692,8 @@ instance : IsCompactlyGenerated (Submodule R M) := /-- A submodule is equal to the supremum of the spans of the submodule's nonzero elements. -/ theorem submodule_eq_sSup_le_nonzero_spans (p : Submodule R M) : - p = sSup { T : Submodule R M | ∃ (m : M) (_ : m ∈ p) (_ : m ≠ 0), T = span R {m} } := by - let S := { T : Submodule R M | ∃ (m : M) (_ : m ∈ p) (_ : m ≠ 0), T = span R {m} } + p = sSup { T : Submodule R M | ∃ m ∈ p, m ≠ 0 ∧ T = span R {m} } := by + let S := { T : Submodule R M | ∃ m ∈ p, m ≠ 0 ∧ T = span R {m} } apply le_antisymm · intro m hm by_cases h : m = 0 diff --git a/Mathlib/MeasureTheory/Covering/Vitali.lean b/Mathlib/MeasureTheory/Covering/Vitali.lean index cab3688bd39ad..34bafa877746a 100644 --- a/Mathlib/MeasureTheory/Covering/Vitali.lean +++ b/Mathlib/MeasureTheory/Covering/Vitali.lean @@ -58,7 +58,7 @@ wider applicability. theorem exists_disjoint_subfamily_covering_enlargment (B : ι → Set α) (t : Set ι) (δ : ι → ℝ) (τ : ℝ) (hτ : 1 < τ) (δnonneg : ∀ a ∈ t, 0 ≤ δ a) (R : ℝ) (δle : ∀ a ∈ t, δ a ≤ R) (hne : ∀ a ∈ t, (B a).Nonempty) : - ∃ (u : _) (_ : u ⊆ t), + ∃ u ⊆ t, u.PairwiseDisjoint B ∧ ∀ a ∈ t, ∃ b ∈ u, (B a ∩ B b).Nonempty ∧ δ a ≤ τ * δ b := by /- The proof could be formulated as a transfinite induction. First pick an element of `t` with `δ` as large as possible (up to a factor of `τ`). Then among the remaining elements not intersecting @@ -160,7 +160,7 @@ extract a disjoint subfamily `u ⊆ t` so that all balls in `t` are covered by t dilations of balls in `u`. -/ theorem exists_disjoint_subfamily_covering_enlargment_closedBall [MetricSpace α] (t : Set ι) (x : ι → α) (r : ι → ℝ) (R : ℝ) (hr : ∀ a ∈ t, r a ≤ R) : - ∃ (u : _) (_ : u ⊆ t), + ∃ u ⊆ t, (u.PairwiseDisjoint fun a => closedBall (x a) (r a)) ∧ ∀ a ∈ t, ∃ b ∈ u, closedBall (x a) (r a) ⊆ closedBall (x b) (5 * r b) := by rcases eq_empty_or_nonempty t with (rfl | _) @@ -205,7 +205,7 @@ theorem exists_disjoint_covering_ae [MetricSpace α] [MeasurableSpace α] [Opens (μB : ∀ a ∈ t, μ (closedBall (c a) (3 * r a)) ≤ C * μ (B a)) (ht : ∀ a ∈ t, (interior (B a)).Nonempty) (h't : ∀ a ∈ t, IsClosed (B a)) (hf : ∀ x ∈ s, ∀ ε > (0 : ℝ), ∃ a ∈ t, r a ≤ ε ∧ c a = x) : - ∃ (u : _) (_ : u ⊆ t), u.Countable ∧ u.PairwiseDisjoint B ∧ μ (s \ ⋃ a ∈ u, B a) = 0 := by + ∃ u ⊆ t, u.Countable ∧ u.PairwiseDisjoint B ∧ μ (s \ ⋃ a ∈ u, B a) = 0 := by /- The idea of the proof is the following. Assume for simplicity that `μ` is finite. Applying the abstract Vitali covering theorem with `δ = r` given by `hf`, one obtains a disjoint subfamily `u`, such that any element of `t` intersects an element of `u` with comparable radius. Fix `ε > 0`. @@ -243,7 +243,7 @@ theorem exists_disjoint_covering_ae [MetricSpace α] [MeasurableSpace α] [Opens -- they only see a finite part of the measure, and with a doubling property let t' := { a ∈ t | r a ≤ R (c a) } -- extract a disjoint subfamily `u` of `t'` thanks to the abstract Vitali covering theorem. - obtain ⟨u, ut', u_disj, hu⟩ : ∃ (u : _) (_ : u ⊆ t'), + obtain ⟨u, ut', u_disj, hu⟩ : ∃ u ⊆ t', u.PairwiseDisjoint B ∧ ∀ a ∈ t', ∃ b ∈ u, (B a ∩ B b).Nonempty ∧ r a ≤ 2 * r b := by have A : ∀ a ∈ t', r a ≤ 1 := by intro a ha diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean index 4057fe0c41ef3..799b206df9975 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean @@ -691,7 +691,7 @@ theorem Memℒp.induction_stronglyMeasurable (hm : m ≤ m0) (hp_ne_top : p ≠ P f → P g → P (f + g)) (h_closed : IsClosed {f : lpMeas F ℝ m p μ | P f}) (h_ae : ∀ ⦃f g⦄, f =ᵐ[μ] g → Memℒp f p μ → P f → P g) : - ∀ ⦃f : α → F⦄ (_ : Memℒp f p μ) (_ : AEStronglyMeasurable' m f μ), P f := by + ∀ ⦃f : α → F⦄, Memℒp f p μ → AEStronglyMeasurable' m f μ → P f := by intro f hf hfm let f_Lp := hf.toLp f have hfm_Lp : AEStronglyMeasurable' m f_Lp μ := hfm.congr hf.coeFn_toLp.symm diff --git a/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean b/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean index 03eb8fbdac493..2fa8888ab2cb1 100644 --- a/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean +++ b/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean @@ -52,13 +52,13 @@ variable {α ι E : Type*} {m : MeasurableSpace α} {μ : Measure α} some given filter `l`. -/ def TendstoInMeasure [Dist E] {_ : MeasurableSpace α} (μ : Measure α) (f : ι → α → E) (l : Filter ι) (g : α → E) : Prop := - ∀ (ε) (_ : 0 < ε), Tendsto (fun i => μ { x | ε ≤ dist (f i x) (g x) }) l (𝓝 0) + ∀ ε, 0 < ε → Tendsto (fun i => μ { x | ε ≤ dist (f i x) (g x) }) l (𝓝 0) #align measure_theory.tendsto_in_measure MeasureTheory.TendstoInMeasure theorem tendstoInMeasure_iff_norm [SeminormedAddCommGroup E] {l : Filter ι} {f : ι → α → E} {g : α → E} : TendstoInMeasure μ f l g ↔ - ∀ (ε) (hε : 0 < ε), Tendsto (fun i => μ { x | ε ≤ ‖f i x - g x‖ }) l (𝓝 0) := by + ∀ ε, 0 < ε → Tendsto (fun i => μ { x | ε ≤ ‖f i x - g x‖ }) l (𝓝 0) := by simp_rw [TendstoInMeasure, dist_eq_norm] #align measure_theory.tendsto_in_measure_iff_norm MeasureTheory.tendstoInMeasure_iff_norm diff --git a/Mathlib/MeasureTheory/Function/LpSpace.lean b/Mathlib/MeasureTheory/Function/LpSpace.lean index 660d0f2916f7c..d8872ba41e5e7 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace.lean @@ -1680,7 +1680,7 @@ theorem cauchy_complete_ℒp [CompleteSpace E] (hp : 1 ≤ p) {f : ℕ → α ∃ (f_lim : α → E), Memℒp f_lim p μ ∧ atTop.Tendsto (fun n => snorm (f n - f_lim) p μ) (𝓝 0) := by obtain ⟨f_lim, h_f_lim_meas, h_lim⟩ : - ∃ (f_lim : α → E) (_ : StronglyMeasurable f_lim), + ∃ f_lim : α → E, StronglyMeasurable f_lim ∧ ∀ᵐ x ∂μ, Tendsto (fun n => f n x) atTop (nhds (f_lim x)) := exists_stronglyMeasurable_limit_of_tendsto_ae (fun n => (hf n).1) (ae_tendsto_of_cauchy_snorm (fun n => (hf n).1) hp hB h_cau) diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean index 462a63efeb4ad..e13ac5df0b533 100644 --- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean +++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean @@ -1695,7 +1695,7 @@ one can select a strongly measurable function as the almost everywhere limit. -/ theorem _root_.exists_stronglyMeasurable_limit_of_tendsto_ae [PseudoMetrizableSpace β] {f : ℕ → α → β} (hf : ∀ n, AEStronglyMeasurable (f n) μ) (h_ae_tendsto : ∀ᵐ x ∂μ, ∃ l : β, Tendsto (fun n => f n x) atTop (𝓝 l)) : - ∃ (f_lim : α → β) (hf_lim_meas : StronglyMeasurable f_lim), + ∃ f_lim : α → β, StronglyMeasurable f_lim ∧ ∀ᵐ x ∂μ, Tendsto (fun n => f n x) atTop (𝓝 (f_lim x)) := by borelize β obtain ⟨g, _, hg⟩ : diff --git a/Mathlib/MeasureTheory/Group/FundamentalDomain.lean b/Mathlib/MeasureTheory/Group/FundamentalDomain.lean index 48fb4d2b2d170..2a7b5a44cdabc 100644 --- a/Mathlib/MeasureTheory/Group/FundamentalDomain.lean +++ b/Mathlib/MeasureTheory/Group/FundamentalDomain.lean @@ -110,7 +110,7 @@ sufficiently large. -/ to check that its translates `g +ᵥ s` are (almost) disjoint and that the sum `∑' g, μ (g +ᵥ s)` is sufficiently large."] theorem mk_of_measure_univ_le [IsFiniteMeasure μ] [Countable G] (h_meas : NullMeasurableSet s μ) - (h_ae_disjoint : ∀ (g) (_ : g ≠ (1 : G)), AEDisjoint μ (g • s) s) + (h_ae_disjoint : ∀ g ≠ (1 : G), AEDisjoint μ (g • s) s) (h_qmp : ∀ g : G, QuasiMeasurePreserving (g • · : α → α) μ μ) (h_measure_univ_le : μ (univ : Set α) ≤ ∑' g : G, μ (g • s)) : IsFundamentalDomain G s μ := have aedisjoint : Pairwise (AEDisjoint μ on fun g : G => g • s) := diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index 52424750ef4a7..f6fd90533d436 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -1857,7 +1857,7 @@ open Pointwise @[to_additive] theorem pairwise_aedisjoint_of_aedisjoint_forall_ne_one {G α : Type*} [Group G] [MulAction G α] [MeasurableSpace α] {μ : Measure α} {s : Set α} - (h_ae_disjoint : ∀ (g) (_ : g ≠ (1 : G)), AEDisjoint μ (g • s) s) + (h_ae_disjoint : ∀ g ≠ (1 : G), AEDisjoint μ (g • s) s) (h_qmp : ∀ g : G, QuasiMeasurePreserving (g • ·) μ μ) : Pairwise (AEDisjoint μ on fun g : G => g • s) := by intro g₁ g₂ hg diff --git a/Mathlib/MeasureTheory/Measure/OuterMeasure.lean b/Mathlib/MeasureTheory/Measure/OuterMeasure.lean index c1964dc75cf8e..ba56568145bd5 100644 --- a/Mathlib/MeasureTheory/Measure/OuterMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/OuterMeasure.lean @@ -743,7 +743,7 @@ theorem ofFunction_union_of_top_of_nonempty_inter {s t : Set α} set I := fun s => { i : ℕ | (s ∩ f i).Nonempty } have hd : Disjoint (I s) (I t) := disjoint_iff_inf_le.mpr fun i hi => he ⟨i, hi⟩ - have hI : ∀ (u) (_ : u ⊆ s ∪ t), μ u ≤ ∑' i : I u, μ (f i) := fun u hu => + have hI : ∀ u ⊆ s ∪ t, μ u ≤ ∑' i : I u, μ (f i) := fun u hu => calc μ u ≤ μ (⋃ i : I u, f i) := μ.mono fun x hx => diff --git a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean index e909e9fc83d97..32f40dfef6f7e 100644 --- a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean @@ -1156,7 +1156,7 @@ to use. This is equivalent to the definition which requires measurability. To pr `MutuallySingular` with the measurability condition, use `MeasureTheory.VectorMeasure.MutuallySingular.mk`. -/ def MutuallySingular (v : VectorMeasure α M) (w : VectorMeasure α N) : Prop := - ∃ s : Set α, MeasurableSet s ∧ (∀ t ⊆ s, v t = 0) ∧ ∀ (t) (_ : t ⊆ sᶜ), w t = 0 + ∃ s : Set α, MeasurableSet s ∧ (∀ t ⊆ s, v t = 0) ∧ ∀ t ⊆ sᶜ, w t = 0 #align measure_theory.vector_measure.mutually_singular MeasureTheory.VectorMeasure.MutuallySingular @[inherit_doc VectorMeasure.MutuallySingular] diff --git a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean index a0193c29a16f0..3374189203b25 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean @@ -272,7 +272,7 @@ theorem list_prod_right {a : ℤ} {l : List ℕ} (hl : ∀ n ∈ l, n ≠ 0) : /-- If `J(a | n) = -1`, then `n` has a prime divisor `p` such that `J(a | p) = -1`. -/ theorem eq_neg_one_at_prime_divisor_of_eq_neg_one {a : ℤ} {n : ℕ} (h : J(a | n) = -1) : - ∃ (p : ℕ) (_ : p.Prime), p ∣ n ∧ J(a | p) = -1 := by + ∃ p : ℕ, p.Prime ∧ p ∣ n ∧ J(a | p) = -1 := by have hn₀ : n ≠ 0 := by rintro rfl rw [zero_right, eq_neg_self_iff] at h @@ -323,7 +323,7 @@ namespace jacobiSym /-- If `χ` is a multiplicative function such that `J(a | p) = χ p` for all odd primes `p`, then `J(a | b)` equals `χ b` for all odd natural numbers `b`. -/ theorem value_at (a : ℤ) {R : Type*} [CommSemiring R] (χ : R →* ℤ) - (hp : ∀ (p : ℕ) (pp : p.Prime) (_ : p ≠ 2), @legendreSym p ⟨pp⟩ a = χ p) {b : ℕ} (hb : Odd b) : + (hp : ∀ (p : ℕ) (pp : p.Prime), p ≠ 2 → @legendreSym p ⟨pp⟩ a = χ p) {b : ℕ} (hb : Odd b) : J(a | b) = χ b := by conv_rhs => rw [← prod_factors hb.pos.ne', cast_list_prod, χ.map_list_prod] rw [jacobiSym, List.map_map, ← List.pmap_eq_map Nat.Prime _ _ fun _ => prime_of_mem_factors] diff --git a/Mathlib/NumberTheory/Padics/PadicNumbers.lean b/Mathlib/NumberTheory/Padics/PadicNumbers.lean index ae45a6bb5e9e4..52e36ef6cfa17 100644 --- a/Mathlib/NumberTheory/Padics/PadicNumbers.lean +++ b/Mathlib/NumberTheory/Padics/PadicNumbers.lean @@ -656,7 +656,7 @@ variable {p : ℕ} [Fact p.Prime] (f : CauSeq _ (@padicNormE p _)) theorem rat_dense' (q : ℚ_[p]) {ε : ℚ} (hε : 0 < ε) : ∃ r : ℚ, padicNormE (q - r : ℚ_[p]) < ε := Quotient.inductionOn q fun q' ↦ - have : ∃ N, ∀ (m) (_ : m ≥ N) (n) (_ : n ≥ N), padicNorm p (q' m - q' n) < ε := cauchy₂ _ hε + have : ∃ N, ∀ m ≥ N, ∀ n ≥ N, padicNorm p (q' m - q' n) < ε := cauchy₂ _ hε let ⟨N, hN⟩ := this ⟨q' N, by dsimp [padicNormE] diff --git a/Mathlib/NumberTheory/ZetaFunction.lean b/Mathlib/NumberTheory/ZetaFunction.lean index e6a04813ebfd8..17cc453b3d2e2 100644 --- a/Mathlib/NumberTheory/ZetaFunction.lean +++ b/Mathlib/NumberTheory/ZetaFunction.lean @@ -512,7 +512,7 @@ theorem mellin_zetaKernel₁_eq_tsum {s : ℂ} (hs : 1 / 2 < s.re) : let bd : ℕ → ℝ → ℝ := fun n t => t ^ (s.re - 1) * exp (-π * t * ((n : ℝ) + 1) ^ 2) let f : ℕ → ℝ → ℂ := fun n t => (t : ℂ) ^ (s - 1) * exp (-π * t * ((n : ℝ) + 1) ^ 2) have hm : MeasurableSet (Ioi (0 : ℝ)) := measurableSet_Ioi - have h_norm : ∀ (n : ℕ) {t : ℝ} (_ : 0 < t), ‖f n t‖ = bd n t := by + have h_norm : ∀ (n : ℕ) {t : ℝ}, 0 < t → ‖f n t‖ = bd n t := by intro n t ht rw [norm_mul, Complex.norm_eq_abs, Complex.norm_eq_abs, Complex.abs_of_nonneg (exp_pos _).le, abs_cpow_eq_rpow_re_of_pos ht, sub_re, one_re] @@ -526,7 +526,7 @@ theorem mellin_zetaKernel₁_eq_tsum {s : ℂ} (hs : 1 / 2 < s.re) : (continuous_exp.comp ((continuous_const.mul continuous_id').mul continuous_const)) have h_le : ∀ n : ℕ, ∀ᵐ t : ℝ ∂volume.restrict (Ioi 0), ‖f n t‖ ≤ bd n t := fun n => (ae_restrict_iff' hm).mpr (ae_of_all _ fun t ht => le_of_eq (h_norm n ht)) - have h_sum0 : ∀ {t : ℝ} (_ : 0 < t), HasSum (fun n => f n t) + have h_sum0 : ∀ {t : ℝ}, 0 < t → HasSum (fun n => f n t) ((t : ℂ) ^ (s - 1) * zetaKernel₁ t) := by intro t ht rw [zetaKernel₁] diff --git a/Mathlib/Order/CountableDenseLinearOrder.lean b/Mathlib/Order/CountableDenseLinearOrder.lean index a3d17feeb5c03..e18c46aa76d0b 100644 --- a/Mathlib/Order/CountableDenseLinearOrder.lean +++ b/Mathlib/Order/CountableDenseLinearOrder.lean @@ -74,7 +74,7 @@ variable (α β : Type*) [LinearOrder α] [LinearOrder β] of pairs which should be identified. -/ def PartialIso : Type _ := { f : Finset (α × β) // - ∀ (p) (_ : p ∈ f) (q) (_ : q ∈ f), + ∀ p ∈ f, ∀ q ∈ f, cmp (Prod.fst p) (Prod.fst q) = cmp (Prod.snd p) (Prod.snd q) } #align order.partial_iso Order.PartialIso diff --git a/Mathlib/Order/Extension/Linear.lean b/Mathlib/Order/Extension/Linear.lean index 21a1d6636a702..04130b389c64a 100644 --- a/Mathlib/Order/Extension/Linear.lean +++ b/Mathlib/Order/Extension/Linear.lean @@ -24,7 +24,7 @@ open Classical /-- Any partial order can be extended to a linear order. -/ theorem extend_partialOrder {α : Type u} (r : α → α → Prop) [IsPartialOrder α r] : - ∃ (s : α → α → Prop) (_ : IsLinearOrder α s), r ≤ s := by + ∃ s : α → α → Prop, IsLinearOrder α s ∧ r ≤ s := by let S := { s | IsPartialOrder α s } have hS : ∀ c, c ⊆ S → IsChain (· ≤ ·) c → ∀ y ∈ c, ∃ ub ∈ S, ∀ z ∈ c, z ≤ ub := by rintro c hc₁ hc₂ s hs @@ -80,16 +80,16 @@ def LinearExtension (α : Type u) : Type u := noncomputable instance {α : Type u} [PartialOrder α] : LinearOrder (LinearExtension α) where le := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose - le_refl := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.choose.1.1.1.1 - le_trans := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.choose.1.1.2.1 - le_antisymm := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.choose.1.2.1 - le_total := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.choose.2.1 + le_refl := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.1.1.1.1.1 + le_trans := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.1.1.1.2.1 + le_antisymm := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.1.1.2.1 + le_total := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.1.2.1 decidableLE := Classical.decRel _ /-- The embedding of `α` into `LinearExtension α` as an order homomorphism. -/ def toLinearExtension {α : Type u} [PartialOrder α] : α →o LinearExtension α where toFun x := x - monotone' := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.choose_spec + monotone' := (extend_partialOrder ((· ≤ ·) : α → α → Prop)).choose_spec.2 #align to_linear_extension toLinearExtension instance {α : Type u} [Inhabited α] : Inhabited (LinearExtension α) := diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index 239ab82453851..69553696881f4 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -373,7 +373,7 @@ theorem le_generate_iff {s : Set (Set α)} {f : Filter α} : f ≤ generate s #align filter.sets_iff_generate Filter.le_generate_iff theorem mem_generate_iff {s : Set <| Set α} {U : Set α} : - U ∈ generate s ↔ ∃ (t : _) (_ : t ⊆ s), Set.Finite t ∧ ⋂₀ t ⊆ U := by + U ∈ generate s ↔ ∃ t ⊆ s, Set.Finite t ∧ ⋂₀ t ⊆ U := by constructor <;> intro h · induction h case basic V V_in => @@ -638,7 +638,7 @@ theorem mem_iInf {ι} {s : ι → Filter α} {U : Set α} : theorem mem_iInf' {ι} {s : ι → Filter α} {U : Set α} : (U ∈ ⨅ i, s i) ↔ ∃ I : Set ι, I.Finite ∧ ∃ V : ι → Set α, (∀ i, V i ∈ s i) ∧ - (∀ (i) (_hi : i ∉ I), V i = univ) ∧ (U = ⋂ i ∈ I, V i) ∧ U = ⋂ i, V i := by + (∀ i ∉ I, V i = univ) ∧ (U = ⋂ i ∈ I, V i) ∧ U = ⋂ i, V i := by simp only [mem_iInf, SetCoe.forall', biInter_eq_iInter] refine' ⟨_, fun ⟨I, If, V, hVs, _, hVU, _⟩ => ⟨I, If, fun i => V i, fun i => hVs i, hVU⟩⟩ rintro ⟨I, If, V, hV, rfl⟩ diff --git a/Mathlib/Order/GaloisConnection.lean b/Mathlib/Order/GaloisConnection.lean index e87a062c021c7..defed5491802b 100644 --- a/Mathlib/Order/GaloisConnection.lean +++ b/Mathlib/Order/GaloisConnection.lean @@ -563,7 +563,7 @@ theorem l_iSup_u [CompleteLattice α] [CompleteLattice β] (gi : GaloisInsertion #align galois_insertion.l_supr_u GaloisInsertion.l_iSup_u theorem l_biSup_u [CompleteLattice α] [CompleteLattice β] (gi : GaloisInsertion l u) {ι : Sort x} - {p : ι → Prop} (f : ∀ (i) (_ : p i), β) : l (⨆ (i) (hi), u (f i hi)) = ⨆ (i) (hi), f i hi := by + {p : ι → Prop} (f : ∀ i, p i → β) : l (⨆ (i) (hi), u (f i hi)) = ⨆ (i) (hi), f i hi := by simp only [iSup_subtype', gi.l_iSup_u] #align galois_insertion.l_bsupr_u GaloisInsertion.l_biSup_u diff --git a/Mathlib/Order/Monotone/Basic.lean b/Mathlib/Order/Monotone/Basic.lean index 4d08036fad4d8..a81d17e1925ac 100644 --- a/Mathlib/Order/Monotone/Basic.lean +++ b/Mathlib/Order/Monotone/Basic.lean @@ -124,19 +124,19 @@ variable [Preorder α] [Preorder β] {f : α → β} {s : Set α} instance [i : Decidable (∀ a b, a ≤ b → f a ≤ f b)] : Decidable (Monotone f) := i instance [i : Decidable (∀ a b, a ≤ b → f b ≤ f a)] : Decidable (Antitone f) := i -instance [i : Decidable (∀ (a) (_ : a ∈ s) (b) (_ : b ∈ s), a ≤ b → f a ≤ f b)] : +instance [i : Decidable (∀ a ∈ s, ∀ b ∈ s, a ≤ b → f a ≤ f b)] : Decidable (MonotoneOn f s) := i -instance [i : Decidable (∀ (a) (_ : a ∈ s) (b) (_ : b ∈ s), a ≤ b → f b ≤ f a)] : +instance [i : Decidable (∀ a ∈ s, ∀ b ∈ s, a ≤ b → f b ≤ f a)] : Decidable (AntitoneOn f s) := i instance [i : Decidable (∀ a b, a < b → f a < f b)] : Decidable (StrictMono f) := i instance [i : Decidable (∀ a b, a < b → f b < f a)] : Decidable (StrictAnti f) := i -instance [i : Decidable (∀ (a) (_ : a ∈ s) (b) (_ : b ∈ s), a < b → f a < f b)] : +instance [i : Decidable (∀ a ∈ s, ∀ b ∈ s, a < b → f a < f b)] : Decidable (StrictMonoOn f s) := i -instance [i : Decidable (∀ (a) (_ : a ∈ s) (b) (_ : b ∈ s), a < b → f b < f a)] : +instance [i : Decidable (∀ a ∈ s, ∀ b ∈ s, a < b → f b < f a)] : Decidable (StrictAntiOn f s) := i end Decidable diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index f62909baf08d2..5bd0cedbb4f68 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -120,7 +120,7 @@ variable (A K) /-- Send a set of `x`s in a finite extension `L` of the fraction field of `R` to `(y : R) • x ∈ integralClosure R L`. -/ theorem exists_integral_multiples (s : Finset L) : - ∃ (y : _) (_ : y ≠ (0 : A)), ∀ x ∈ s, IsIntegral A (y • x) := by + ∃ y ≠ (0 : A), ∀ x ∈ s, IsIntegral A (y • x) := by haveI := Classical.decEq L refine' s.induction _ _ · use 1, one_ne_zero diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 39c0d075a1d5a..43e909af119f5 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -1024,7 +1024,7 @@ theorem radical_eq_sInf (I : Ideal R) : radical I = sInf { J : Ideal R | I ≤ J hc hyc ⟨n, hrny⟩, fun z => le_sSup⟩) I hri - have : ∀ (x) (_ : x ∉ m), r ∈ radical (m ⊔ span {x}) := fun x hxm => + have : ∀ x ∉ m, r ∈ radical (m ⊔ span {x}) := fun x hxm => by_contradiction fun hrmx => hxm <| hm (m ⊔ span {x}) hrmx le_sup_left ▸ diff --git a/Mathlib/RingTheory/Ideal/Over.lean b/Mathlib/RingTheory/Ideal/Over.lean index c059a2e2d5cc1..b25859073ce05 100644 --- a/Mathlib/RingTheory/Ideal/Over.lean +++ b/Mathlib/RingTheory/Ideal/Over.lean @@ -55,7 +55,7 @@ theorem coeff_zero_mem_comap_of_root_mem {r : S} (hr : r ∈ I) {p : R[X]} (hp : theorem exists_coeff_ne_zero_mem_comap_of_non_zero_divisor_root_mem {r : S} (r_non_zero_divisor : ∀ {x}, x * r = 0 → x = 0) (hr : r ∈ I) {p : R[X]} : - ∀ (_ : p ≠ 0) (_ : p.eval₂ f r = 0), ∃ i, p.coeff i ≠ 0 ∧ p.coeff i ∈ I.comap f := by + p ≠ 0 → p.eval₂ f r = 0 → ∃ i, p.coeff i ≠ 0 ∧ p.coeff i ∈ I.comap f := by refine' p.recOnHorner _ _ _ · intro h contradiction @@ -194,7 +194,7 @@ variable {S : Type*} [CommRing S] {f : R →+* S} {I J : Ideal S} theorem exists_coeff_ne_zero_mem_comap_of_root_mem [IsDomain S] {r : S} (r_ne_zero : r ≠ 0) (hr : r ∈ I) {p : R[X]} : - ∀ (_ : p ≠ 0) (_ : p.eval₂ f r = 0), ∃ i, p.coeff i ≠ 0 ∧ p.coeff i ∈ I.comap f := + p ≠ 0 → p.eval₂ f r = 0 → ∃ i, p.coeff i ≠ 0 ∧ p.coeff i ∈ I.comap f := exists_coeff_ne_zero_mem_comap_of_non_zero_divisor_root_mem (fun {_} h => Or.resolve_right (mul_eq_zero.mp h) r_ne_zero) hr #align ideal.exists_coeff_ne_zero_mem_comap_of_root_mem Ideal.exists_coeff_ne_zero_mem_comap_of_root_mem diff --git a/Mathlib/RingTheory/IntegralDomain.lean b/Mathlib/RingTheory/IntegralDomain.lean index e2d25548254db..813c6e500a38b 100644 --- a/Mathlib/RingTheory/IntegralDomain.lean +++ b/Mathlib/RingTheory/IntegralDomain.lean @@ -72,7 +72,7 @@ theorem exists_eq_pow_of_mul_eq_pow_of_coprime {R : Type*} [CommSemiring R] [IsD nonrec theorem Finset.exists_eq_pow_of_mul_eq_pow_of_coprime {ι R : Type*} [CommSemiring R] [IsDomain R] [GCDMonoid R] [Unique Rˣ] {n : ℕ} {c : R} {s : Finset ι} {f : ι → R} - (h : ∀ (i) (_ : i ∈ s) (j) (_ : j ∈ s), i ≠ j → IsCoprime (f i) (f j)) + (h : ∀ i ∈ s, ∀ j ∈ s, i ≠ j → IsCoprime (f i) (f j)) (hprod : ∏ i in s, f i = c ^ n) : ∀ i ∈ s, ∃ d : R, f i = d ^ n := by classical intro i hi diff --git a/Mathlib/Topology/Algebra/UniformGroup.lean b/Mathlib/Topology/Algebra/UniformGroup.lean index c4f87c4163181..0d8ac0be372b4 100644 --- a/Mathlib/Topology/Algebra/UniformGroup.lean +++ b/Mathlib/Topology/Algebra/UniformGroup.lean @@ -765,8 +765,8 @@ variable (hφ : Continuous (fun p : β × δ => φ p.1 p.2)) variable {W' : Set G} (W'_nhd : W' ∈ 𝓝 (0 : G)) -private theorem extend_Z_bilin_aux (x₀ : α) (y₁ : δ) : ∃ U₂ ∈ comap e (𝓝 x₀), ∀ (x) (_ : x ∈ U₂) - (x') (_ : x' ∈ U₂), (fun p : β × δ => φ p.1 p.2) (x' - x, y₁) ∈ W' := by +private theorem extend_Z_bilin_aux (x₀ : α) (y₁ : δ) : ∃ U₂ ∈ comap e (𝓝 x₀), ∀ x ∈ U₂, ∀ x' ∈ U₂, + (fun p : β × δ => φ p.1 p.2) (x' - x, y₁) ∈ W' := by let Nx := 𝓝 x₀ let ee := fun u : β × β => (e u.1, e u.2) have lim1 : Tendsto (fun a : β × β => (a.2 - a.1, y₁)) @@ -784,7 +784,7 @@ private theorem extend_Z_bilin_aux (x₀ : α) (y₁ : δ) : ∃ U₂ ∈ comap #noalign dense_inducing.extend_Z_bilin_aux private theorem extend_Z_bilin_key (x₀ : α) (y₀ : γ) : ∃ U ∈ comap e (𝓝 x₀), ∃ V ∈ comap f (𝓝 y₀), - ∀ (x) (_ : x ∈ U) (x') (_ : x' ∈ U), ∀ (y) (_ : y ∈ V) (y') (_ : y' ∈ V), + ∀ x ∈ U, ∀ x' ∈ U, ∀ (y) (_ : y ∈ V) (y') (_ : y' ∈ V), (fun p : β × δ => φ p.1 p.2) (x', y') - (fun p : β × δ => φ p.1 p.2) (x, y) ∈ W' := by let ee := fun u : β × β => (e u.1, e u.2) let ff := fun u : δ × δ => (f u.1, f u.2) diff --git a/Mathlib/Topology/PartitionOfUnity.lean b/Mathlib/Topology/PartitionOfUnity.lean index 8a3267b212c00..0db4ce7f6f92b 100644 --- a/Mathlib/Topology/PartitionOfUnity.lean +++ b/Mathlib/Topology/PartitionOfUnity.lean @@ -203,12 +203,8 @@ variable {f} theorem exists_finset_nhd_support_subset {U : ι → Set X} (hso : f.IsSubordinate U) (ho : ∀ i, IsOpen (U i)) (x : X) : - ∃ (is : Finset ι) (n : Set X) (_ : n ∈ 𝓝 x) (_ : n ⊆ ⋂ i ∈ is, U i), - ∀ z ∈ n, (support fun i => f i z) ⊆ is := - -- Porting note: Original proof was simply - -- `f.locallyFinite.exists_finset_nhd_support_subset hso ho x` - let ⟨a, ⟨b, ⟨c, ⟨d, e⟩⟩⟩⟩ := f.locallyFinite.exists_finset_nhd_support_subset hso ho x - ⟨a, b, c, d, e⟩ + ∃ (is : Finset ι), ∃ n ∈ 𝓝 x, n ⊆ ⋂ i ∈ is, U i ∧ ∀ z ∈ n, (support (f · z)) ⊆ is := + f.locallyFinite.exists_finset_nhd_support_subset hso ho x #align partition_of_unity.exists_finset_nhd_support_subset PartitionOfUnity.exists_finset_nhd_support_subset /-- If `f` is a partition of unity that is subordinate to a family of open sets `U i` and diff --git a/Mathlib/Topology/UniformSpace/CompactConvergence.lean b/Mathlib/Topology/UniformSpace/CompactConvergence.lean index 8c101db2afbb4..87c07e30fd68d 100644 --- a/Mathlib/Topology/UniformSpace/CompactConvergence.lean +++ b/Mathlib/Topology/UniformSpace/CompactConvergence.lean @@ -154,8 +154,7 @@ def compactConvergenceFilterBasis (f : C(α, β)) : FilterBasis C(α, β) := theorem mem_compactConvergence_nhd_filter (Y : Set C(α, β)) : Y ∈ (compactConvergenceFilterBasis f).filter ↔ - ∃ (K : Set α) (V : Set (β × β)) (_hK : IsCompact K) (_hV : V ∈ 𝓤 β), - compactConvNhd K V f ⊆ Y := by + ∃ (K : Set α) (V : Set (β × β)), IsCompact K ∧ V ∈ 𝓤 β ∧ compactConvNhd K V f ⊆ Y := by constructor · rintro ⟨X, ⟨⟨K, V⟩, ⟨hK, hV⟩, rfl⟩, hY⟩ exact ⟨K, V, hK, hV, hY⟩ @@ -308,15 +307,14 @@ theorem hasBasis_compactConvergenceUniformity_aux : useful. -/ theorem mem_compactConvergenceUniformity (X : Set (C(α, β) × C(α, β))) : X ∈ @compactConvergenceUniformity α β _ _ ↔ - ∃ (K : Set α) (V : Set (β × β)) (_hK : IsCompact K) (_hV : V ∈ 𝓤 β), + ∃ (K : Set α) (V : Set (β × β)), IsCompact K ∧ V ∈ 𝓤 β ∧ { fg : C(α, β) × C(α, β) | ∀ x ∈ K, (fg.1 x, fg.2 x) ∈ V } ⊆ X := by simp only [hasBasis_compactConvergenceUniformity_aux.mem_iff, exists_prop, Prod.exists, and_assoc] #align continuous_map.mem_compact_convergence_uniformity ContinuousMap.mem_compactConvergenceUniformity /-- Note that we ensure the induced topology is definitionally the compact-open topology. -/ -instance compactConvergenceUniformSpace : UniformSpace C(α, β) - where +instance compactConvergenceUniformSpace : UniformSpace C(α, β) where uniformity := compactConvergenceUniformity refl := by simp only [compactConvergenceUniformity, and_imp, Filter.le_principal_iff, Prod.forall, @@ -348,14 +346,15 @@ instance compactConvergenceUniformSpace : UniformSpace C(α, β) refine' fun Y => forall₂_congr fun f hf => _ simp only [mem_compactConvergence_nhd_filter, mem_compactConvergenceUniformity, Prod.forall, setOf_subset_setOf, compactConvNhd] - refine' exists₄_congr fun K V _hK _hV => ⟨_, fun hY g hg => hY f g hg rfl⟩ + refine' exists₂_congr fun K V => and_congr_right' <| and_congr_right' + ⟨_, fun hY g hg => hY f g hg rfl⟩ rintro hY g₁ g₂ hg₁ rfl exact hY hg₁ #align continuous_map.compact_convergence_uniform_space ContinuousMap.compactConvergenceUniformSpace theorem mem_compactConvergence_entourage_iff (X : Set (C(α, β) × C(α, β))) : X ∈ 𝓤 C(α, β) ↔ - ∃ (K : Set α) (V : Set (β × β)) (_hK : IsCompact K) (_hV : V ∈ 𝓤 β), + ∃ (K : Set α) (V : Set (β × β)), IsCompact K ∧ V ∈ 𝓤 β ∧ { fg : C(α, β) × C(α, β) | ∀ x ∈ K, (fg.1 x, fg.2 x) ∈ V } ⊆ X := mem_compactConvergenceUniformity X #align continuous_map.mem_compact_convergence_entourage_iff ContinuousMap.mem_compactConvergence_entourage_iff From 490c92f8dbbd6ee71a847bcb0b6af9ec6cd73827 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Mon, 25 Dec 2023 13:26:05 +0000 Subject: [PATCH 169/353] feat(FieldTheory/Separable): add some results regarding separable and no repeated roots (#9263) - `nodup_[a]roots_iff_of_splits`: a polynomial has no repeated roots if and only if it is separable. - `card_rootSet_eq_natDegree_iff_of_splits`: a polynomial has number of roots equal to its degree if and only if it is separable. A converse to `card_rootSet_eq_natDegree`. Also add some convenience lemmas: - `Separable.ne_zero`: a separable polynomial is not zero. - `Separable.map_minpoly`: if an element is separable over a small field, then it's also separable over a large field. --- Mathlib/FieldTheory/Separable.lean | 40 +++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/Mathlib/FieldTheory/Separable.lean b/Mathlib/FieldTheory/Separable.lean index d84753e080e0c..8ae70dd7b20d9 100644 --- a/Mathlib/FieldTheory/Separable.lean +++ b/Mathlib/FieldTheory/Separable.lean @@ -53,6 +53,9 @@ theorem not_separable_zero [Nontrivial R] : ¬Separable (0 : R[X]) := by simp only [derivative_zero, mul_zero, add_zero, zero_ne_one] at h #align polynomial.not_separable_zero Polynomial.not_separable_zero +theorem Separable.ne_zero [Nontrivial R] {f : R[X]} (h : f.Separable) : f ≠ 0 := + (not_separable_zero <| · ▸ h) + theorem separable_one : (1 : R[X]).Separable := isCoprime_one_left #align polynomial.separable_one Polynomial.separable_one @@ -437,10 +440,32 @@ section Splits theorem card_rootSet_eq_natDegree [Algebra F K] {p : F[X]} (hsep : p.Separable) (hsplit : Splits (algebraMap F K) p) : Fintype.card (p.rootSet K) = p.natDegree := by simp_rw [rootSet_def, Finset.coe_sort_coe, Fintype.card_coe] - rw [Multiset.toFinset_card_of_nodup, ← natDegree_eq_card_roots hsplit] - exact nodup_roots hsep.map + rw [Multiset.toFinset_card_of_nodup (nodup_roots hsep.map), ← natDegree_eq_card_roots hsplit] #align polynomial.card_root_set_eq_nat_degree Polynomial.card_rootSet_eq_natDegree +/-- If a non-zero polynomial splits, then it has no repeated roots on that field +if and only if it is separable. -/ +theorem nodup_roots_iff_of_splits {f : F[X]} (hf : f ≠ 0) (h : f.Splits (RingHom.id F)) : + f.roots.Nodup ↔ f.Separable := by + refine ⟨(fun hnsep ↦ ?_).mtr, nodup_roots⟩ + rw [Separable, ← gcd_isUnit_iff, isUnit_iff_degree_eq_zero] at hnsep + obtain ⟨x, hx⟩ := exists_root_of_splits _ + (splits_of_splits_of_dvd _ hf h (gcd_dvd_left f _)) hnsep + simp_rw [Multiset.nodup_iff_count_le_one, not_forall, not_le] + exact ⟨x, ((one_lt_rootMultiplicity_iff_isRoot_gcd hf).2 hx).trans_eq f.count_roots.symm⟩ + +/-- If a non-zero polynomial over `F` splits in `K`, then it has no repeated roots on `K` +if and only if it is separable. -/ +theorem nodup_aroots_iff_of_splits [Algebra F K] {f : F[X]} (hf : f ≠ 0) + (h : f.Splits (algebraMap F K)) : (f.aroots K).Nodup ↔ f.Separable := by + rw [← (algebraMap F K).id_comp, ← splits_map_iff] at h + rw [nodup_roots_iff_of_splits (map_ne_zero hf) h, separable_map] + +theorem card_rootSet_eq_natDegree_iff_of_splits [Algebra F K] {f : F[X]} (hf : f ≠ 0) + (h : f.Splits (algebraMap F K)) : Fintype.card (f.rootSet K) = f.natDegree ↔ f.Separable := by + simp_rw [rootSet_def, Finset.coe_sort_coe, Fintype.card_coe, natDegree_eq_card_roots h, + Multiset.toFinset_card_eq_card_iff_nodup, nodup_aroots_iff_of_splits hf h] + variable {i : F →+* K} theorem eq_X_sub_C_of_separable_of_root_eq {x : F} {h : F[X]} (h_sep : h.Separable) @@ -528,7 +553,7 @@ theorem Polynomial.Separable.isIntegral {x : K} (h : (minpoly F x).Separable) : cases subsingleton_or_nontrivial F · haveI := Module.subsingleton F K exact ⟨1, monic_one, Subsingleton.elim _ _⟩ - · exact of_not_not fun h' ↦ not_separable_zero (minpoly.eq_zero h' ▸ h) + · exact of_not_not (h.ne_zero <| minpoly.eq_zero ·) theorem IsSeparable.isIntegral [IsSeparable F K] : ∀ x : K, IsIntegral F x := fun x ↦ (IsSeparable.separable F x).isIntegral @@ -571,11 +596,18 @@ instance (priority := 100) IsSeparable.of_finite (F K : Type*) [Field F] [Field section IsSeparableTower +/-- If `R / K / A` is an extension tower, `x : R` is separable over `A`, then it's also separable +over `K`. -/ +theorem Polynomial.Separable.map_minpoly {A : Type*} [CommRing A] + (K : Type*) [Field K] [Algebra A K] {R : Type*} [CommRing R] [Algebra A R] [Algebra K R] + [IsScalarTower A K R] {x : R} (h : (minpoly A x).Separable) : (minpoly K x).Separable := + h.map.of_dvd (minpoly.dvd_map_of_isScalarTower _ _ _) + variable (F K E : Type*) [Field F] [Field K] [Field E] [Algebra F K] [Algebra F E] [Algebra K E] [IsScalarTower F K E] theorem isSeparable_tower_top_of_isSeparable [IsSeparable F E] : IsSeparable K E := - ⟨fun x ↦ (IsSeparable.separable F x).map.of_dvd (minpoly.dvd_map_of_isScalarTower _ _ _)⟩ + ⟨fun x ↦ (IsSeparable.separable F x).map_minpoly _⟩ #align is_separable_tower_top_of_is_separable isSeparable_tower_top_of_isSeparable theorem isSeparable_tower_bot_of_isSeparable [h : IsSeparable F E] : IsSeparable F K := From 1edf6ce47ed7f185b313658f5ba148b929aad69b Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Dec 2023 14:38:04 +0000 Subject: [PATCH 170/353] feat(Normed/Group): add `Filter.HasBasis.cobounded_of_norm` (#9244) --- Mathlib/Analysis/Normed/Group/Basic.lean | 9 +++++++++ Mathlib/Analysis/NormedSpace/Spectrum.lean | 7 +++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Mathlib/Analysis/Normed/Group/Basic.lean b/Mathlib/Analysis/Normed/Group/Basic.lean index 3b0235511df7b..d6db12edc4426 100644 --- a/Mathlib/Analysis/Normed/Group/Basic.lean +++ b/Mathlib/Analysis/Normed/Group/Basic.lean @@ -413,6 +413,15 @@ theorem Isometry.norm_map_of_map_one {f : E → F} (hi : Isometry f) (h₁ : f 1 theorem comap_norm_atTop' : comap norm atTop = cobounded E := by simpa only [dist_one_right] using comap_dist_right_atTop (1 : E) +@[to_additive Filter.HasBasis.cobounded_of_norm] +lemma Filter.HasBasis.cobounded_of_norm' {ι : Sort*} {p : ι → Prop} {s : ι → Set ℝ} + (h : HasBasis atTop p s) : HasBasis (cobounded E) p fun i ↦ norm ⁻¹' s i := + comap_norm_atTop' (E := E) ▸ h.comap _ + +@[to_additive Filter.hasBasis_cobounded_norm] +lemma Filter.hasBasis_cobounded_norm' : HasBasis (cobounded E) (fun _ ↦ True) ({x | · ≤ ‖x‖}) := + atTop_basis.cobounded_of_norm' + @[to_additive (attr := simp) tendsto_norm_atTop_iff_cobounded] theorem tendsto_norm_atTop_iff_cobounded' {f : α → E} {l : Filter α} : Tendsto (‖f ·‖) l atTop ↔ Tendsto f l (cobounded E) := by diff --git a/Mathlib/Analysis/NormedSpace/Spectrum.lean b/Mathlib/Analysis/NormedSpace/Spectrum.lean index a470299779ba0..46649c95784fe 100644 --- a/Mathlib/Analysis/NormedSpace/Spectrum.lean +++ b/Mathlib/Analysis/NormedSpace/Spectrum.lean @@ -226,9 +226,8 @@ theorem hasDerivAt_resolvent {a : A} {k : 𝕜} (hk : k ∈ ρ a) : #noalign spectrum.norm_resolvent_le_forall theorem eventually_isUnit_resolvent (a : A) : ∀ᶠ z in cobounded 𝕜, IsUnit (resolvent a z) := by - rw [← comap_norm_atTop, atTop_basis.comap (‖·‖) |>.eventually_iff] - refine ⟨‖a‖ * ‖(1 : A)‖ + 1, by trivial, fun z hz ↦ ?_⟩ - exact isUnit_resolvent.mp <| mem_resolventSet_of_norm_lt_mul <| (lt_add_one (‖a‖ * _)).trans_le hz + rw [atTop_basis_Ioi.cobounded_of_norm.eventually_iff] + exact ⟨‖a‖ * ‖(1 : A)‖, trivial, fun _ ↦ isUnit_resolvent.mp ∘ mem_resolventSet_of_norm_lt_mul⟩ theorem resolvent_isBigO_inv (a : A) : resolvent a =O[cobounded 𝕜] Inv.inv := have h : (fun z ↦ resolvent (z⁻¹ • a) (1 : 𝕜)) =O[cobounded 𝕜] (fun _ ↦ (1 : ℝ)) := by @@ -240,7 +239,7 @@ theorem resolvent_isBigO_inv (a : A) : resolvent a =O[cobounded 𝕜] Inv.inv := filter_upwards [isBounded_singleton (x := 0)] with z hz lift z to 𝕜ˣ using Ne.isUnit hz simpa [Units.smul_def] using congr(z⁻¹ • $(units_smul_resolvent_self (r := z) (a := a))) - _ =O[cobounded 𝕜] (· ⁻¹) := IsBigO.of_norm_right <| by + _ =O[cobounded 𝕜] (· ⁻¹) := .of_norm_right <| by simpa using (isBigO_refl (· ⁻¹) (cobounded 𝕜)).norm_right.smul h theorem resolvent_tendsto_cobounded (a : A) : Tendsto (resolvent a) (cobounded 𝕜) (𝓝 0) := From 42ab70e7053780bb3ec0780a68443214ec958f3b Mon Sep 17 00:00:00 2001 From: grunweg Date: Mon, 25 Dec 2023 15:55:16 +0000 Subject: [PATCH 171/353] feat: (partial) homeomorphisms are local homeomorphisms (#9246) Co-authored-by: grunweg --- Mathlib/Topology/IsLocalHomeomorph.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Mathlib/Topology/IsLocalHomeomorph.lean b/Mathlib/Topology/IsLocalHomeomorph.lean index b6445d9ad5987..758f53745e802 100644 --- a/Mathlib/Topology/IsLocalHomeomorph.lean +++ b/Mathlib/Topology/IsLocalHomeomorph.lean @@ -77,6 +77,11 @@ theorem mk (h : ∀ x ∈ s, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ S hx, rfl⟩ #align is_locally_homeomorph_on.mk IsLocalHomeomorphOn.mk +/-- A `PartialHomeomorph` is a local homeomorphism on its source. -/ +lemma PartialHomeomorph.isLocalHomeomorphOn (e : PartialHomeomorph X Y) : + IsLocalHomeomorphOn e e.source := + fun _ hx ↦ ⟨e, hx, rfl⟩ + variable {g f s t} theorem mono {t : Set X} (hf : IsLocalHomeomorphOn f t) (hst : s ⊆ t) : IsLocalHomeomorphOn f s := @@ -169,6 +174,10 @@ theorem mk (h : ∀ x : X, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ Set (IsLocalHomeomorphOn.mk f Set.univ fun x _hx ↦ h x) #align is_locally_homeomorph.mk IsLocalHomeomorph.mk +/-- A homeomorphism is a local homeomorphism. -/ +lemma Homeomorph.isLocalHomeomorph (h : X ≃ₜ Y) : IsLocalHomeomorph h := + fun _ ↦ ⟨h.toPartialHomeomorph, trivial, rfl⟩ + variable {g f} lemma isLocallyInjective (hf : IsLocalHomeomorph f) : IsLocallyInjective f := From 0a89f4620adb6c399d759d717fb2770e10cddd23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 25 Dec 2023 16:17:43 +0000 Subject: [PATCH 172/353] chore: Deprecate pow monotonicity lemmas (#9235) Add deprecated aliases for all the lemmas removed in #9095 and fix a few renames that were botched. --- .../Algebra/GroupPower/CovariantClass.lean | 54 +++++++++++++++---- Mathlib/Algebra/GroupPower/Order.lean | 24 +++++++++ Mathlib/Data/Nat/Pow.lean | 13 +++++ 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/Mathlib/Algebra/GroupPower/CovariantClass.lean b/Mathlib/Algebra/GroupPower/CovariantClass.lean index a89c22c72e81f..cb069580a1f15 100644 --- a/Mathlib/Algebra/GroupPower/CovariantClass.lean +++ b/Mathlib/Algebra/GroupPower/CovariantClass.lean @@ -175,19 +175,18 @@ variable [Preorder β] [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] @[to_additive Monotone.const_nsmul] -theorem Monotone.pow_right {f : β → M} (hf : Monotone f) : ∀ n : ℕ, Monotone fun a => f a ^ n +theorem Monotone.pow_const {f : β → M} (hf : Monotone f) : ∀ n : ℕ, Monotone fun a => f a ^ n | 0 => by simpa using monotone_const | n + 1 => by simp_rw [pow_succ] - exact hf.mul' (Monotone.pow_right hf _) -#align monotone.pow_right Monotone.pow_right + exact hf.mul' (Monotone.pow_const hf _) +#align monotone.pow_right Monotone.pow_const #align monotone.const_nsmul Monotone.const_nsmul -@[to_additive nsmul_mono_left] -theorem pow_mono_right (n : ℕ) : Monotone fun a : M => a ^ n := - monotone_id.pow_right _ -#align pow_mono_right pow_mono_right -#align nsmul_mono_left nsmul_mono_left +@[to_additive nsmul_right_mono] +theorem pow_left_mono (n : ℕ) : Monotone fun a : M => a ^ n := monotone_id.pow_const _ +#align pow_mono_right pow_left_mono +#align nsmul_mono_left nsmul_right_mono end CovariantLESwap @@ -276,7 +275,7 @@ variable [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap ( @[to_additive lt_of_nsmul_lt_nsmul_right] theorem lt_of_pow_lt_pow_left' {a b : M} (n : ℕ) : a ^ n < b ^ n → a < b := - (pow_mono_right _).reflect_lt + (pow_left_mono _).reflect_lt #align lt_of_pow_lt_pow' lt_of_pow_lt_pow_left' #align lt_of_nsmul_lt_nsmul lt_of_nsmul_lt_nsmul_right @@ -298,11 +297,11 @@ section CovariantLTSwap variable [CovariantClass M M (· * ·) (· < ·)] [CovariantClass M M (swap (· * ·)) (· < ·)] -@[to_additive le_of_nsmul_le_nsmul_right'] +@[to_additive le_of_nsmul_le_nsmul_right] theorem le_of_pow_le_pow_left' {a b : M} {n : ℕ} (hn : n ≠ 0) : a ^ n ≤ b ^ n → a ≤ b := (pow_left_strictMono hn).le_iff_le.1 #align le_of_pow_le_pow' le_of_pow_le_pow_left' -#align le_of_nsmul_le_nsmul le_of_nsmul_le_nsmul_right' +#align le_of_nsmul_le_nsmul le_of_nsmul_le_nsmul_right @[to_additive min_le_of_add_le_two_nsmul] theorem min_le_of_mul_le_sq {a b c : M} (h : a * b ≤ c ^ 2) : min a b ≤ c := by @@ -357,3 +356,36 @@ theorem one_le_zpow {x : G} (H : 1 ≤ x) {n : ℤ} (hn : 0 ≤ n) : 1 ≤ x ^ n #align zsmul_nonneg zsmul_nonneg end DivInvMonoid + +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on 2023-12-23. +-/ + +@[deprecated] alias pow_le_pow_of_le_left' := pow_le_pow_left' +@[deprecated] alias nsmul_le_nsmul_of_le_right := nsmul_le_nsmul_right +@[deprecated] alias pow_lt_pow' := pow_lt_pow_right' +@[deprecated] alias nsmul_lt_nsmul := nsmul_lt_nsmul_left +@[deprecated] alias pow_strictMono_left := pow_right_strictMono' +@[deprecated] alias nsmul_strictMono_right := nsmul_left_strictMono +@[deprecated] alias StrictMono.pow_right' := StrictMono.pow_const +@[deprecated] alias StrictMono.nsmul_left := StrictMono.const_nsmul +@[deprecated] alias pow_strictMono_right' := pow_left_strictMono +@[deprecated] alias nsmul_strictMono_left := nsmul_right_strictMono +@[deprecated] alias Monotone.pow_right := Monotone.pow_const +@[deprecated] alias Monotone.nsmul_left := Monotone.const_nsmul +@[deprecated] alias lt_of_pow_lt_pow' := lt_of_pow_lt_pow_left' +@[deprecated] alias lt_of_nsmul_lt_nsmul := lt_of_nsmul_lt_nsmul_right +@[deprecated] alias pow_le_pow' := pow_le_pow_right' +@[deprecated] alias nsmul_le_nsmul := nsmul_le_nsmul_left +@[deprecated] alias pow_le_pow_of_le_one' := pow_le_pow_right_of_le_one' +@[deprecated] alias nsmul_le_nsmul_of_nonpos := nsmul_le_nsmul_left_of_nonpos +@[deprecated] alias le_of_pow_le_pow' := le_of_pow_le_pow_left' +@[deprecated] alias le_of_nsmul_le_nsmul := le_of_nsmul_le_nsmul_right +@[deprecated] alias pow_le_pow_iff' := pow_le_pow_iff_right' +@[deprecated] alias nsmul_le_nsmul_iff := nsmul_le_nsmul_iff_left +@[deprecated] alias pow_lt_pow_iff' := pow_lt_pow_iff_right' +@[deprecated] alias nsmul_lt_nsmul_iff := nsmul_lt_nsmul_iff_left +@[deprecated] alias pow_mono_right := pow_left_mono +@[deprecated] alias nsmul_mono_left := nsmul_right_mono diff --git a/Mathlib/Algebra/GroupPower/Order.lean b/Mathlib/Algebra/GroupPower/Order.lean index efb81ce3e9cac..cc7b451a04e82 100644 --- a/Mathlib/Algebra/GroupPower/Order.lean +++ b/Mathlib/Algebra/GroupPower/Order.lean @@ -458,3 +458,27 @@ theorem map_sub_swap (x y : R) : f (x - y) = f (y - x) := by rw [← map_neg, ne #align monoid_hom.map_sub_swap MonoidHom.map_sub_swap end MonoidHom + +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on 2023-12-23. +-/ + +@[deprecated] alias pow_mono := pow_right_mono +@[deprecated] alias pow_le_pow := pow_le_pow_right +@[deprecated] alias pow_le_pow_of_le_left := pow_le_pow_left +@[deprecated] alias pow_lt_pow_of_lt_left := pow_lt_pow_left +@[deprecated] alias strictMonoOn_pow := pow_left_strictMonoOn +@[deprecated] alias pow_strictMono_right := pow_right_strictMono +@[deprecated] alias pow_lt_pow := pow_lt_pow_right +@[deprecated] alias pow_lt_pow_iff := pow_lt_pow_iff_right +@[deprecated] alias pow_le_pow_iff := pow_le_pow_iff_right +@[deprecated] alias self_lt_pow := lt_self_pow +@[deprecated] alias strictAnti_pow := pow_right_strictAnti +@[deprecated] alias pow_lt_pow_iff_of_lt_one := pow_lt_pow_iff_right_of_lt_one +@[deprecated] alias pow_lt_pow_of_lt_one := pow_lt_pow_right_of_lt_one +@[deprecated] alias lt_of_pow_lt_pow := lt_of_pow_lt_pow_left +@[deprecated] alias le_of_pow_le_pow := le_of_pow_le_pow_left +@[deprecated] alias pow_lt_pow₀ := pow_lt_pow_right₀ +@[deprecated] alias self_le_pow := le_self_pow diff --git a/Mathlib/Data/Nat/Pow.lean b/Mathlib/Data/Nat/Pow.lean index 41d571b67e98a..b2df1c6ac4d24 100644 --- a/Mathlib/Data/Nat/Pow.lean +++ b/Mathlib/Data/Nat/Pow.lean @@ -228,3 +228,16 @@ theorem lt_of_pow_dvd_right {p i n : ℕ} (hn : n ≠ 0) (hp : 2 ≤ p) (h : p ^ #align nat.lt_of_pow_dvd_right Nat.lt_of_pow_dvd_right end Nat + +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on 2023-12-23. +-/ + +@[deprecated] alias Nat.pow_lt_pow_of_lt_left := Nat.pow_lt_pow_left +@[deprecated] alias Nat.pow_le_iff_le_left := Nat.pow_le_pow_iff_left +@[deprecated] alias Nat.pow_lt_pow_of_lt_right := pow_lt_pow_right +@[deprecated] protected alias Nat.pow_right_strictMono := pow_right_strictMono +@[deprecated] alias Nat.pow_le_iff_le_right := pow_le_pow_iff_right +@[deprecated] alias Nat.pow_lt_iff_lt_right := pow_lt_pow_iff_right From f1addf8d8855ededf73b4ce8cfae76f04102dd50 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Mon, 25 Dec 2023 17:37:26 +0000 Subject: [PATCH 173/353] feat(FieldTheory/Adjoin): add `exists_lt_finrank_of_infinite_dimensional` (#9262) ... which state that an infinite algebraic extension has finite subextension with arbitrary large degree. --- Mathlib/FieldTheory/Adjoin.lean | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Mathlib/FieldTheory/Adjoin.lean b/Mathlib/FieldTheory/Adjoin.lean index 304f4cbfc7be9..893429365694b 100644 --- a/Mathlib/FieldTheory/Adjoin.lean +++ b/Mathlib/FieldTheory/Adjoin.lean @@ -1043,6 +1043,26 @@ theorem adjoin_minpoly_coeff_of_exists_primitive_element ((g.monic_toSubring _ _).mpr <| (minpoly.monic <| .of_finite K α).map _).ne_zero using 1 rw [natDegree_toSubring, natDegree_map] +variable {F} in +/-- If `E / F` is an infinite algebraic extension, then there exists an intermediate field +`L / F` with arbitrarily large finite extension degree. -/ +theorem exists_lt_finrank_of_infinite_dimensional + (halg : Algebra.IsAlgebraic F E) (hnfd : ¬ FiniteDimensional F E) (n : ℕ) : + ∃ L : IntermediateField F E, FiniteDimensional F L ∧ n < finrank F L := by + induction' n with n ih + · exact ⟨⊥, Subalgebra.finiteDimensional_bot, finrank_pos⟩ + obtain ⟨L, fin, hn⟩ := ih + obtain ⟨x, hx⟩ : ∃ x : E, x ∉ L := by + contrapose! hnfd + rw [show L = ⊤ from eq_top_iff.2 fun x _ ↦ hnfd x] at fin + exact topEquiv.toLinearEquiv.finiteDimensional + let L' := L ⊔ F⟮x⟯ + haveI := adjoin.finiteDimensional (halg x).isIntegral + refine ⟨L', inferInstance, by_contra fun h ↦ ?_⟩ + have h1 : L = L' := eq_of_le_of_finrank_le le_sup_left ((not_lt.1 h).trans hn) + have h2 : F⟮x⟯ ≤ L' := le_sup_right + exact hx <| (h1.symm ▸ h2) <| mem_adjoin_simple_self F x + theorem _root_.minpoly.natDegree_le (x : L) [FiniteDimensional K L] : (minpoly K x).natDegree ≤ finrank K L := le_of_eq_of_le (IntermediateField.adjoin.finrank (.of_finite _ _)).symm From c26c85d1328a8c7f0134ac387dc97ea8a8660afb Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Dec 2023 18:05:53 +0000 Subject: [PATCH 174/353] feat(Stirling): add a version in terms of `IsEquivalent` (#9231) --- Mathlib/Analysis/SpecialFunctions/Stirling.lean | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Mathlib/Analysis/SpecialFunctions/Stirling.lean b/Mathlib/Analysis/SpecialFunctions/Stirling.lean index cc0e9e7df53c8..2ff8d44070f19 100644 --- a/Mathlib/Analysis/SpecialFunctions/Stirling.lean +++ b/Mathlib/Analysis/SpecialFunctions/Stirling.lean @@ -32,7 +32,7 @@ formula for `π`. -/ -open scoped Topology Real BigOperators Nat +open scoped Topology Real BigOperators Nat Asymptotics open Finset Filter Nat Real @@ -254,4 +254,16 @@ theorem tendsto_stirlingSeq_sqrt_pi : Tendsto (fun n : ℕ => stirlingSeq n) atT rwa [(div_left_inj' (two_ne_zero' ℝ)).mp hπ, sqrt_sq hapos.le] #align stirling.tendsto_stirling_seq_sqrt_pi Stirling.tendsto_stirlingSeq_sqrt_pi +/-- **Stirling's Formula**, formulated in terms of `Asymptotics.IsEquivalent`. -/ +lemma factorial_isEquivalent_stirling : + (fun n ↦ n ! : ℕ → ℝ) ~[atTop] fun n ↦ Real.sqrt (2 * n * π) * (n / exp 1) ^ n := by + refine Asymptotics.isEquivalent_of_tendsto_one ?_ ?_ + · filter_upwards [eventually_ne_atTop 0] with n hn h + exact absurd h (by positivity) + · have : sqrt π ≠ 0 := by positivity + nth_rewrite 2 [← div_self this] + convert tendsto_stirlingSeq_sqrt_pi.div tendsto_const_nhds this using 1 + ext n + field_simp [stirlingSeq, mul_right_comm] + end Stirling From 5ca2c4b10cd771000d2102070f389ad62d538f9c Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Mon, 25 Dec 2023 18:05:54 +0000 Subject: [PATCH 175/353] feat(Algebra/CharP/ExpChar): add `expChar[_pow]_pos` (#9260) ... which states that (the power of) exponential characteristic is positive. --- Mathlib/Algebra/CharP/ExpChar.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Mathlib/Algebra/CharP/ExpChar.lean b/Mathlib/Algebra/CharP/ExpChar.lean index f6bb0308c0a4a..94d248dd17670 100644 --- a/Mathlib/Algebra/CharP/ExpChar.lean +++ b/Mathlib/Algebra/CharP/ExpChar.lean @@ -107,6 +107,15 @@ theorem expChar_is_prime_or_one (q : ℕ) [hq : ExpChar R q] : Nat.Prime q ∨ q case prime hp _ => exact .inl hp #align exp_char_is_prime_or_one expChar_is_prime_or_one +/-- The exponential characteristic is positive. -/ +theorem expChar_pos (q : ℕ) [ExpChar R q] : 0 < q := by + rcases expChar_is_prime_or_one R q with h | rfl + exacts [Nat.Prime.pos h, Nat.one_pos] + +/-- Any power of the exponential characteristic is positive. -/ +theorem expChar_pow_pos (q : ℕ) [ExpChar R q] (n : ℕ) : 0 < q ^ n := + Nat.pos_pow_of_pos n (expChar_pos R q) + end NoZeroDivisors end Nontrivial From b1556bbbbd8d64d5c27db7c0440ee7239f8ecf46 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Mon, 25 Dec 2023 18:05:55 +0000 Subject: [PATCH 176/353] feat(Data/Polynomial/Expand): add `leadingCoeff_expand` and `monic_expand_iff` (#9261) The first states that `expand` preserves leading coefficient; the second states that `expand` preserves monicity, hence gives a converse to `Monic.expand`. --- Mathlib/Data/Polynomial/Expand.lean | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Mathlib/Data/Polynomial/Expand.lean b/Mathlib/Data/Polynomial/Expand.lean index e49abfdba91c5..795deb2c365bc 100644 --- a/Mathlib/Data/Polynomial/Expand.lean +++ b/Mathlib/Data/Polynomial/Expand.lean @@ -170,9 +170,14 @@ theorem natDegree_expand (p : ℕ) (f : R[X]) : (expand R p f).natDegree = f.nat exact mt leadingCoeff_eq_zero.1 hf #align polynomial.nat_degree_expand Polynomial.natDegree_expand -theorem Monic.expand {p : ℕ} {f : R[X]} (hp : 0 < p) (h : f.Monic) : (expand R p f).Monic := by - rw [Monic.def, Polynomial.leadingCoeff, natDegree_expand, coeff_expand hp] - simp [hp, h] +theorem leadingCoeff_expand {p : ℕ} {f : R[X]} (hp : 0 < p) : + (expand R p f).leadingCoeff = f.leadingCoeff := by + simp_rw [leadingCoeff, natDegree_expand, coeff_expand_mul hp] + +theorem monic_expand_iff {p : ℕ} {f : R[X]} (hp : 0 < p) : (expand R p f).Monic ↔ f.Monic := by + simp only [Monic, leadingCoeff_expand hp] + +alias ⟨_, Monic.expand⟩ := monic_expand_iff #align polynomial.monic.expand Polynomial.Monic.expand theorem map_expand {p : ℕ} {f : R →+* S} {q : R[X]} : From 76d03d77d104449a51a5e8c24cb65d4968034992 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Mon, 25 Dec 2023 18:43:44 +0000 Subject: [PATCH 177/353] refactor: Subfield of DivisionRing, not just Field (#8941) The definition of `Subfield.closure` is changed to use `sInf` like many substructures. In the commutative case (at the end of the file), it's shown to be equal to the original version, renamed to `commClosure`, in the new lemma `commClosure_eq_closure`. No lemma is removed, and all lemma statements remain the same. I do not change the name `Subfield` to `SubdivisionRing` as this kind of name abuse is accepted practice in mathlib, and since a division ring is also called a skew field. Also generalizes `RingHom.eqLocus(Field)` slightly. Co-authored-by: Junyan Xu --- Mathlib/FieldTheory/Subfield.lean | 180 +++++++++++++++----------- Mathlib/RingTheory/Subring/Basic.lean | 6 + 2 files changed, 111 insertions(+), 75 deletions(-) diff --git a/Mathlib/FieldTheory/Subfield.lean b/Mathlib/FieldTheory/Subfield.lean index d6b8b89dd0a7a..9a2524a8a7bb5 100644 --- a/Mathlib/FieldTheory/Subfield.lean +++ b/Mathlib/FieldTheory/Subfield.lean @@ -11,27 +11,29 @@ import Mathlib.Algebra.Order.Field.InjSurj /-! # Subfields -Let `K` be a field. This file defines the "bundled" subfield type `Subfield K`, a type -whose terms correspond to subfields of `K`. This is the preferred way to talk +Let `K` be a division ring, for example a field. +This file defines the "bundled" subfield type `Subfield K`, a type +whose terms correspond to subfields of `K`. Note we do not require the "subfields" to be +commutative, so they are really sub-division rings / skew fields. This is the preferred way to talk about subfields in mathlib. Unbundled subfields (`s : Set K` and `IsSubfield s`) are not in this file, and they will ultimately be deprecated. We prove that subfields are a complete lattice, and that you can `map` (pushforward) and `comap` (pull back) them along ring homomorphisms. -We define the `closure` construction from `Set R` to `Subfield R`, sending a subset of `R` +We define the `closure` construction from `Set K` to `Subfield K`, sending a subset of `K` to the subfield it generates, and prove that it is a Galois insertion. ## Main definitions Notation used here: -`(K : Type u) [Field K] (L : Type u) [Field L] (f g : K →+* L)` +`(K : Type u) [DivisionRing K] (L : Type u) [DivisionRing L] (f g : K →+* L)` `(A : Subfield K) (B : Subfield L) (s : Set K)` -* `Subfield R` : the type of subfields of a ring `R`. +* `Subfield K` : the type of subfields of a division ring `K`. -* `instance : CompleteLattice (Subfield R)` : the complete lattice structure on the subfields. +* `instance : CompleteLattice (Subfield K)` : the complete lattice structure on the subfields. * `Subfield.closure` : subfield closure of a set, i.e., the smallest subfield that includes the set. @@ -42,9 +44,7 @@ Notation used here: * `map f A : Subfield L` : the image of a subfield `A` along the ring homomorphism `f`. -* `prod A B : Subfield (K × L)` : the product of subfields - -* `f.fieldRange : Subfield B` : the range of the ring homomorphism `f`. +* `f.fieldRange : Subfield L` : the range of the ring homomorphism `f`. * `eqLocusField f g : Subfield K` : given ring homomorphisms `f g : K →+* R`, the subfield of `K` where `f x = g x` @@ -65,10 +65,11 @@ open BigOperators universe u v w -variable {K : Type u} {L : Type v} {M : Type w} [Field K] [Field L] [Field M] +variable {K : Type u} {L : Type v} {M : Type w} +variable [DivisionRing K] [DivisionRing L] [DivisionRing M] /-- `SubfieldClass S K` states `S` is a type of subsets `s ⊆ K` closed under field operations. -/ -class SubfieldClass (S K : Type*) [Field K] [SetLike S K] extends SubringClass S K, +class SubfieldClass (S K : Type*) [DivisionRing K] [SetLike S K] extends SubringClass S K, InvMemClass S K : Prop #align subfield_class SubfieldClass @@ -122,9 +123,18 @@ theorem coe_rat_smul (s : S) (a : ℚ) (x : s) : ↑(a • x) = a • (x : K) := variable (S) +/-- A subfield inherits a division ring structure -/ +instance (priority := 75) toDivisionRing (s : S) : DivisionRing s := + Subtype.coe_injective.divisionRing ((↑) : s → K) + (by rfl) (by rfl) (by intros _ _; rfl) (by intros _ _; rfl) (by intros _; rfl) + (by intros _ _; rfl) (by intros _; rfl) (by intros _ _; rfl) (by intros _ _; rfl) + (by intros _ _; rfl) (by intros _ _; rfl) (by intros _ _; rfl) (by intros _ _; rfl) + (by intros _; rfl) (by intros _; rfl) (by intros _; rfl) + -- Prefer subclasses of `Field` over subclasses of `SubfieldClass`. -/-- A subfield inherits a field structure -/ -instance (priority := 75) toField (s : S) : Field s := +/-- A subfield of a field inherits a field structure -/ +instance (priority := 75) toField {K} [Field K] [SetLike S K] [SubfieldClass S K] (s : S) : + Field s := Subtype.coe_injective.field ((↑) : s → K) (by rfl) (by rfl) (by intros _ _; rfl) (by intros _ _; rfl) (by intros _; rfl) (by intros _ _; rfl) (by intros _; rfl) (by intros _ _; rfl) (by intros _ _; rfl) @@ -148,7 +158,7 @@ end SubfieldClass /-- `Subfield R` is the type of subfields of `R`. A subfield of `R` is a subset `s` that is a multiplicative submonoid and an additive subgroup. Note in particular that it shares the same 0 and 1 as R. -/ -structure Subfield (K : Type u) [Field K] extends Subring K where +structure Subfield (K : Type u) [DivisionRing K] extends Subring K where /-- A subfield is closed under multiplicative inverses. -/ inv_mem' : ∀ x ∈ carrier, x⁻¹ ∈ carrier #align subfield Subfield @@ -299,22 +309,11 @@ protected theorem list_sum_mem {l : List K} : (∀ x ∈ l, x ∈ s) → l.sum list_sum_mem #align subfield.list_sum_mem Subfield.list_sum_mem -/-- Product of a multiset of elements in a subfield is in the subfield. -/ -protected theorem multiset_prod_mem (m : Multiset K) : (∀ a ∈ m, a ∈ s) → m.prod ∈ s := - multiset_prod_mem m -#align subfield.multiset_prod_mem Subfield.multiset_prod_mem - /-- Sum of a multiset of elements in a `Subfield` is in the `Subfield`. -/ protected theorem multiset_sum_mem (m : Multiset K) : (∀ a ∈ m, a ∈ s) → m.sum ∈ s := multiset_sum_mem m #align subfield.multiset_sum_mem Subfield.multiset_sum_mem -/-- Product of elements of a subfield indexed by a `Finset` is in the subfield. -/ -protected theorem prod_mem {ι : Type*} {t : Finset ι} {f : ι → K} (h : ∀ c ∈ t, f c ∈ s) : - (∏ i in t, f i) ∈ s := - prod_mem h -#align subfield.prod_mem Subfield.prod_mem - /-- Sum of elements in a `Subfield` indexed by a `Finset` is in the `Subfield`. -/ protected theorem sum_mem {ι : Type*} {t : Finset ι} {f : ι → K} (h : ∀ c ∈ t, f c ∈ s) : (∑ i in t, f i) ∈ s := @@ -351,8 +350,13 @@ instance : Inv s := instance : Pow s ℤ := ⟨fun x z => ⟨x ^ z, s.zpow_mem x.2 z⟩⟩ +instance toDivisionRing (s : Subfield K) : DivisionRing s := + Subtype.coe_injective.divisionRing ((↑) : s → K) rfl rfl (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) + (fun _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) + (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ ↦ rfl) fun _ ↦ rfl + /-- A subfield inherits a field structure -/ -instance toField : Field s := +instance toField {K} [Field K] (s : Subfield K) : Field s := Subtype.coe_injective.field ((↑) : s → K) rfl rfl (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ => rfl) fun _ => rfl @@ -413,16 +417,13 @@ def subtype (s : Subfield K) : s →+* K := { s.toSubmonoid.subtype, s.toAddSubgroup.subtype with toFun := (↑) } #align subfield.subtype Subfield.subtype -instance toAlgebra : Algebra s K := - RingHom.toAlgebra s.subtype -#align subfield.to_algebra Subfield.toAlgebra - @[simp] theorem coe_subtype : ⇑(s.subtype) = ((↑) : s → K) := rfl #align subfield.coe_subtype Subfield.coe_subtype -theorem toSubring_subtype_eq_subtype (F : Type*) [Field F] (S : Subfield F) : +variable (K) in +theorem toSubring_subtype_eq_subtype (S : Subfield K) : S.toSubring.subtype = S.subtype := rfl #align subfield.to_subring.subtype_eq_subtype Subfield.toSubring_subtype_eq_subtype @@ -665,57 +666,26 @@ instance : CompleteLattice (Subfield K) := /-! # subfield closure of a subset -/ /-- The `Subfield` generated by a set. -/ -def closure (s : Set K) : Subfield K where - carrier := {z : K | ∃ x ∈ Subring.closure s, ∃ y ∈ Subring.closure s, x / y = z} - zero_mem' := ⟨0, Subring.zero_mem _, 1, Subring.one_mem _, div_one _⟩ - one_mem' := ⟨1, Subring.one_mem _, 1, Subring.one_mem _, div_one _⟩ - neg_mem' {x} := by - rintro ⟨y, hy, z, hz, x_eq⟩ - exact ⟨-y, Subring.neg_mem _ hy, z, hz, x_eq ▸ neg_div _ _⟩ - inv_mem' x := by rintro ⟨y, hy, z, hz, x_eq⟩; exact ⟨z, hz, y, hy, x_eq ▸ (inv_div _ _).symm ⟩ - add_mem' x_mem y_mem := by - -- Use `id` in the next 2 `obtain`s so that assumptions stay there for the `rwa`s below - obtain ⟨nx, hnx, dx, hdx, rfl⟩ := id x_mem - obtain ⟨ny, hny, dy, hdy, rfl⟩ := id y_mem - by_cases hx0 : dx = 0; · rwa [hx0, div_zero, zero_add] - by_cases hy0 : dy = 0; · rwa [hy0, div_zero, add_zero] - exact - ⟨nx * dy + dx * ny, Subring.add_mem _ (Subring.mul_mem _ hnx hdy) (Subring.mul_mem _ hdx hny), - dx * dy, Subring.mul_mem _ hdx hdy, (div_add_div nx ny hx0 hy0).symm⟩ - mul_mem' := by - rintro _ _ ⟨nx, hnx, dx, hdx, rfl⟩ ⟨ny, hny, dy, hdy, rfl⟩ - exact ⟨nx * ny, Subring.mul_mem _ hnx hny, dx * dy, Subring.mul_mem _ hdx hdy, - (div_mul_div_comm _ _ _ _).symm⟩ +def closure (s : Set K) : Subfield K := sInf {S | s ⊆ S} #align subfield.closure Subfield.closure -theorem mem_closure_iff {s : Set K} {x} : - x ∈ closure s ↔ ∃ y ∈ Subring.closure s, ∃ z ∈ Subring.closure s, y / z = x := by - change x ∈ (closure s).carrier ↔ ∃ y ∈ Subring.closure s, ∃ z ∈ Subring.closure s, y / z = x - simp only [closure, exists_prop, Set.mem_setOf_eq] -#align subfield.mem_closure_iff Subfield.mem_closure_iff - -theorem subring_closure_le (s : Set K) : Subring.closure s ≤ (closure s).toSubring := fun x hx => - ⟨x, hx, 1, Subring.one_mem _, div_one x⟩ -#align subfield.subring_closure_le Subfield.subring_closure_le +theorem mem_closure {x : K} {s : Set K} : x ∈ closure s ↔ ∀ S : Subfield K, s ⊆ S → x ∈ S := + mem_sInf +#align subfield.mem_closure Subfield.mem_closure /-- The subfield generated by a set includes the set. -/ @[simp, aesop safe 20 apply (rule_sets [SetLike])] -theorem subset_closure {s : Set K} : s ⊆ closure s := - Set.Subset.trans Subring.subset_closure (subring_closure_le s) +theorem subset_closure {s : Set K} : s ⊆ closure s := fun _ hx => mem_closure.2 fun _ hS => hS hx #align subfield.subset_closure Subfield.subset_closure +theorem subring_closure_le (s : Set K) : Subring.closure s ≤ (closure s).toSubring := + Subring.closure_le.mpr subset_closure +#align subfield.subring_closure_le Subfield.subring_closure_le + theorem not_mem_of_not_mem_closure {s : Set K} {P : K} (hP : P ∉ closure s) : P ∉ s := fun h => hP (subset_closure h) #align subfield.not_mem_of_not_mem_closure Subfield.not_mem_of_not_mem_closure -theorem mem_closure {x : K} {s : Set K} : x ∈ closure s ↔ ∀ S : Subfield K, s ⊆ S → x ∈ S := - ⟨fun ⟨_, hy, _, hz, x_eq⟩ t le => - x_eq ▸ - t.div_mem (Subring.mem_closure.mp hy t.toSubring le) - (Subring.mem_closure.mp hz t.toSubring le), - fun h => h (closure s) subset_closure⟩ -#align subfield.mem_closure Subfield.mem_closure - /-- A subfield `t` includes `closure s` if and only if it includes `s`. -/ @[simp] theorem closure_le {s : Set K} {t : Subfield K} : closure s ≤ t ↔ s ⊆ t := @@ -862,12 +832,16 @@ theorem coe_rangeRestrictField (f : K →+* L) (x : K) : (f.rangeRestrictField x rfl #align ring_hom.coe_range_restrict_field RingHom.coe_rangeRestrictField +section eqLocus + +variable {L : Type v} [Semiring L] + /-- The subfield of elements `x : R` such that `f x = g x`, i.e., the equalizer of f and g as a subfield of R -/ -def eqLocusField (f g : K →+* L) : Subfield K := - { (f : K →+* L).eqLocus g with - inv_mem' := fun x (hx : f x = g x) => show f x⁻¹ = g x⁻¹ by rw [map_inv₀ f, map_inv₀ g, hx] - carrier := { x | f x = g x } } +def eqLocusField (f g : K →+* L) : Subfield K where + __ := (f : K →+* L).eqLocus g + inv_mem' _ := eq_on_inv₀ f g + carrier := { x | f x = g x } #align ring_hom.eq_locus_field RingHom.eqLocusField /-- If two ring homomorphisms are equal on a set, then they are equal on its subfield closure. -/ @@ -885,6 +859,8 @@ theorem eq_of_eqOn_of_field_closure_eq_top {s : Set K} (hs : closure s = ⊤) {f eq_of_eqOn_subfield_top <| hs ▸ eqOn_field_closure h #align ring_hom.eq_of_eq_on_of_field_closure_eq_top RingHom.eq_of_eqOn_of_field_closure_eq_top +end eqLocus + theorem field_closure_preimage_le (f : K →+* L) (s : Set L) : closure (f ⁻¹' s) ≤ (closure s).comap f := closure_le.2 fun _ hx => SetLike.mem_coe.2 <| mem_comap.2 <| subset_closure hx @@ -939,4 +915,58 @@ theorem closure_preimage_le (f : K →+* L) (s : Set L) : closure (f ⁻¹' s) closure_le.2 fun _ hx => SetLike.mem_coe.2 <| mem_comap.2 <| subset_closure hx #align subfield.closure_preimage_le Subfield.closure_preimage_le +section Commutative + +variable {K : Type u} [Field K] (s : Subfield K) + +/-- Product of a multiset of elements in a subfield is in the subfield. -/ +protected theorem multiset_prod_mem (m : Multiset K) : (∀ a ∈ m, a ∈ s) → m.prod ∈ s := + multiset_prod_mem m +#align subfield.multiset_prod_mem Subfield.multiset_prod_mem + +/-- Product of elements of a subfield indexed by a `Finset` is in the subfield. -/ +protected theorem prod_mem {ι : Type*} {t : Finset ι} {f : ι → K} (h : ∀ c ∈ t, f c ∈ s) : + (∏ i in t, f i) ∈ s := + prod_mem h +#align subfield.prod_mem Subfield.prod_mem + +instance toAlgebra : Algebra s K := + RingHom.toAlgebra s.subtype +#align subfield.to_algebra Subfield.toAlgebra + +/-- The `Subfield` generated by a set in a field. -/ +private def commClosure (s : Set K) : Subfield K where + carrier := {z : K | ∃ x ∈ Subring.closure s, ∃ y ∈ Subring.closure s, x / y = z} + zero_mem' := ⟨0, Subring.zero_mem _, 1, Subring.one_mem _, div_one _⟩ + one_mem' := ⟨1, Subring.one_mem _, 1, Subring.one_mem _, div_one _⟩ + neg_mem' {x} := by + rintro ⟨y, hy, z, hz, x_eq⟩ + exact ⟨-y, Subring.neg_mem _ hy, z, hz, x_eq ▸ neg_div _ _⟩ + inv_mem' x := by rintro ⟨y, hy, z, hz, x_eq⟩; exact ⟨z, hz, y, hy, x_eq ▸ (inv_div _ _).symm ⟩ + add_mem' x_mem y_mem := by + -- Use `id` in the next 2 `obtain`s so that assumptions stay there for the `rwa`s below + obtain ⟨nx, hnx, dx, hdx, rfl⟩ := id x_mem + obtain ⟨ny, hny, dy, hdy, rfl⟩ := id y_mem + by_cases hx0 : dx = 0; · rwa [hx0, div_zero, zero_add] + by_cases hy0 : dy = 0; · rwa [hy0, div_zero, add_zero] + exact + ⟨nx * dy + dx * ny, Subring.add_mem _ (Subring.mul_mem _ hnx hdy) (Subring.mul_mem _ hdx hny), + dx * dy, Subring.mul_mem _ hdx hdy, (div_add_div nx ny hx0 hy0).symm⟩ + mul_mem' := by + rintro _ _ ⟨nx, hnx, dx, hdx, rfl⟩ ⟨ny, hny, dy, hdy, rfl⟩ + exact ⟨nx * ny, Subring.mul_mem _ hnx hny, dx * dy, Subring.mul_mem _ hdx hdy, + (div_mul_div_comm _ _ _ _).symm⟩ + +private theorem commClosure_eq_closure {s : Set K} : commClosure s = closure s := + le_antisymm + (fun _ ⟨_, hy, _, hz, eq⟩ ↦ eq ▸ div_mem (subring_closure_le s hy) (subring_closure_le s hz)) + (closure_le.mpr fun x hx ↦ ⟨x, Subring.subset_closure hx, 1, Subring.one_mem _, div_one x⟩) + +theorem mem_closure_iff {s : Set K} {x} : + x ∈ closure s ↔ ∃ y ∈ Subring.closure s, ∃ z ∈ Subring.closure s, y / z = x := by + rw [← commClosure_eq_closure]; rfl +#align subfield.mem_closure_iff Subfield.mem_closure_iff + +end Commutative + end Subfield diff --git a/Mathlib/RingTheory/Subring/Basic.lean b/Mathlib/RingTheory/Subring/Basic.lean index f031eeb131a24..2a13188dec350 100644 --- a/Mathlib/RingTheory/Subring/Basic.lean +++ b/Mathlib/RingTheory/Subring/Basic.lean @@ -1237,6 +1237,10 @@ theorem range_top_of_surjective (f : R →+* S) (hf : Function.Surjective f) : range_top_iff_surjective.2 hf #align ring_hom.range_top_of_surjective RingHom.range_top_of_surjective +section eqLocus + +variable {S : Type v} [Semiring S] + /-- The subring of elements `x : R` such that `f x = g x`, i.e., the equalizer of f and g as a subring of R -/ def eqLocus (f g : R →+* S) : Subring R := @@ -1263,6 +1267,8 @@ theorem eq_of_eqOn_set_dense {s : Set R} (hs : closure s = ⊤) {f g : R →+* S eq_of_eqOn_set_top <| hs ▸ eqOn_set_closure h #align ring_hom.eq_of_eq_on_set_dense RingHom.eq_of_eqOn_set_dense +end eqLocus + theorem closure_preimage_le (f : R →+* S) (s : Set S) : closure (f ⁻¹' s) ≤ (closure s).comap f := closure_le.2 fun _ hx => SetLike.mem_coe.2 <| mem_comap.2 <| subset_closure hx #align ring_hom.closure_preimage_le RingHom.closure_preimage_le From 93e820f3619d1e6ec775246653c587c04439de0c Mon Sep 17 00:00:00 2001 From: grunweg Date: Mon, 25 Dec 2023 18:43:45 +0000 Subject: [PATCH 178/353] feat: bijective local homeomorphisms are homeomorphisms (#9247) Basis for generalising the result for local diffeomorphism to local structomorphisms. Co-authored-by: grunweg --- Mathlib/Topology/IsLocalHomeomorph.lean | 11 +++++++++++ Mathlib/Topology/Maps.lean | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/Mathlib/Topology/IsLocalHomeomorph.lean b/Mathlib/Topology/IsLocalHomeomorph.lean index 758f53745e802..b4daa9005e833 100644 --- a/Mathlib/Topology/IsLocalHomeomorph.lean +++ b/Mathlib/Topology/IsLocalHomeomorph.lean @@ -214,6 +214,17 @@ theorem openEmbedding_of_injective (hf : IsLocalHomeomorph f) (hi : f.Injective) OpenEmbedding f := openEmbedding_of_continuous_injective_open hf.continuous hi hf.isOpenMap +/-- A surjective embedding is a homeomorphism. -/ +noncomputable def _root_.Embedding.toHomeomeomorph_of_surjective (hf : Embedding f) + (hsurj : Function.Surjective f) : X ≃ₜ Y := + Homeomorph.homeomorphOfContinuousOpen (Equiv.ofBijective f ⟨hf.inj, hsurj⟩) + hf.continuous (hf.toOpenEmbedding_of_surjective hsurj).isOpenMap + +/-- A bijective local homeomorphism is a homeomorphism. -/ +noncomputable def toHomeomorph_of_bijective (hf : IsLocalHomeomorph f) (hb : f.Bijective) : + X ≃ₜ Y := + Homeomorph.homeomorphOfContinuousOpen (Equiv.ofBijective f hb) hf.continuous hf.isOpenMap + /-- Continuous local sections of a local homeomorphism are open embeddings. -/ theorem openEmbedding_of_comp (hf : IsLocalHomeomorph g) (hgf : OpenEmbedding (g ∘ f)) (cont : Continuous f) : OpenEmbedding f := diff --git a/Mathlib/Topology/Maps.lean b/Mathlib/Topology/Maps.lean index c8f5f542b227f..4eb13edccc84d 100644 --- a/Mathlib/Topology/Maps.lean +++ b/Mathlib/Topology/Maps.lean @@ -622,6 +622,11 @@ theorem openEmbedding_of_embedding_open {f : α → β} (h₁ : Embedding f) (h ⟨h₁, h₂.isOpen_range⟩ #align open_embedding_of_embedding_open openEmbedding_of_embedding_open +/-- A surjective embedding is an `OpenEmbedding`. -/ +theorem _root_.Embedding.toOpenEmbedding_of_surjective {f : α → β} + (hf : Embedding f) (hsurj: f.Surjective) : OpenEmbedding f := + ⟨hf, hsurj.range_eq ▸ isOpen_univ⟩ + theorem openEmbedding_iff_embedding_open {f : α → β} : OpenEmbedding f ↔ Embedding f ∧ IsOpenMap f := ⟨fun h => ⟨h.1, h.isOpenMap⟩, fun h => openEmbedding_of_embedding_open h.1 h.2⟩ From 61efe6de0869cfb384372c69dd1f40a0219f687f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 03:42:24 +0000 Subject: [PATCH 179/353] feat: The double factorial is positive (#9102) and other basic results. Also include a positivity extension to encode that new result. From LeanAPAP --- Mathlib/Data/Nat/Factorial/Basic.lean | 12 +++++++++ Mathlib/Data/Nat/Factorial/BigOperators.lean | 11 +++----- .../Data/Nat/Factorial/DoubleFactorial.lean | 27 +++++++++++++++++++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Mathlib/Data/Nat/Factorial/Basic.lean b/Mathlib/Data/Nat/Factorial/Basic.lean index 7a2b7b4d7626e..14afd1fc03435 100644 --- a/Mathlib/Data/Nat/Factorial/Basic.lean +++ b/Mathlib/Data/Nat/Factorial/Basic.lean @@ -449,4 +449,16 @@ theorem descFactorial_lt_pow {n : ℕ} (hn : 1 ≤ n) : ∀ {k : ℕ}, 2 ≤ k end DescFactorial +lemma factorial_two_mul_le (n : ℕ) : (2 * n)! ≤ (2 * n) ^ n * n ! := by + rw [two_mul, ← factorial_mul_ascFactorial, mul_comm] + exact mul_le_mul_right' (ascFactorial_le_pow_add _ _) _ + +lemma two_pow_mul_factorial_le_factorial_two_mul (n : ℕ) : 2 ^ n * n ! ≤ (2 * n) ! := by + obtain _ | n := n + · simp + rw [mul_comm, two_mul] + calc + _ ≤ (n + 1)! * (n + 2) ^ (n + 1) := mul_le_mul_left' (pow_le_pow_of_le_left le_add_self _) _ + _ ≤ _ := Nat.factorial_mul_pow_le_factorial + end Nat diff --git a/Mathlib/Data/Nat/Factorial/BigOperators.lean b/Mathlib/Data/Nat/Factorial/BigOperators.lean index 642ba3f562abb..bfb6a8406ef8b 100644 --- a/Mathlib/Data/Nat/Factorial/BigOperators.lean +++ b/Mathlib/Data/Nat/Factorial/BigOperators.lean @@ -30,13 +30,10 @@ theorem prod_factorial_pos : 0 < ∏ i in s, (f i)! := #align nat.prod_factorial_pos Nat.prod_factorial_pos theorem prod_factorial_dvd_factorial_sum : (∏ i in s, (f i)!) ∣ (∑ i in s, f i)! := by - classical - induction' s using Finset.induction with a' s' has ih - · simp only [prod_empty, factorial, dvd_refl] - · simp only [Finset.prod_insert has, Finset.sum_insert has] - refine' dvd_trans (mul_dvd_mul_left (f a')! ih) _ - apply Nat.factorial_mul_factorial_dvd_factorial_add -#align nat.prod_factorial_dvd_factorial_sum Nat.prod_factorial_dvd_factorial_sum + induction' s using Finset.cons_induction_on with a s has ih + · simp + · rw [prod_cons, Finset.sum_cons] + exact (mul_dvd_mul_left _ ih).trans (Nat.factorial_mul_factorial_dvd_factorial_add _ _) theorem descFactorial_eq_prod_range (n : ℕ) : ∀ k, n.descFactorial k = ∏ i in range k, (n - i) | 0 => rfl diff --git a/Mathlib/Data/Nat/Factorial/DoubleFactorial.lean b/Mathlib/Data/Nat/Factorial/DoubleFactorial.lean index a023aca76229f..1bda3a8a658b5 100644 --- a/Mathlib/Data/Nat/Factorial/DoubleFactorial.lean +++ b/Mathlib/Data/Nat/Factorial/DoubleFactorial.lean @@ -36,6 +36,10 @@ def doubleFactorial : ℕ → ℕ -- This notation is `\!!` not two !'s scoped notation:10000 n "‼" => Nat.doubleFactorial n +lemma doubleFactorial_pos : ∀ n, 0 < n‼ + | 0 | 1 => zero_lt_one + | _n + 2 => mul_pos (succ_pos _) (doubleFactorial_pos _) + theorem doubleFactorial_add_two (n : ℕ) : (n + 2)‼ = (n + 2) * n‼ := rfl #align nat.double_factorial_add_two Nat.doubleFactorial_add_two @@ -50,6 +54,11 @@ theorem factorial_eq_mul_doubleFactorial : ∀ n : ℕ, (n + 1)! = (n + 1)‼ * mul_assoc] #align nat.factorial_eq_mul_double_factorial Nat.factorial_eq_mul_doubleFactorial +lemma doubleFactorial_le_factorial : ∀ n, n‼ ≤ n ! + | 0 => le_rfl + | n + 1 => by + rw [factorial_eq_mul_doubleFactorial]; exact le_mul_of_pos_right n.doubleFactorial_pos + theorem doubleFactorial_two_mul : ∀ n : ℕ, (2 * n)‼ = 2 ^ n * n ! | 0 => rfl | n + 1 => by @@ -78,3 +87,21 @@ theorem doubleFactorial_eq_prod_odd : #align nat.double_factorial_eq_prod_odd Nat.doubleFactorial_eq_prod_odd end Nat + +namespace Mathlib.Meta.Positivity +open Lean Meta Qq + +/-- Extension for `Nat.doubleFactorial`. -/ +@[positivity Nat.doubleFactorial _] +def evalDoubleFactorial : PositivityExt where eval {u α} _ _ e := do + if let 0 := u then -- lean4#3060 means we can't combine this with the match below + match α, e with + | ~q(ℕ), ~q(Nat.doubleFactorial $n) => + assumeInstancesCommute + return .positive q(Nat.doubleFactorial_pos $n) + | _, _ => throwError "not Nat.doubleFactorial" + else throwError "not Nat.doubleFactorial" + +example (n : ℕ) : 0 < n‼ := by positivity + +end Mathlib.Meta.Positivity From 081c6724808d3086e3bf50d53f7e2213192d2438 Mon Sep 17 00:00:00 2001 From: LW Date: Tue, 26 Dec 2023 04:50:59 +0000 Subject: [PATCH 180/353] =?UTF-8?q?feat:=20`AddCommGroup`=20is=20`ZMod=20n?= =?UTF-8?q?`=20module=20if=20`n=20=E2=80=A2=20x=20=3D=200`=20for=20all=20`?= =?UTF-8?q?x`=20(#9017)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generalization of content from PFR for doing linear algebra over $C_2^n$. Co-authored-by: L Lllvvuu --- Mathlib/Data/ZMod/Module.lean | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Mathlib/Data/ZMod/Module.lean b/Mathlib/Data/ZMod/Module.lean index 82c6cbca1a858..7fca517aebab1 100644 --- a/Mathlib/Data/ZMod/Module.lean +++ b/Mathlib/Data/ZMod/Module.lean @@ -10,7 +10,38 @@ import Mathlib.Algebra.Module.LinearMap # The `ZMod n`-module structure on Abelian groups whose elements have order dividing `n` -/ -variable {n : ℕ} {M M₁ F S : Type*} [AddCommGroup M] [AddCommGroup M₁] [AddMonoidHomClass F M M₁] +variable {n : ℕ} {M M₁ : Type*} + +/-- The `ZMod n`-module structure on commutative monoids whose elements have order dividing `n ≠ 0`. +Also implies a group structure via `Module.addCommMonoidToAddCommGroup`. +See note [reducible non-instances]. -/ +@[reducible] +def AddCommMonoid.zmodModule [NeZero n] [AddCommMonoid M] (h : ∀ (x : M), n • x = 0) : + Module (ZMod n) M := by + have h_mod (c : ℕ) (x : M) : (c % n) • x = c • x := by + suffices (c % n + c / n * n) • x = c • x by rwa [add_nsmul, mul_nsmul, h, add_zero] at this + rw [Nat.mod_add_div'] + cases n; cases NeZero.ne 0 rfl + exact { + smul := fun (c : Fin _) x ↦ c.val • x + smul_zero := fun _ ↦ nsmul_zero _ + zero_smul := fun _ ↦ zero_nsmul _ + smul_add := fun _ _ _ ↦ nsmul_add _ _ _ + one_smul := fun _ ↦ (h_mod _ _).trans <| one_nsmul _ + add_smul := fun _ _ _ ↦ (h_mod _ _).trans <| add_nsmul _ _ _ + mul_smul := fun _ _ _ ↦ (h_mod _ _).trans <| mul_nsmul' _ _ _ + } + +/-- The `ZMod n`-module structure on Abelian groups whose elements have order dividing `n`. +See note [reducible non-instances]. -/ +@[reducible] +def AddCommGroup.zmodModule {G : Type*} [AddCommGroup G] (h : ∀ (x : G), n • x = 0) : + Module (ZMod n) G := + match n with + | 0 => AddCommGroup.intModule G + | _ + 1 => AddCommMonoid.zmodModule h + +variable {F S : Type*} [AddCommGroup M] [AddCommGroup M₁] [AddMonoidHomClass F M M₁] [Module (ZMod n) M] [Module (ZMod n) M₁] [SetLike S M] [AddSubgroupClass S M] {x : M} {K : S} namespace ZMod From caeafefd6df12ef3b8bb11f454f91acf5ecc3aa9 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Tue, 26 Dec 2023 06:12:03 +0000 Subject: [PATCH 181/353] chore(RingTheory/Polynomial/SeparableDegree): add `HasSeparableContraction.isSeparableContraction` and ... (#9272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … move `Irreducible.hasSeparableContraction` to global namespace --- Mathlib/RingTheory/Polynomial/SeparableDegree.lean | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Mathlib/RingTheory/Polynomial/SeparableDegree.lean b/Mathlib/RingTheory/Polynomial/SeparableDegree.lean index 871b8d4ca1adf..48b738d91bdf6 100644 --- a/Mathlib/RingTheory/Polynomial/SeparableDegree.lean +++ b/Mathlib/RingTheory/Polynomial/SeparableDegree.lean @@ -22,7 +22,7 @@ This file contains basics about the separable degree of a polynomial. - `HasSeparableContraction`: the condition of having a separable contraction - `HasSeparableContraction.degree`: the separable degree, defined as the degree of some separable contraction -- `Irreducible.HasSeparableContraction`: any irreducible polynomial can be contracted +- `Irreducible.hasSeparableContraction`: any irreducible polynomial can be contracted to a separable polynomial - `HasSeparableContraction.dvd_degree'`: the degree of a separable contraction divides the degree, in function of the exponential characteristic of the field @@ -69,6 +69,10 @@ def HasSeparableContraction.degree : ℕ := hf.contraction.natDegree #align polynomial.has_separable_contraction.degree Polynomial.HasSeparableContraction.degree +/-- The `HasSeparableContraction.contraction` is indeed a separable contraction. -/ +theorem HasSeparableContraction.isSeparableContraction : + IsSeparableContraction q f hf.contraction := Classical.choose_spec hf + /-- The separable degree divides the degree, in function of the exponential characteristic of F. -/ theorem IsSeparableContraction.dvd_degree' {g} (hf : IsSeparableContraction q f g) : ∃ m : ℕ, g.natDegree * q ^ m = f.natDegree := by @@ -104,13 +108,13 @@ variable (q : ℕ) {f : F[X]} (hf : HasSeparableContraction q f) /-- Every irreducible polynomial can be contracted to a separable polynomial. https://stacks.math.columbia.edu/tag/09H0 -/ -theorem Irreducible.hasSeparableContraction (q : ℕ) [hF : ExpChar F q] (f : F[X]) +theorem _root_.Irreducible.hasSeparableContraction (q : ℕ) [hF : ExpChar F q] {f : F[X]} (irred : Irreducible f) : HasSeparableContraction q f := by cases hF · exact ⟨f, irred.separable, ⟨0, by rw [pow_zero, expand_one]⟩⟩ · rcases exists_separable_of_irreducible q irred ‹q.Prime›.ne_zero with ⟨n, g, hgs, hge⟩ exact ⟨g, hgs, n, hge⟩ -#align irreducible.has_separable_contraction Polynomial.Irreducible.hasSeparableContraction +#align irreducible.has_separable_contraction Irreducible.hasSeparableContraction /-- If two expansions (along the positive characteristic) of two separable polynomials `g` and `g'` agree, then they have the same degree. -/ From 2041984887d0295090a7197265ca664d99404033 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Tue, 26 Dec 2023 06:34:16 +0000 Subject: [PATCH 182/353] feat(FieldTheory/Perfect): add `rootsExpand[Pow]EquivRoots[_apply]` (#9271) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... which state that over a perfect integral domain `R` of characteristic `p`, `x ↦ x ^ p ^ n` is a bijection from the set of roots of `Polynomial.expand R (p ^ n) f` to the set of roots of `f`. --- Mathlib/FieldTheory/Perfect.lean | 40 +++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/Mathlib/FieldTheory/Perfect.lean b/Mathlib/FieldTheory/Perfect.lean index 3a347ff4581d4..806175a7b9808 100644 --- a/Mathlib/FieldTheory/Perfect.lean +++ b/Mathlib/FieldTheory/Perfect.lean @@ -111,7 +111,7 @@ theorem not_irreducible_expand (f : R[X]) : ¬ Irreducible (expand R p f) := by rw [polynomial_expand_eq] exact not_irreducible_pow hp.out.ne_one -instance (S : Type*) [CommSemiring S] [CharP S p] [PerfectRing S p] : +instance instPerfectRingProd (S : Type*) [CommSemiring S] [CharP S p] [PerfectRing S p] : PerfectRing (R × S) p := by constructor have : frobenius (R × S) p = Prod.map (frobenius R p) (frobenius S p) := by @@ -119,6 +119,44 @@ instance (S : Type*) [CommSemiring S] [CharP S p] [PerfectRing S p] : rw [this] exact Bijective.Prod_map (bijective_frobenius R p) (bijective_frobenius S p) +namespace Polynomial + +open scoped Classical + +variable {R : Type*} [CommRing R] [IsDomain R] + (p : ℕ) [Fact p.Prime] [CharP R p] [PerfectRing R p] (f : R[X]) + +/-- If `f` is a polynomial over a perfect integral domain `R` of characteristic `p`, then there is +a bijection from the set of roots of `Polynomial.expand R p f` to the set of roots of `f`. +It's given by `x ↦ x ^ p`, see `rootsExpandEquivRoots_apply`. -/ +noncomputable def rootsExpandEquivRoots : (expand R p f).roots.toFinset ≃ f.roots.toFinset := + ((frobeniusEquiv R p).image _).trans <| Equiv.Set.ofEq <| show _ '' (setOf _) = setOf _ by + ext r; obtain ⟨r, rfl⟩ := surjective_frobenius R p r + simp [expand_eq_zero (Fact.out : p.Prime).pos, (frobenius_inj R p).eq_iff, ← frobenius_def] + +@[simp] +theorem rootsExpandEquivRoots_apply (x) : (rootsExpandEquivRoots p f x : R) = x ^ p := rfl + +/-- If `f` is a polynomial over a perfect integral domain `R` of characteristic `p`, then there is +a bijection from the set of roots of `Polynomial.expand R (p ^ n) f` to the set of roots of `f`. +It's given by `x ↦ x ^ (p ^ n)`, see `rootsExpandPowEquivRoots_apply`. -/ +noncomputable def rootsExpandPowEquivRoots : + (n : ℕ) → (expand R (p ^ n) f).roots.toFinset ≃ f.roots.toFinset + | 0 => Equiv.Set.ofEq <| by rw [pow_zero, expand_one] + | n + 1 => (Equiv.Set.ofEq <| by rw [pow_succ, ← expand_expand]).trans + (rootsExpandEquivRoots p (expand R (p ^ n) f)) |>.trans (rootsExpandPowEquivRoots n) + +@[simp] +theorem rootsExpandPowEquivRoots_apply (n : ℕ) (x) : + (rootsExpandPowEquivRoots p f n x : R) = x ^ p ^ n := by + induction' n with n ih + · simp only [pow_zero, pow_one] + rfl + simp_rw [rootsExpandPowEquivRoots, Equiv.trans_apply, ih, pow_succ, pow_mul] + rfl + +end Polynomial + end PerfectRing /-- A perfect field. From 9d6b50d77c4326994ca7b7553175db97fbf05b40 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Dec 2023 07:02:16 +0000 Subject: [PATCH 183/353] chore(DedekindDomain): use `wlog` (#9278) * Use `wlog` tactic instead of an explicit `suffices`. * Restate a lemma in terms of an inequality between fractional ideals. * Drop an unneeded assumption, thanks to @erdOne Co-authored-by: @erdOne Co-authored-by: erd1 --- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 53 +++++++------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index e65d929db4123..1be9caa7c604c 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -392,39 +392,30 @@ namespace FractionalIdeal open Ideal -theorem exists_not_mem_one_of_ne_bot [IsDedekindDomain A] (hNF : ¬IsField A) {I : Ideal A} - (hI0 : I ≠ ⊥) (hI1 : I ≠ ⊤) : - ∃ x : K, x ∈ (I⁻¹ : FractionalIdeal A⁰ K) ∧ x ∉ (1 : FractionalIdeal A⁰ K) := by - -- WLOG, let `I` be maximal. - suffices - ∀ {M : Ideal A} (_hM : M.IsMaximal), - ∃ x : K, x ∈ (M⁻¹ : FractionalIdeal A⁰ K) ∧ x ∉ (1 : FractionalIdeal A⁰ K) by - obtain ⟨M, hM, hIM⟩ : ∃ M : Ideal A, IsMaximal M ∧ I ≤ M := Ideal.exists_le_maximal I hI1 - have hM0 := (M.bot_lt_of_maximal hNF).ne' - obtain ⟨x, hxM, hx1⟩ := this hM - refine ⟨x, inv_anti_mono ?_ ?_ ((coeIdeal_le_coeIdeal _).mpr hIM) hxM, hx1⟩ <;> - rw [coeIdeal_ne_zero] <;> assumption - -- Let `a` be a nonzero element of `M` and `J` the ideal generated by `a`. - intro M hM - obtain ⟨⟨a, haM⟩, ha0⟩ := Submodule.nonzero_mem_of_bot_lt (M.bot_lt_of_maximal hNF) +lemma not_inv_le_one_of_ne_bot [IsDedekindDomain A] {I : Ideal A} + (hI0 : I ≠ ⊥) (hI1 : I ≠ ⊤) : ¬(I⁻¹ : FractionalIdeal A⁰ K) ≤ 1 := by + have hNF : ¬IsField A := fun h ↦ letI := h.toField; (eq_bot_or_eq_top I).elim hI0 hI1 + wlog hM : I.IsMaximal generalizing I + · rcases I.exists_le_maximal hI1 with ⟨M, hmax, hIM⟩ + have hMbot : M ≠ ⊥ := (M.bot_lt_of_maximal hNF).ne' + refine mt (le_trans <| inv_anti_mono ?_ ?_ ?_) (this hMbot hmax.ne_top hmax) <;> + simpa only [coeIdeal_ne_zero, coeIdeal_le_coeIdeal] + have hI0 : ⊥ < I := I.bot_lt_of_maximal hNF + obtain ⟨⟨a, haI⟩, ha0⟩ := Submodule.nonzero_mem_of_bot_lt hI0 replace ha0 : a ≠ 0 := Subtype.coe_injective.ne ha0 let J : Ideal A := Ideal.span {a} have hJ0 : J ≠ ⊥ := mt Ideal.span_singleton_eq_bot.mp ha0 - have hJM : J ≤ M := Ideal.span_le.mpr (Set.singleton_subset_iff.mpr haM) - have hM0 : ⊥ < M := M.bot_lt_of_maximal hNF + have hJI : J ≤ I := I.span_singleton_le_iff_mem.2 haI -- Then we can find a product of prime (hence maximal) ideals contained in `J`, -- such that removing element `M` from the product is not contained in `J`. - obtain ⟨Z, hle, hnle⟩ := exists_multiset_prod_cons_le_and_prod_not_le hNF hJ0 hJM + obtain ⟨Z, hle, hnle⟩ := exists_multiset_prod_cons_le_and_prod_not_le hNF hJ0 hJI -- Choose an element `b` of the product that is not in `J`. obtain ⟨b, hbZ, hbJ⟩ := SetLike.not_le_iff_exists.mp hnle have hnz_fa : algebraMap A K a ≠ 0 := mt ((injective_iff_map_eq_zero _).mp (IsFractionRing.injective A K) a) ha0 - have _hb0 : algebraMap A K b ≠ 0 := - mt ((injective_iff_map_eq_zero _).mp (IsFractionRing.injective A K) b) fun h => - hbJ <| h.symm ▸ J.zero_mem -- Then `b a⁻¹ : K` is in `M⁻¹` but not in `1`. - refine' ⟨algebraMap A K b * (algebraMap A K a)⁻¹, (mem_inv_iff _).mpr _, _⟩ - · exact coeIdeal_ne_zero.mpr hM0.ne' + refine Set.not_subset.2 ⟨algebraMap A K b * (algebraMap A K a)⁻¹, (mem_inv_iff ?_).mpr ?_, ?_⟩ + · exact coeIdeal_ne_zero.mpr hI0.ne' · rintro y₀ hy₀ obtain ⟨y, h_Iy, rfl⟩ := (mem_coeIdeal _).mp hy₀ rw [mul_comm, ← mul_assoc, ← RingHom.map_mul] @@ -441,6 +432,10 @@ theorem exists_not_mem_one_of_ne_bot [IsDedekindDomain A] (hNF : ¬IsField A) {I rw [← div_eq_mul_inv, eq_div_iff_mul_eq hnz_fa, ← RingHom.map_mul] at h₂_abs have := Ideal.mem_span_singleton'.mpr ⟨x', IsFractionRing.injective A K h₂_abs⟩ contradiction + +theorem exists_not_mem_one_of_ne_bot [IsDedekindDomain A] {I : Ideal A} (hI0 : I ≠ ⊥) + (hI1 : I ≠ ⊤) : ∃ x ∈ (I⁻¹ : FractionalIdeal A⁰ K), x ∉ (1 : FractionalIdeal A⁰ K) := + Set.not_subset.1 <| not_inv_le_one_of_ne_bot hI0 hI1 #align fractional_ideal.exists_not_mem_one_of_ne_bot FractionalIdeal.exists_not_mem_one_of_ne_bot theorem one_mem_inv_coe_ideal {I : Ideal A} (hI : I ≠ ⊥) : @@ -453,11 +448,6 @@ theorem one_mem_inv_coe_ideal {I : Ideal A} (hI : I ≠ ⊥) : theorem mul_inv_cancel_of_le_one [h : IsDedekindDomain A] {I : Ideal A} (hI0 : I ≠ ⊥) (hI : (I * (I : FractionalIdeal A⁰ K)⁻¹)⁻¹ ≤ 1) : I * (I : FractionalIdeal A⁰ K)⁻¹ = 1 := by - -- Handle a few trivial cases. - by_cases hI1 : I = ⊤ - · rw [hI1, coeIdeal_top, one_mul, inv_one] - by_cases hNF : IsField A - · letI := hNF.toField; rcases hI1 (I.eq_bot_or_top.resolve_left hI0) with ⟨⟩ -- We'll show a contradiction with `exists_not_mem_one_of_ne_bot`: -- `J⁻¹ = (I * I⁻¹)⁻¹` cannot have an element `x ∉ 1`, so it must equal `1`. obtain ⟨J, hJ⟩ : ∃ J : Ideal A, (J : FractionalIdeal A⁰ K) = I * (I : FractionalIdeal A⁰ K)⁻¹ := @@ -469,12 +459,7 @@ theorem mul_inv_cancel_of_le_one [h : IsDedekindDomain A] {I : Ideal A} (hI0 : I exact coe_ideal_le_self_mul_inv K I by_cases hJ1 : J = ⊤ · rw [← hJ, hJ1, coeIdeal_top] - obtain ⟨x, hx, hx1⟩ : - ∃ x : K, x ∈ (J : FractionalIdeal A⁰ K)⁻¹ ∧ x ∉ (1 : FractionalIdeal A⁰ K) := - exists_not_mem_one_of_ne_bot hNF hJ0 hJ1 - contrapose! hx1 with h_abs - rw [hJ] at hx - exact hI hx + exact (not_inv_le_one_of_ne_bot (K := K) hJ0 hJ1 (hJ ▸ hI)).elim #align fractional_ideal.mul_inv_cancel_of_le_one FractionalIdeal.mul_inv_cancel_of_le_one /-- Nonzero integral ideals in a Dedekind domain are invertible. From 925559df7538f58188bf3ba42208c10426adbafd Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Dec 2023 07:02:17 +0000 Subject: [PATCH 184/353] chore(TopCat/Limits/Cofiltered): golf (#9279) --- .../Topology/Category/TopCat/Limits/Cofiltered.lean | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean b/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean index 45932ffaad2ed..1f342f7f6693b 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean @@ -70,14 +70,10 @@ theorem isTopologicalBasis_cofiltered_limit (T : ∀ j, Set (Set (F.obj j))) · rintro ⟨j, V, hV, rfl⟩ let U : ∀ i, Set (F.obj i) := fun i => if h : i = j then by rw [h]; exact V else Set.univ refine' ⟨U, {j}, _, _⟩ - · rintro i h - rw [Finset.mem_singleton] at h - dsimp - rw [dif_pos h] - subst h - exact hV - · dsimp - simp + · simp only [Finset.mem_singleton] + rintro i rfl + simpa + · simp · rintro ⟨U, G, h1, h2⟩ obtain ⟨j, hj⟩ := IsCofiltered.inf_objs_exists G let g : ∀ (e) (_he : e ∈ G), j ⟶ e := fun _ he => (hj he).some From 4fda6f75a24576d1bee6410cfcd8c2d587eaab96 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 26 Dec 2023 07:02:18 +0000 Subject: [PATCH 185/353] feat: The galois group acts on infinite places. (#9280) --- .../NumberTheory/NumberField/Embeddings.lean | 136 +++++++++++++++++- 1 file changed, 130 insertions(+), 6 deletions(-) diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index 77a7f8adfa8d8..78333f019d378 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -156,7 +156,7 @@ open Complex NumberField open scoped ComplexConjugate -variable {K : Type*} [Field K] +variable {K : Type*} [Field K] {k : Type*} [Field k] /-- The conjugate of a complex embedding as a complex embedding. -/ @[reducible] @@ -203,13 +203,31 @@ theorem IsReal.coe_embedding_apply {φ : K →+* ℂ} (hφ : IsReal φ) (x : K) exact RingHom.congr_fun hφ x #align number_field.complex_embedding.is_real.coe_embedding_apply NumberField.ComplexEmbedding.IsReal.coe_embedding_apply +lemma IsReal.comp (f : k →+* K) {φ : K →+* ℂ} (hφ : IsReal φ) : + IsReal (φ.comp f) := by ext1 x; simpa using RingHom.congr_fun hφ (f x) + +lemma isReal_comp_iff {f : k ≃+* K} {φ : K →+* ℂ} : + IsReal (φ.comp (f : k →+* K)) ↔ IsReal φ := + ⟨fun H ↦ by convert H.comp f.symm.toRingHom; ext1; simp, IsReal.comp _⟩ + +lemma exists_comp_symm_eq_of_comp_eq [Algebra k K] [IsGalois k K] (φ ψ : K →+* ℂ) + (h : φ.comp (algebraMap k K) = ψ.comp (algebraMap k K)) : + ∃ σ : K ≃ₐ[k] K, φ.comp σ.symm = ψ := by + letI := (φ.comp (algebraMap k K)).toAlgebra + letI := φ.toAlgebra + have : IsScalarTower k K ℂ := IsScalarTower.of_algebraMap_eq' rfl + let ψ' : K →ₐ[k] ℂ := { ψ with commutes' := fun r ↦ (RingHom.congr_fun h r).symm } + use (AlgHom.restrictNormal' ψ' K).symm + ext1 x + exact AlgHom.restrictNormal_commutes ψ' K x + end NumberField.ComplexEmbedding section InfinitePlace open NumberField -variable (K : Type*) [Field K] +variable (K : Type*) [Field K] {k : Type*} [Field k] {F : Type*} [Field F] /-- An infinite place of a number field `K` is a place associated to a complex embedding. -/ def NumberField.InfinitePlace := { w : AbsoluteValue K ℝ // ∃ φ : K →+* ℂ, place φ = w } @@ -380,12 +398,17 @@ theorem isReal_of_mk_isReal {φ : K →+* ℂ} (h : IsReal (mk φ)) : rw [not_isReal_iff_isComplex] exact ⟨φ, h, rfl⟩ +lemma isReal_mk_iff {φ : K →+* ℂ} : + IsReal (mk φ) ↔ ComplexEmbedding.IsReal φ := + ⟨isReal_of_mk_isReal, fun H ↦ ⟨_, H, rfl⟩⟩ + +lemma isComplex_mk_iff {φ : K →+* ℂ} : + IsComplex (mk φ) ↔ ¬ ComplexEmbedding.IsReal φ := + not_isReal_iff_isComplex.symm.trans isReal_mk_iff.not + @[simp] theorem not_isReal_of_mk_isComplex {φ : K →+* ℂ} (h : IsComplex (mk φ)) : - ¬ ComplexEmbedding.IsReal φ := by - contrapose! h - rw [← not_isReal_iff_isComplex.not, not_not] - exact ⟨φ, h, rfl⟩ + ¬ ComplexEmbedding.IsReal φ := by rwa [← isComplex_mk_iff] /-- The multiplicity of an infinite place, that is the number of distinct complex embeddings that define it, see `card_filter_mk_eq`. -/ @@ -502,6 +525,107 @@ theorem card_add_two_mul_card_eq_rank : ← Embeddings.card K ℂ, Nat.add_sub_of_le] exact Fintype.card_subtype_le _ +variable {K} + +/-- The restriction of an infinite place along an embedding. -/ +def comap (w : InfinitePlace K) (f : k →+* K) : InfinitePlace k := + ⟨w.1.comp f.injective, w.embedding.comp f, + by { ext x; show _ = w.1 (f x); rw [← w.2.choose_spec]; rfl }⟩ + +@[simp] +lemma comap_mk (φ : K →+* ℂ) (f : k →+* K) : (mk φ).comap f = mk (φ.comp f) := rfl + +lemma comap_comp (w : InfinitePlace K) (f : F →+* K) (g : k →+* F) : + w.comap (f.comp g) = (w.comap f).comap g := rfl + +lemma IsReal.comap (f : k →+* K) {w : InfinitePlace K} (hφ : IsReal w) : + IsReal (w.comap f) := by + rw [← mk_embedding w, comap_mk, isReal_mk_iff] + rw [← mk_embedding w, isReal_mk_iff] at hφ + exact hφ.comp f + +lemma isReal_comap_iff (f : k ≃+* K) {w : InfinitePlace K} : + IsReal (w.comap (f : k →+* K)) ↔ IsReal w := by + rw [← mk_embedding w, comap_mk, isReal_mk_iff, isReal_mk_iff, ComplexEmbedding.isReal_comp_iff] + +lemma comap_surjective [Algebra k K] (h : Algebra.IsAlgebraic k K) : + Function.Surjective (comap · (algebraMap k K)) := fun w ↦ + letI := w.embedding.toAlgebra + ⟨mk (IsAlgClosed.lift (M := ℂ) h), by simp [comap_mk, RingHom.algebraMap_toAlgebra]⟩ + +variable [Algebra k K] (σ : K ≃ₐ[k] K) (w : InfinitePlace K) + +/-- The action of the galois group on infinite places. -/ +@[simps! smul_coe_apply] +instance : MulAction (K ≃ₐ[k] K) (InfinitePlace K) where + smul := fun σ w ↦ w.comap σ.symm + one_smul := fun _ ↦ rfl + mul_smul := fun _ _ _ ↦ rfl + +lemma smul_eq_comap : σ • w = w.comap σ.symm := rfl + +@[simp] lemma smul_apply (x) : (σ • w) x = w (σ.symm x) := rfl + +@[simp] lemma smul_mk (φ : K →+* ℂ) : σ • mk φ = mk (φ.comp σ.symm) := rfl + +lemma comap_smul {f : F →+* K} : (σ • w).comap f = w.comap (RingHom.comp σ.symm f) := rfl + +variable {σ w} + +lemma isReal_smul_iff : IsReal (σ • w) ↔ IsReal w := isReal_comap_iff (f := σ.symm.toRingEquiv) + +lemma isComplex_smul_iff : IsComplex (σ • w) ↔ IsComplex w := by + rw [← not_isReal_iff_isComplex, ← not_isReal_iff_isComplex, isReal_smul_iff] + +lemma ComplexEmbedding.exists_comp_symm_eq_of_comp_eq [Algebra k K] [IsGalois k K] (φ ψ : K →+* ℂ) + (h : φ.comp (algebraMap k K) = ψ.comp (algebraMap k K)) : + ∃ σ : K ≃ₐ[k] K, φ.comp σ.symm = ψ := by + letI := (φ.comp (algebraMap k K)).toAlgebra + letI := φ.toAlgebra + have : IsScalarTower k K ℂ := IsScalarTower.of_algebraMap_eq' rfl + let ψ' : K →ₐ[k] ℂ := { ψ with commutes' := fun r ↦ (RingHom.congr_fun h r).symm } + use (AlgHom.restrictNormal' ψ' K).symm + ext1 x + exact AlgHom.restrictNormal_commutes ψ' K x + +lemma exists_smul_eq_of_comap_eq [Algebra k K] [IsGalois k K] (w w' : InfinitePlace K) + (h : w.comap (algebraMap k K) = w'.comap (algebraMap k K)) : ∃ σ : K ≃ₐ[k] K, σ • w = w' := by + rw [← mk_embedding w, ← mk_embedding w', comap_mk, comap_mk, mk_eq_iff] at h + cases h with + | inl h => + obtain ⟨σ, hσ⟩ := ComplexEmbedding.exists_comp_symm_eq_of_comp_eq w.embedding w'.embedding h + use σ + rw [← mk_embedding w, ← mk_embedding w', smul_mk, hσ] + | inr h => + obtain ⟨σ, hσ⟩ := ComplexEmbedding.exists_comp_symm_eq_of_comp_eq + ((starRingEnd ℂ).comp (embedding w)) w'.embedding h + use σ + rw [← mk_embedding w, ← mk_embedding w', smul_mk, mk_eq_iff] + exact Or.inr hσ + +lemma mem_orbit_iff [IsGalois k K] {w w' : InfinitePlace K} : + w' ∈ MulAction.orbit (K ≃ₐ[k] K) w ↔ w.comap (algebraMap k K) = w'.comap (algebraMap k K) := by + refine ⟨?_, exists_smul_eq_of_comap_eq w w'⟩ + rintro ⟨σ, rfl : σ • w = w'⟩ + rw [← mk_embedding w, comap_mk, smul_mk, comap_mk] + congr 1; ext1; simp + +/-- The orbits of infinite places under the action of the galois group are indexed by +the infinite places of the base field. -/ +noncomputable +def orbitRelEquiv [IsGalois k K] : + Quotient (MulAction.orbitRel (K ≃ₐ[k] K) (InfinitePlace K)) ≃ InfinitePlace k := by + refine Equiv.ofBijective (Quotient.lift (comap · (algebraMap k K)) + <| fun _ _ e ↦ (mem_orbit_iff.mp e).symm) ⟨?_, ?_⟩ + · rintro ⟨w⟩ ⟨w'⟩ e + exact Quotient.sound (mem_orbit_iff.mpr e.symm) + · intro w + obtain ⟨w', hw⟩ := comap_surjective (Normal.isAlgebraic' (K := K)) w + exact ⟨⟦w'⟧, hw⟩ + +lemma orbitRelEquiv_apply_mk'' [IsGalois k K] (w : InfinitePlace K) : + orbitRelEquiv (Quotient.mk'' w) = comap w (algebraMap k K) := rfl + end NumberField.InfinitePlace end InfinitePlace From 0fd6ae715b50d878633dae38d6365ffc7283b99f Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Dec 2023 07:27:10 +0000 Subject: [PATCH 186/353] chore(ExteriorAlgebra.Grading): drop `ExteriorAlgebra.instZero` (#9274) Locally change the priority of `MulZeroClass.toZero` instead. See also [Zulip chat](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Exterior.20algebras.20everywhere.2E.2E.2E) --- Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean b/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean index 87526cfc31a4d..020dcbdf19ac8 100644 --- a/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean +++ b/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean @@ -44,8 +44,7 @@ theorem GradedAlgebra.ι_apply (m : M) : -- Porting note: Lean needs to be reminded of this instance otherwise it cannot -- synthesize 0 in the next theorem -instance (α : Type*) [MulZeroClass α] : Zero α := MulZeroClass.toZero - +attribute [instance 1100] MulZeroClass.toZero in theorem GradedAlgebra.ι_sq_zero (m : M) : GradedAlgebra.ι R M m * GradedAlgebra.ι R M m = 0 := by rw [GradedAlgebra.ι_apply, DirectSum.of_mul_of] refine DFinsupp.single_eq_zero.mpr (Subtype.ext <| ExteriorAlgebra.ι_sq_zero _) From e49f0e6079363bb6e9ed5f801e9b8493b2101325 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Tue, 26 Dec 2023 07:50:37 +0000 Subject: [PATCH 187/353] chore: remove deprecated MulEquiv.map_prod, AddEquiv.map_sum (#9078) --- Mathlib/Algebra/Algebra/Equiv.lean | 6 ++++-- Mathlib/Algebra/BigOperators/Basic.lean | 14 ++++---------- Mathlib/Algebra/Star/BigOperators.lean | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Mathlib/Algebra/Algebra/Equiv.lean b/Mathlib/Algebra/Algebra/Equiv.lean index ef768ea12e29d..b4f4504c49961 100644 --- a/Mathlib/Algebra/Algebra/Equiv.lean +++ b/Mathlib/Algebra/Algebra/Equiv.lean @@ -241,8 +241,10 @@ theorem map_smul (r : R) (x : A₁) : e (r • x) = r • e x := by simp only [Algebra.smul_def, map_mul, commutes] #align alg_equiv.map_smul AlgEquiv.map_smul -theorem map_sum {ι : Type*} (f : ι → A₁) (s : Finset ι) : e (∑ x in s, f x) = ∑ x in s, e (f x) := - e.toAddEquiv.map_sum f s +@[deprecated map_sum] +nonrec theorem map_sum {ι : Type*} (f : ι → A₁) (s : Finset ι) : + e (∑ x in s, f x) = ∑ x in s, e (f x) := + map_sum e f s #align alg_equiv.map_sum AlgEquiv.map_sum theorem map_finsupp_sum {α : Type*} [Zero α] {ι : Type*} (f : ι →₀ α) (g : ι → α → A₁) : diff --git a/Mathlib/Algebra/BigOperators/Basic.lean b/Mathlib/Algebra/BigOperators/Basic.lean index 51ccd6cddc5a1..7c252a8743dfa 100644 --- a/Mathlib/Algebra/BigOperators/Basic.lean +++ b/Mathlib/Algebra/BigOperators/Basic.lean @@ -219,14 +219,8 @@ section Deprecated #align monoid_hom.map_prod map_prodₓ #align add_monoid_hom.map_sum map_sumₓ - -/-- Deprecated: use `_root_.map_prod` instead. -/ -@[to_additive (attr := deprecated) "Deprecated: use `_root_.map_sum` instead."] -protected theorem MulEquiv.map_prod [CommMonoid β] [CommMonoid γ] (g : β ≃* γ) (f : α → β) - (s : Finset α) : g (∏ x in s, f x) = ∏ x in s, g (f x) := - map_prod g f s -#align mul_equiv.map_prod MulEquiv.map_prod -#align add_equiv.map_sum AddEquiv.map_sum +#align mul_equiv.map_prod map_prodₓ +#align add_equiv.map_sum map_sumₓ @[deprecated _root_.map_list_prod] protected theorem RingHom.map_list_prod [Semiring β] [Semiring γ] (f : β →+* γ) (l : List β) : @@ -1904,13 +1898,13 @@ open MulOpposite @[simp] theorem op_sum [AddCommMonoid β] {s : Finset α} (f : α → β) : op (∑ x in s, f x) = ∑ x in s, op (f x) := - (opAddEquiv : β ≃+ βᵐᵒᵖ).map_sum _ _ + map_sum (opAddEquiv : β ≃+ βᵐᵒᵖ) _ _ #align finset.op_sum Finset.op_sum @[simp] theorem unop_sum [AddCommMonoid β] {s : Finset α} (f : α → βᵐᵒᵖ) : unop (∑ x in s, f x) = ∑ x in s, unop (f x) := - (opAddEquiv : β ≃+ βᵐᵒᵖ).symm.map_sum _ _ + map_sum (opAddEquiv : β ≃+ βᵐᵒᵖ).symm _ _ #align finset.unop_sum Finset.unop_sum end Opposite diff --git a/Mathlib/Algebra/Star/BigOperators.lean b/Mathlib/Algebra/Star/BigOperators.lean index 70ec49b8ee77b..5a8a771506d77 100644 --- a/Mathlib/Algebra/Star/BigOperators.lean +++ b/Mathlib/Algebra/Star/BigOperators.lean @@ -25,5 +25,5 @@ theorem star_prod [CommMonoid R] [StarMul R] {α : Type*} (s : Finset α) (f : @[simp] theorem star_sum [AddCommMonoid R] [StarAddMonoid R] {α : Type*} (s : Finset α) (f : α → R) : - star (∑ x in s, f x) = ∑ x in s, star (f x) := (starAddEquiv : R ≃+ R).map_sum _ _ + star (∑ x in s, f x) = ∑ x in s, star (f x) := map_sum (starAddEquiv : R ≃+ R) _ _ #align star_sum star_sum From 760ba709eb6f8adb505af117d846c2265e21e8a4 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Tue, 26 Dec 2023 07:50:38 +0000 Subject: [PATCH 188/353] chore: address wlog porting note in OrdConnectedComponent (#9183) `Data.Set.Intervals.OrdConnectedComponent` was ported in #1303 and `wlog` was added later in #2144. Before this change, `trace.profiler` reports that elaborating this proof takes 0.13 seconds. After this change, it reports 0.10 seconds. --- .../Set/Intervals/OrdConnectedComponent.lean | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean b/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean index d7e846c791f3b..7bdca5a5f4608 100644 --- a/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean +++ b/Mathlib/Data/Set/Intervals/OrdConnectedComponent.lean @@ -203,35 +203,32 @@ theorem disjoint_ordT5Nhd : Disjoint (ordT5Nhd s t) (ordT5Nhd t s) := by rcases mem_iUnion₂.1 hx₂ with ⟨b, hbt, hb⟩ clear hx₂ rw [mem_ordConnectedComponent, subset_inter_iff] at ha hb - rcases le_total a b with hab | hab - on_goal 2 => swap_var a ↔ b, s ↔ t, ha ↔ hb, has ↔ hbt - all_goals --- porting note: wlog not implemented yet, the following replaces the three previous lines --- wlog (discharger := tactic.skip) hab : a ≤ b := le_total a b using a b s t, b a t s - cases' ha with ha ha' - cases' hb with hb hb' - have hsub : [[a, b]] ⊆ (ordSeparatingSet s t).ordConnectedSectionᶜ := by - rw [ordSeparatingSet_comm, uIcc_comm] at hb' - calc - [[a, b]] ⊆ [[a, x]] ∪ [[x, b]] := uIcc_subset_uIcc_union_uIcc - _ ⊆ (ordSeparatingSet s t).ordConnectedSectionᶜ := union_subset ha' hb' - clear ha' hb' - rcases le_total x a with hxa | hax - · exact hb (Icc_subset_uIcc' ⟨hxa, hab⟩) has - rcases le_total b x with hbx | hxb - · exact ha (Icc_subset_uIcc ⟨hab, hbx⟩) hbt - have h' : x ∈ ordSeparatingSet s t := ⟨mem_iUnion₂.2 ⟨a, has, ha⟩, mem_iUnion₂.2 ⟨b, hbt, hb⟩⟩ - -- porting note: lift not implemented yet - -- lift x to ordSeparatingSet s t using this - suffices ordConnectedComponent (ordSeparatingSet s t) x ⊆ [[a, b]] from - hsub (this <| ordConnectedProj_mem_ordConnectedComponent _ ⟨x, h'⟩) (mem_range_self _) - rintro y (hy : [[x, y]] ⊆ ordSeparatingSet s t) - rw [uIcc_of_le hab, mem_Icc, ← not_lt, ← not_lt] - have sol1 := fun (hya : y < a) => - (disjoint_left (t := ordSeparatingSet s t)).1 disjoint_left_ordSeparatingSet has - (hy <| Icc_subset_uIcc' ⟨hya.le, hax⟩) - have sol2 := fun (hby : b < y) => - (disjoint_left (t := ordSeparatingSet s t)).1 disjoint_right_ordSeparatingSet hbt - (hy <| Icc_subset_uIcc ⟨hxb, hby.le⟩) - exact ⟨sol1, sol2⟩ + wlog hab : a ≤ b with H + · exact H (x := x) (y := y) (z := z) b hbt hb a has ha (le_of_not_le hab) + cases' ha with ha ha' + cases' hb with hb hb' + have hsub : [[a, b]] ⊆ (ordSeparatingSet s t).ordConnectedSectionᶜ := by + rw [ordSeparatingSet_comm, uIcc_comm] at hb' + calc + [[a, b]] ⊆ [[a, x]] ∪ [[x, b]] := uIcc_subset_uIcc_union_uIcc + _ ⊆ (ordSeparatingSet s t).ordConnectedSectionᶜ := union_subset ha' hb' + clear ha' hb' + rcases le_total x a with hxa | hax + · exact hb (Icc_subset_uIcc' ⟨hxa, hab⟩) has + rcases le_total b x with hbx | hxb + · exact ha (Icc_subset_uIcc ⟨hab, hbx⟩) hbt + have h' : x ∈ ordSeparatingSet s t := ⟨mem_iUnion₂.2 ⟨a, has, ha⟩, mem_iUnion₂.2 ⟨b, hbt, hb⟩⟩ + -- porting note: lift not implemented yet + -- lift x to ordSeparatingSet s t using this + suffices ordConnectedComponent (ordSeparatingSet s t) x ⊆ [[a, b]] from + hsub (this <| ordConnectedProj_mem_ordConnectedComponent _ ⟨x, h'⟩) (mem_range_self _) + rintro y (hy : [[x, y]] ⊆ ordSeparatingSet s t) + rw [uIcc_of_le hab, mem_Icc, ← not_lt, ← not_lt] + have sol1 := fun (hya : y < a) => + (disjoint_left (t := ordSeparatingSet s t)).1 disjoint_left_ordSeparatingSet has + (hy <| Icc_subset_uIcc' ⟨hya.le, hax⟩) + have sol2 := fun (hby : b < y) => + (disjoint_left (t := ordSeparatingSet s t)).1 disjoint_right_ordSeparatingSet hbt + (hy <| Icc_subset_uIcc ⟨hxb, hby.le⟩) + exact ⟨sol1, sol2⟩ #align set.disjoint_ord_t5_nhd Set.disjoint_ordT5Nhd From 23429eb29eb7dcfeb8194b9a1a35e2e74c10ff13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 07:50:39 +0000 Subject: [PATCH 189/353] =?UTF-8?q?feat:=20`0=20=E2=89=A4=20a=20*=20b=20?= =?UTF-8?q?=E2=86=94=20(0=20<=20a=20=E2=86=92=200=20=E2=89=A4=20b)=20?= =?UTF-8?q?=E2=88=A7=20(0=20<=20b=20=E2=86=92=200=20=E2=89=A4=20a)`=20(#92?= =?UTF-8?q?19)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I had a slightly logic-heavy argument that was nicely simplified by stating this lemma. Also fix a few lemma names. From LeanAPAP and LeanCamCombi --- Mathlib/Algebra/Order/Floor.lean | 4 +- .../Algebra/Order/Monoid/Canonical/Defs.lean | 3 +- Mathlib/Algebra/Order/Ring/Canonical.lean | 29 ++++++++++- Mathlib/Algebra/Order/Ring/Defs.lean | 50 +++++++++++++++---- Mathlib/Algebra/Order/Ring/Lemmas.lean | 21 ++++---- Mathlib/Analysis/Hofer.lean | 2 +- .../Analysis/InnerProductSpace/Spectrum.lean | 4 +- .../Analysis/NormedSpace/OperatorNorm.lean | 2 +- Mathlib/Analysis/SpecificLimits/Normed.lean | 2 +- .../Combinatorics/SimpleGraph/DegreeSum.lean | 2 +- .../SimpleGraph/Regularity/Bound.lean | 2 +- .../MeasureTheory/Covering/LiminfLimsup.lean | 3 +- .../DiophantineApproximation.lean | 4 +- Mathlib/NumberTheory/FLT/Four.lean | 2 +- Mathlib/NumberTheory/SumFourSquares.lean | 2 +- .../Probability/Distributions/Gaussian.lean | 8 +-- Mathlib/Tactic/NormNum/Prime.lean | 2 +- 17 files changed, 98 insertions(+), 44 deletions(-) diff --git a/Mathlib/Algebra/Order/Floor.lean b/Mathlib/Algebra/Order/Floor.lean index 3dbf3c2ac4706..6ac5c8149f523 100644 --- a/Mathlib/Algebra/Order/Floor.lean +++ b/Mathlib/Algebra/Order/Floor.lean @@ -1108,7 +1108,7 @@ section LinearOrderedField variable {k : Type*} [LinearOrderedField k] [FloorRing k] {b : k} theorem fract_div_mul_self_mem_Ico (a b : k) (ha : 0 < a) : fract (b / a) * a ∈ Ico 0 a := - ⟨(zero_le_mul_right ha).2 (fract_nonneg (b / a)), + ⟨(mul_nonneg_iff_of_pos_right ha).2 (fract_nonneg (b / a)), (mul_lt_iff_lt_one_left ha).2 (fract_lt_one (b / a))⟩ #align int.fract_div_mul_self_mem_Ico Int.fract_div_mul_self_mem_Ico @@ -1538,7 +1538,7 @@ theorem abs_sub_round_eq_min (x : α) : |x - round x| = min (fract x) (1 - fract · rw [if_pos hx, if_pos hx, self_sub_floor, abs_fract] · have : 0 < fract x := by replace hx : 0 < fract x + fract x := lt_of_lt_of_le zero_lt_one (tsub_le_iff_left.mp hx) - simpa only [← two_mul, zero_lt_mul_left, zero_lt_two] using hx + simpa only [← two_mul, mul_pos_iff_of_pos_left, zero_lt_two] using hx rw [if_neg (not_lt.mpr hx), if_neg (not_lt.mpr hx), abs_sub_comm, ceil_sub_self_eq this.ne.symm, abs_one_sub_fract] #align abs_sub_round_eq_min abs_sub_round_eq_min diff --git a/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean b/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean index 3384afbe32afb..7abb44d07cc6c 100644 --- a/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean +++ b/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean @@ -237,8 +237,7 @@ theorem one_lt_iff_ne_one : 1 < a ↔ a ≠ 1 := #align pos_iff_ne_zero pos_iff_ne_zero @[to_additive] -theorem eq_one_or_one_lt : a = 1 ∨ 1 < a := - (one_le a).eq_or_lt.imp_left Eq.symm +theorem eq_one_or_one_lt (a : α) : a = 1 ∨ 1 < a := (one_le a).eq_or_lt.imp_left Eq.symm #align eq_one_or_one_lt eq_one_or_one_lt #align eq_zero_or_pos eq_zero_or_pos diff --git a/Mathlib/Algebra/Order/Ring/Canonical.lean b/Mathlib/Algebra/Order/Ring/Canonical.lean index 905d04c8c81bb..923c86569fc58 100644 --- a/Mathlib/Algebra/Order/Ring/Canonical.lean +++ b/Mathlib/Algebra/Order/Ring/Canonical.lean @@ -81,9 +81,25 @@ end ExistsAddOfLE end StrictOrderedSemiring +section LinearOrderedCommSemiring +variable [LinearOrderedCommSemiring α] [ExistsAddOfLE α] {a b : α} + +lemma add_sq_le : (a + b) ^ 2 ≤ 2 * (a ^ 2 + b ^ 2) := by + calc + (a + b) ^ 2 = a ^ 2 + b ^ 2 + (a * b + b * a) := by + simp_rw [pow_succ, pow_zero, mul_one, add_mul_self_eq, mul_assoc, two_mul, + add_right_comm _ (_ + _), mul_comm] + _ ≤ a ^ 2 + b ^ 2 + (a * a + b * b) := add_le_add_left ?_ _ + _ = _ := by simp_rw [pow_succ, pow_zero, mul_one, two_mul] + cases le_total a b + · exact mul_add_mul_le_mul_add_mul ‹_› ‹_› + · exact mul_add_mul_le_mul_add_mul' ‹_› ‹_› + +end LinearOrderedCommSemiring + namespace CanonicallyOrderedCommSemiring -variable [CanonicallyOrderedCommSemiring α] {a b : α} +variable [CanonicallyOrderedCommSemiring α] {a b c d : α} -- see Note [lower instance priority] instance (priority := 100) toNoZeroDivisors : NoZeroDivisors α := @@ -112,10 +128,19 @@ instance (priority := 100) toOrderedCommSemiring : OrderedCommSemiring α := #align canonically_ordered_comm_semiring.to_ordered_comm_semiring CanonicallyOrderedCommSemiring.toOrderedCommSemiring @[simp] -theorem mul_pos : 0 < a * b ↔ 0 < a ∧ 0 < b := by +protected theorem mul_pos : 0 < a * b ↔ 0 < a ∧ 0 < b := by simp only [pos_iff_ne_zero, ne_eq, mul_eq_zero, not_or] #align canonically_ordered_comm_semiring.mul_pos CanonicallyOrderedCommSemiring.mul_pos +protected lemma mul_lt_mul_of_lt_of_lt [PosMulStrictMono α] (hab : a < b) (hcd : c < d) : + a * c < b * d := by + -- TODO: This should be an instance but it currently times out + have := posMulStrictMono_iff_mulPosStrictMono.1 ‹_› + obtain rfl | hc := eq_zero_or_pos c + · rw [mul_zero] + exact mul_pos ((zero_le _).trans_lt hab) hcd + · exact mul_lt_mul_of_lt_of_lt' hab hcd ((zero_le _).trans_lt hab) hc + end CanonicallyOrderedCommSemiring section Sub diff --git a/Mathlib/Algebra/Order/Ring/Defs.lean b/Mathlib/Algebra/Order/Ring/Defs.lean index a2db8c247eec6..0281527fcfa1e 100644 --- a/Mathlib/Algebra/Order/Ring/Defs.lean +++ b/Mathlib/Algebra/Order/Ring/Defs.lean @@ -3,6 +3,7 @@ Copyright (c) 2016 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Yaël Dillies -/ +import Mathlib.Algebra.Group.Units import Mathlib.Algebra.GroupWithZero.NeZero import Mathlib.Algebra.Order.Group.Defs import Mathlib.Algebra.Order.Monoid.Defs @@ -11,10 +12,10 @@ import Mathlib.Algebra.Order.Monoid.NatCast import Mathlib.Algebra.Order.Monoid.WithZero.Defs import Mathlib.Algebra.Order.Ring.Lemmas import Mathlib.Algebra.Ring.Defs +import Mathlib.Data.Pi.Algebra import Mathlib.Order.MinMax import Mathlib.Tactic.Nontriviality -import Mathlib.Data.Pi.Algebra -import Mathlib.Algebra.Group.Units +import Mathlib.Tactic.Tauto #align_import algebra.order.ring.defs from "leanprover-community/mathlib"@"44e29dbcff83ba7114a464d592b8c3743987c1e5" @@ -830,15 +831,15 @@ theorem nonpos_of_mul_nonpos_right (h : a * b ≤ 0) (ha : 0 < a) : b ≤ 0 := #align nonpos_of_mul_nonpos_right nonpos_of_mul_nonpos_right @[simp] -theorem zero_le_mul_left (h : 0 < c) : 0 ≤ c * b ↔ 0 ≤ b := by +theorem mul_nonneg_iff_of_pos_left (h : 0 < c) : 0 ≤ c * b ↔ 0 ≤ b := by convert mul_le_mul_left h simp -#align zero_le_mul_left zero_le_mul_left +#align zero_le_mul_left mul_nonneg_iff_of_pos_left @[simp] -theorem zero_le_mul_right (h : 0 < c) : 0 ≤ b * c ↔ 0 ≤ b := by +theorem mul_nonneg_iff_of_pos_right (h : 0 < c) : 0 ≤ b * c ↔ 0 ≤ b := by simpa using (mul_le_mul_right h : 0 * c ≤ b * c ↔ 0 ≤ b) -#align zero_le_mul_right zero_le_mul_right +#align zero_le_mul_right mul_nonneg_iff_of_pos_right -- Porting note: we used to not need the type annotation on `(0 : α)` at the start of the `calc`. theorem add_le_mul_of_left_le_right (a2 : 2 ≤ a) (ab : a ≤ b) : a + b ≤ a * b := @@ -900,22 +901,22 @@ theorem bit1_lt_bit1 : bit1 a < bit1 b ↔ a < b := @[simp] theorem one_le_bit1 : (1 : α) ≤ bit1 a ↔ 0 ≤ a := by - rw [bit1, le_add_iff_nonneg_left, bit0, ← two_mul, zero_le_mul_left (zero_lt_two : 0 < (2 : α))] + rw [bit1, le_add_iff_nonneg_left, bit0, ← two_mul, mul_nonneg_iff_of_pos_left (zero_lt_two' α)] #align one_le_bit1 one_le_bit1 @[simp] theorem one_lt_bit1 : (1 : α) < bit1 a ↔ 0 < a := by - rw [bit1, lt_add_iff_pos_left, bit0, ← two_mul, zero_lt_mul_left (zero_lt_two : 0 < (2 : α))] + rw [bit1, lt_add_iff_pos_left, bit0, ← two_mul, mul_pos_iff_of_pos_left (zero_lt_two' α)] #align one_lt_bit1 one_lt_bit1 @[simp] theorem zero_le_bit0 : (0 : α) ≤ bit0 a ↔ 0 ≤ a := by - rw [bit0, ← two_mul, zero_le_mul_left (zero_lt_two : 0 < (2 : α))] + rw [bit0, ← two_mul, mul_nonneg_iff_of_pos_left (zero_lt_two : 0 < (2 : α))] #align zero_le_bit0 zero_le_bit0 @[simp] theorem zero_lt_bit0 : (0 : α) < bit0 a ↔ 0 < a := by - rw [bit0, ← two_mul, zero_lt_mul_left (zero_lt_two : 0 < (2 : α))] + rw [bit0, ← two_mul, mul_pos_iff_of_pos_left (zero_lt_two : 0 < (2 : α))] #align zero_lt_bit0 zero_lt_bit0 end @@ -939,7 +940,7 @@ theorem nonpos_of_mul_nonneg_right (h : 0 ≤ a * b) (ha : a < 0) : b ≤ 0 := @[simp] theorem Units.inv_pos {u : αˣ} : (0 : α) < ↑u⁻¹ ↔ (0 : α) < u := have : ∀ {u : αˣ}, (0 : α) < u → (0 : α) < ↑u⁻¹ := @fun u h => - (zero_lt_mul_left h).mp <| u.mul_inv.symm ▸ zero_lt_one + (mul_pos_iff_of_pos_left h).mp <| u.mul_inv.symm ▸ zero_lt_one ⟨this, this⟩ #align units.inv_pos Units.inv_pos @@ -1086,6 +1087,22 @@ theorem mul_nonpos_iff : a * b ≤ 0 ↔ 0 ≤ a ∧ b ≤ 0 ∨ a ≤ 0 ∧ 0 rw [← neg_nonneg, neg_mul_eq_mul_neg, mul_nonneg_iff, neg_nonneg, neg_nonpos] #align mul_nonpos_iff mul_nonpos_iff +lemma mul_nonneg_iff_pos_imp_nonneg : 0 ≤ a * b ↔ (0 < a → 0 ≤ b) ∧ (0 < b → 0 ≤ a) := by + refine mul_nonneg_iff.trans ?_ + simp_rw [← not_le, ← or_iff_not_imp_left] + have := le_total a 0 + have := le_total b 0 + tauto + +lemma mul_nonneg_iff_neg_imp_nonpos : 0 ≤ a * b ↔ (a < 0 → b ≤ 0) ∧ (b < 0 → a ≤ 0) := by + rw [← neg_mul_neg, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + +lemma mul_nonpos_iff_pos_imp_nonpos : a * b ≤ 0 ↔ (0 < a → b ≤ 0) ∧ (b < 0 → 0 ≤ a) := by + rw [← neg_nonneg, ← mul_neg, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + +lemma mul_nonpos_iff_neg_imp_nonneg : a * b ≤ 0 ↔ (a < 0 → 0 ≤ b) ∧ (0 < b → a ≤ 0) := by + rw [← neg_nonneg, ← neg_mul, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + theorem mul_self_nonneg (a : α) : 0 ≤ a * a := (le_total 0 a).elim (fun h => mul_nonneg h h) fun h => mul_nonneg_of_nonpos_of_nonpos h h #align mul_self_nonneg mul_self_nonneg @@ -1212,3 +1229,14 @@ theorem max_mul_mul_le_max_mul_max (b c : α) (ha : 0 ≤ a) (hd : 0 ≤ d) : #align max_mul_mul_le_max_mul_max max_mul_mul_le_max_mul_max end LinearOrderedCommRing + +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on 2023/12/23 +-/ + +@[deprecated] alias zero_le_mul_left := mul_nonneg_iff_of_pos_left +@[deprecated] alias zero_le_mul_right := mul_nonneg_iff_of_pos_right +@[deprecated] alias zero_lt_mul_left := mul_pos_iff_of_pos_left +@[deprecated] alias zero_lt_mul_right := mul_pos_iff_of_pos_right diff --git a/Mathlib/Algebra/Order/Ring/Lemmas.lean b/Mathlib/Algebra/Order/Ring/Lemmas.lean index fbaf7bc110d79..e479351e04a2d 100644 --- a/Mathlib/Algebra/Order/Ring/Lemmas.lean +++ b/Mathlib/Algebra/Order/Ring/Lemmas.lean @@ -266,6 +266,11 @@ theorem mul_le_mul_right [MulPosMono α] [MulPosReflectLE α] (a0 : 0 < a) : b * @rel_iff_cov α>0 α (fun x y => y * x) (· ≤ ·) _ _ ⟨a, a0⟩ _ _ #align mul_le_mul_right mul_le_mul_right +alias mul_le_mul_iff_of_pos_left := mul_le_mul_left +alias mul_le_mul_iff_of_pos_right := mul_le_mul_right +alias mul_lt_mul_iff_of_pos_left := mul_lt_mul_left +alias mul_lt_mul_iff_of_pos_right := mul_lt_mul_right + theorem mul_lt_mul_of_pos_of_nonneg [PosMulStrictMono α] [MulPosMono α] (h₁ : a ≤ b) (h₂ : c < d) (a0 : 0 < a) (d0 : 0 ≤ d) : a * c < b * d := (mul_lt_mul_of_pos_left h₂ a0).trans_le (mul_le_mul_of_nonneg_right h₁ d0) @@ -401,11 +406,9 @@ theorem mul_neg_of_pos_of_neg [PosMulStrictMono α] (ha : 0 < a) (hb : b < 0) : #align mul_neg_of_pos_of_neg mul_neg_of_pos_of_neg @[simp] -theorem zero_lt_mul_left [PosMulStrictMono α] [PosMulReflectLT α] (h : 0 < c) : - 0 < c * b ↔ 0 < b := by - rw [← mul_zero c, mul_lt_mul_left h] - simp -#align zero_lt_mul_left zero_lt_mul_left +theorem mul_pos_iff_of_pos_left [PosMulStrictMono α] [PosMulReflectLT α] (h : 0 < a) : + 0 < a * b ↔ 0 < b := by simpa using mul_lt_mul_left (b := 0) h +#align zero_lt_mul_left mul_pos_iff_of_pos_left /-- Assumes right covariance. -/ theorem Right.mul_pos [MulPosStrictMono α] (ha : 0 < a) (hb : 0 < b) : 0 < a * b := by @@ -417,11 +420,9 @@ theorem mul_neg_of_neg_of_pos [MulPosStrictMono α] (ha : a < 0) (hb : 0 < b) : #align mul_neg_of_neg_of_pos mul_neg_of_neg_of_pos @[simp] -theorem zero_lt_mul_right [MulPosStrictMono α] [MulPosReflectLT α] (h : 0 < c) : - 0 < b * c ↔ 0 < b := by - rw [← zero_mul c, mul_lt_mul_right h] - simp -#align zero_lt_mul_right zero_lt_mul_right +theorem mul_pos_iff_of_pos_right [MulPosStrictMono α] [MulPosReflectLT α] (h : 0 < b) : + 0 < a * b ↔ 0 < a := by simpa using mul_lt_mul_right (b := 0) h +#align zero_lt_mul_right mul_pos_iff_of_pos_right /-- Assumes left covariance. -/ theorem Left.mul_nonneg [PosMulMono α] (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a * b := by diff --git a/Mathlib/Analysis/Hofer.lean b/Mathlib/Analysis/Hofer.lean index 30050bd713c45..0b5364efcf5a9 100644 --- a/Mathlib/Analysis/Hofer.lean +++ b/Mathlib/Analysis/Hofer.lean @@ -100,7 +100,7 @@ theorem hofer {X : Type*} [MetricSpace X] [CompleteSpace X] (x : X) (ε : ℝ) ( have hv₀ : 0 < v 0 := by have : 0 ≤ ϕ (u 0) := nonneg x calc - 0 ≤ 2 * ϕ (u 0) := (zero_le_mul_left zero_lt_two).mpr this + 0 ≤ 2 * ϕ (u 0) := (mul_nonneg_iff_of_pos_left zero_lt_two).mpr this _ < ϕ (u (0 + 1)) := key₂ 0 apply tendsto_atTop_of_geom_le hv₀ one_lt_two exact fun n => (key₂ (n + 1)).le diff --git a/Mathlib/Analysis/InnerProductSpace/Spectrum.lean b/Mathlib/Analysis/InnerProductSpace/Spectrum.lean index 58de7527eb1cb..5bd0f990666fa 100644 --- a/Mathlib/Analysis/InnerProductSpace/Spectrum.lean +++ b/Mathlib/Analysis/InnerProductSpace/Spectrum.lean @@ -291,7 +291,7 @@ theorem eigenvalue_nonneg_of_nonneg {μ : ℝ} {T : E →ₗ[𝕜] E} (hμ : Has -- porting note: why can't `exact_mod_cast` do this? These lemmas are marked `norm_cast` rw [← IsROrC.ofReal_pow, ← IsROrC.ofReal_mul] at this exact mod_cast this - exact (zero_le_mul_right hpos).mp (this ▸ hnn v) + exact (mul_nonneg_iff_of_pos_right hpos).mp (this ▸ hnn v) #align eigenvalue_nonneg_of_nonneg eigenvalue_nonneg_of_nonneg theorem eigenvalue_pos_of_pos {μ : ℝ} {T : E →ₗ[𝕜] E} (hμ : HasEigenvalue T μ) @@ -303,7 +303,7 @@ theorem eigenvalue_pos_of_pos {μ : ℝ} {T : E →ₗ[𝕜] E} (hμ : HasEigenv -- porting note: why can't `exact_mod_cast` do this? These lemmas are marked `norm_cast` rw [← IsROrC.ofReal_pow, ← IsROrC.ofReal_mul] at this exact mod_cast this - exact (zero_lt_mul_right hpos).mp (this ▸ hnn v) + exact (mul_pos_iff_of_pos_right hpos).mp (this ▸ hnn v) #align eigenvalue_pos_of_pos eigenvalue_pos_of_pos end Nonneg diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm.lean index cb614ce41f378..8a2d176302e92 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm.lean @@ -1479,7 +1479,7 @@ theorem homothety_norm [RingHomIsometric σ₁₂] [Nontrivial E] (f : E →SL[ (hf : ∀ x, ‖f x‖ = a * ‖x‖) : ‖f‖ = a := by obtain ⟨x, hx⟩ : ∃ x : E, x ≠ 0 := exists_ne 0 rw [← norm_pos_iff] at hx - have ha : 0 ≤ a := by simpa only [hf, hx, zero_le_mul_right] using norm_nonneg (f x) + have ha : 0 ≤ a := by simpa only [hf, hx, mul_nonneg_iff_of_pos_right] using norm_nonneg (f x) apply le_antisymm (f.op_norm_le_bound ha fun y => le_of_eq (hf y)) simpa only [hf, hx, mul_le_mul_right] using f.le_op_norm x #align continuous_linear_map.homothety_norm ContinuousLinearMap.homothety_norm diff --git a/Mathlib/Analysis/SpecificLimits/Normed.lean b/Mathlib/Analysis/SpecificLimits/Normed.lean index ea331b41d8fae..7097914871853 100644 --- a/Mathlib/Analysis/SpecificLimits/Normed.lean +++ b/Mathlib/Analysis/SpecificLimits/Normed.lean @@ -428,7 +428,7 @@ theorem NormedAddCommGroup.cauchy_series_of_le_geometric'' {C : ℝ} {u : ℕ CauchySeq fun n ↦ ∑ k in range (n + 1), u k := by set v : ℕ → α := fun n ↦ if n < N then 0 else u n have hC : 0 ≤ C := - (zero_le_mul_right <| pow_pos hr₀ N).mp ((norm_nonneg _).trans <| h N <| le_refl N) + (mul_nonneg_iff_of_pos_right <| pow_pos hr₀ N).mp ((norm_nonneg _).trans <| h N <| le_refl N) have : ∀ n ≥ N, u n = v n := by intro n hn simp [hn, if_neg (not_lt.mpr hn)] diff --git a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean index 4e9e3055bee8f..f64864503ce12 100644 --- a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean +++ b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean @@ -140,7 +140,7 @@ theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] [DecidableRe use v simp only [true_and_iff, mem_filter, mem_univ] exact h - rwa [← card_pos, hg, ← two_mul, zero_lt_mul_left] at hh + rwa [← card_pos, hg, ← two_mul, mul_pos_iff_of_pos_left] at hh exact zero_lt_two have hc : (fun w : V => w ≠ v ∧ Odd (G.degree w)) = fun w : V => Odd (G.degree w) ∧ w ≠ v := by ext w diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean index 87b8f92135ef7..c26f2522c11c7 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean @@ -50,7 +50,7 @@ theorem stepBound_mono : Monotone stepBound := fun a b h => #align szemeredi_regularity.step_bound_mono SzemerediRegularity.stepBound_mono theorem stepBound_pos_iff {n : ℕ} : 0 < stepBound n ↔ 0 < n := - zero_lt_mul_right <| by positivity + mul_pos_iff_of_pos_right <| by positivity #align szemeredi_regularity.step_bound_pos_iff SzemerediRegularity.stepBound_pos_iff alias ⟨_, stepBound_pos⟩ := stepBound_pos_iff diff --git a/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean b/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean index d4f45067213c0..c0ae3598c66b8 100644 --- a/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean +++ b/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean @@ -282,7 +282,8 @@ theorem blimsup_thickening_mul_ae_eq (p : ℕ → Prop) (s : ℕ → Set α) {M have h₂ : blimsup (fun i => thickening (M * r i) (s i)) atTop p = blimsup (fun i => thickening (M * r i) (s i)) atTop q := by refine' blimsup_congr' (eventually_of_forall fun i h => _) - replace h : 0 < r i; · rw [← zero_lt_mul_left hM]; contrapose! h; apply thickening_of_nonpos h + replace h : 0 < r i + · rw [← mul_pos_iff_of_pos_left hM]; contrapose! h; apply thickening_of_nonpos h simp only [h, iff_self_and, imp_true_iff] rw [h₁, h₂] exact blimsup_thickening_mul_ae_eq_aux μ q s hM r hr (eventually_of_forall fun i hi => hi.2) diff --git a/Mathlib/NumberTheory/DiophantineApproximation.lean b/Mathlib/NumberTheory/DiophantineApproximation.lean index b0d912b7c417a..9ea505ff15bdf 100644 --- a/Mathlib/NumberTheory/DiophantineApproximation.lean +++ b/Mathlib/NumberTheory/DiophantineApproximation.lean @@ -446,8 +446,8 @@ private theorem aux₂ : 0 < u - ⌊ξ⌋ * v ∧ u - ⌊ξ⌋ * v < v := by sub_lt_iff_lt_add, mul_assoc] at h have hu₀ : 0 ≤ u - ⌊ξ⌋ * v := by -- Porting note: this abused the definitional equality `-1 + 1 = 0` - -- refine' (zero_le_mul_right hv₁).mp ((lt_iff_add_one_le (-1 : ℤ) _).mp _) - refine' (zero_le_mul_right hv₁).mp ?_ + -- refine' (mul_nonneg_iff_of_pos_right hv₁).mp ((lt_iff_add_one_le (-1 : ℤ) _).mp _) + refine' (mul_nonneg_iff_of_pos_right hv₁).mp ?_ rw [← sub_one_lt_iff, zero_sub] replace h := h.1 rw [← lt_sub_iff_add_lt, ← mul_assoc, ← sub_mul] at h diff --git a/Mathlib/NumberTheory/FLT/Four.lean b/Mathlib/NumberTheory/FLT/Four.lean index f14ef036a5507..6d7723ec6966f 100644 --- a/Mathlib/NumberTheory/FLT/Four.lean +++ b/Mathlib/NumberTheory/FLT/Four.lean @@ -250,7 +250,7 @@ theorem not_minimal {a b c : ℤ} (h : Minimal a b c) (ha2 : a % 2 = 1) (hc : 0 rw [h1] at hs have h2 : b' ^ 2 ≤ 0 := by rw [hs, (by ring : -d ^ 2 * m = -(d ^ 2 * m))] - exact neg_nonpos.mpr ((zero_le_mul_right h4).mpr (sq_nonneg d)) + exact neg_nonpos.mpr ((mul_nonneg_iff_of_pos_right h4).mpr (sq_nonneg d)) have h2' : 0 ≤ b' ^ 2 := by apply sq_nonneg b' exact absurd (lt_of_le_of_ne h2' (Ne.symm (pow_ne_zero _ h2b0))) (not_lt.mpr h2) replace hd : r * s = d ^ 2 diff --git a/Mathlib/NumberTheory/SumFourSquares.lean b/Mathlib/NumberTheory/SumFourSquares.lean index 1dc0944b7b3c9..df9d144eff129 100644 --- a/Mathlib/NumberTheory/SumFourSquares.lean +++ b/Mathlib/NumberTheory/SumFourSquares.lean @@ -161,7 +161,7 @@ protected theorem Prime.sum_four_squares {p : ℕ} (hp : p.Prime) : by_cases hm : 2 ∣ m · -- If `m` is an even number, then `(m / 2) * p` can be represented as a sum of four squares rcases hm with ⟨m, rfl⟩ - rw [zero_lt_mul_left two_pos] at hm₀ + rw [mul_pos_iff_of_pos_left two_pos] at hm₀ have hm₂ : m < 2 * m := by simpa [two_mul] apply_fun (Nat.cast : ℕ → ℤ) at habcd push_cast [mul_assoc] at habcd diff --git a/Mathlib/Probability/Distributions/Gaussian.lean b/Mathlib/Probability/Distributions/Gaussian.lean index d4c6425f6e0bf..76028a93f2627 100644 --- a/Mathlib/Probability/Distributions/Gaussian.lean +++ b/Mathlib/Probability/Distributions/Gaussian.lean @@ -83,7 +83,7 @@ lemma integrable_gaussianPdfReal (μ : ℝ) (v : ℝ≥0) : refine (integrable_exp_neg_mul_sq ?_).const_mul (Real.sqrt (2 * π * v))⁻¹ simp [lt_of_le_of_ne (zero_le _) (Ne.symm hv)] ext x - simp only [gt_iff_lt, zero_lt_two, zero_le_mul_left, NNReal.zero_le_coe, Real.sqrt_mul', + simp only [zero_lt_two, mul_nonneg_iff_of_pos_left, NNReal.zero_le_coe, Real.sqrt_mul', mul_inv_rev, NNReal.coe_mul, NNReal.coe_inv, NNReal.coe_ofNat, neg_mul, mul_eq_mul_left_iff, Real.exp_eq_exp, mul_eq_zero, inv_eq_zero, Real.sqrt_eq_zero, NNReal.coe_eq_zero, hv, false_or] @@ -100,10 +100,10 @@ lemma lintegral_gaussianPdfReal_eq_one (μ : ℝ) {v : ℝ≥0} (h : v ≠ 0) : (stronglyMeasurable_gaussianPdfReal μ v).aestronglyMeasurable have hf : 0 ≤ₐₛ gaussianPdfReal μ v := ae_of_all _ (gaussianPdfReal_nonneg μ v) rw [← integral_eq_lintegral_of_nonneg_ae hf hfm] - simp only [gaussianPdfReal, gt_iff_lt, zero_lt_two, zero_le_mul_right, ge_iff_le, one_div, + simp only [gaussianPdfReal, zero_lt_two, mul_nonneg_iff_of_pos_right, one_div, Nat.cast_ofNat, integral_mul_left] rw [integral_sub_right_eq_self (μ := volume) (fun a ↦ rexp (-a ^ 2 / ((2 : ℝ) * v))) μ] - simp only [gt_iff_lt, zero_lt_two, zero_le_mul_right, ge_iff_le, div_eq_inv_mul, mul_inv_rev, + simp only [zero_lt_two, mul_nonneg_iff_of_pos_right, div_eq_inv_mul, mul_inv_rev, mul_neg] simp_rw [← neg_mul] rw [neg_mul, integral_gaussian, ← Real.sqrt_inv, ← Real.sqrt_mul] @@ -130,7 +130,7 @@ lemma gaussianPdfReal_add {μ : ℝ} {v : ℝ≥0} (x y : ℝ) : lemma gaussianPdfReal_inv_mul {μ : ℝ} {v : ℝ≥0} {c : ℝ} (hc : c ≠ 0) (x : ℝ) : gaussianPdfReal μ v (c⁻¹ * x) = |c| * gaussianPdfReal (c * μ) (⟨c^2, sq_nonneg _⟩ * v) x := by - simp only [gaussianPdfReal._eq_1, gt_iff_lt, zero_lt_two, zero_le_mul_left, NNReal.zero_le_coe, + simp only [gaussianPdfReal._eq_1, zero_lt_two, mul_nonneg_iff_of_pos_left, NNReal.zero_le_coe, Real.sqrt_mul', one_div, mul_inv_rev, NNReal.coe_mul, NNReal.coe_mk, NNReal.coe_pos] rw [← mul_assoc] refine congr_arg₂ _ ?_ ?_ diff --git a/Mathlib/Tactic/NormNum/Prime.lean b/Mathlib/Tactic/NormNum/Prime.lean index 951b62463536e..76556d646e710 100644 --- a/Mathlib/Tactic/NormNum/Prime.lean +++ b/Mathlib/Tactic/NormNum/Prime.lean @@ -50,7 +50,7 @@ def MinFacHelper (n k : ℕ) : Prop := theorem MinFacHelper.one_lt {n k : ℕ} (h : MinFacHelper n k) : 1 < n := by have : 2 < minFac n := h.1.trans_le h.2.2 - rcases eq_zero_or_pos n with rfl|h + obtain rfl | h := n.eq_zero_or_pos · contradiction rcases (succ_le_of_lt h).eq_or_lt with rfl|h · contradiction From 1b3fc93741a27b64a6fecabba44aab0bcfaabab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 07:50:40 +0000 Subject: [PATCH 190/353] chore: Protect `Nat.Prime.factorization` (#9242) Else this conflicts with `Nat.factorization`. --- Mathlib/Data/Nat/Factorization/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index 9ffc3a06ff529..0259da359732d 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -241,7 +241,7 @@ theorem factorization_pow (n k : ℕ) : factorization (n ^ k) = k • n.factoriz /-- The only prime factor of prime `p` is `p` itself, with multiplicity `1` -/ @[simp] -theorem Prime.factorization {p : ℕ} (hp : Prime p) : p.factorization = single p 1 := by +protected theorem Prime.factorization {p : ℕ} (hp : Prime p) : p.factorization = single p 1 := by ext q rw [← factors_count_eq, factors_prime hp, single_apply, count_singleton', if_congr eq_comm] <;> rfl From 6f7d92d3ab5051217bfcd12e5681aa63c21d0823 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Dec 2023 07:50:41 +0000 Subject: [PATCH 191/353] feat(CompactOpen): unify 2 `continuous_eval` lemmas (#9264) Introduce a typeclass `LocallyCompactPair` that allows us to unify different versions of `ContinuousMap.continuous_eval` and similar lemmas. --- Mathlib/Topology/CompactOpen.lean | 97 +++++++++---------- Mathlib/Topology/Compactness/Compact.lean | 27 ++++-- .../Topology/Compactness/LocallyCompact.lean | 60 +++++++++--- Mathlib/Topology/Connected/PathConnected.lean | 2 +- .../Topology/ContinuousFunction/Algebra.lean | 8 +- .../Topology/ContinuousFunction/Compact.lean | 6 -- Mathlib/Topology/Homotopy/HomotopyGroup.lean | 2 +- Mathlib/Topology/Separation.lean | 31 +++--- 8 files changed, 136 insertions(+), 97 deletions(-) diff --git a/Mathlib/Topology/CompactOpen.lean b/Mathlib/Topology/CompactOpen.lean index b10e139049afd..b11b67ec160c3 100644 --- a/Mathlib/Topology/CompactOpen.lean +++ b/Mathlib/Topology/CompactOpen.lean @@ -32,9 +32,8 @@ compact-open, curry, function space -/ -open Set - -open Topology +open Set Filter TopologicalSpace +open scoped Topology namespace ContinuousMap @@ -91,6 +90,23 @@ protected theorem isOpen_gen {s : Set α} (hs : IsCompact s) {u : Set β} (hu : TopologicalSpace.GenerateOpen.basic _ (by dsimp [mem_setOf_eq]; tauto) #align continuous_map.is_open_gen ContinuousMap.isOpen_gen +lemma isOpen_setOf_mapsTo {K : Set α} (hK : IsCompact K) {U : Set β} (hU : IsOpen U) : + IsOpen {f : C(α, β) | MapsTo f K U} := by + simpa only [mapsTo'] using ContinuousMap.isOpen_gen hK hU + +lemma eventually_mapsTo {f : C(α, β)} {K U} (hK : IsCompact K) (hU : IsOpen U) (h : MapsTo f K U) : + ∀ᶠ g : C(α, β) in 𝓝 f, MapsTo g K U := + (isOpen_setOf_mapsTo hK hU).mem_nhds h + +lemma tendsto_nhds_compactOpen {α : Type*} {l : Filter α} {f : α → C(β, γ)} {g : C(β, γ)} : + Tendsto f l (𝓝 g) ↔ + ∀ K, IsCompact K → ∀ U, IsOpen U → MapsTo g K U → ∀ᶠ a in l, MapsTo (f a) K U := by + simp_rw [compactOpen_eq, tendsto_nhds_generateFrom_iff, forall_image2_iff, mapsTo']; rfl + +lemma continuous_compactOpen {f : α → C(β, γ)} : + Continuous f ↔ ∀ K, IsCompact K → ∀ U, IsOpen U → IsOpen {x | MapsTo (f x) K U} := by + simp_rw [compactOpen_eq, continuous_generateFrom_iff, forall_image2_iff, mapsTo']; rfl + section Functorial variable (g : C(β, γ)) @@ -136,29 +152,20 @@ theorem continuous_comp_left : Continuous (fun g => g.comp f : C(β, γ) → C( /-- Composition is a continuous map from `C(α, β) × C(β, γ)` to `C(α, γ)`, provided that `β` is locally compact. This is Prop. 9 of Chap. X, §3, №. 4 of Bourbaki's *Topologie Générale*. -/ -theorem continuous_comp' [LocallyCompactSpace β] : - Continuous fun x : C(α, β) × C(β, γ) => x.2.comp x.1 := - continuous_generateFrom_iff.2 - (by - rintro M ⟨K, hK, U, hU, rfl⟩ - conv => - congr - rw [CompactOpen.gen, preimage_setOf_eq] - --congr - ext; dsimp [setOf] - rw [image_comp, image_subset_iff] - rw [isOpen_iff_forall_mem_open] - rintro ⟨φ₀, ψ₀⟩ H - obtain ⟨L, hL, hKL, hLU⟩ := exists_compact_between (hK.image φ₀.2) (hU.preimage ψ₀.2) H - use { φ : C(α, β) | φ '' K ⊆ interior L } ×ˢ { ψ : C(β, γ) | ψ '' L ⊆ U } - -- porting note: typing hint `: φ '' K ⊆ interior L` wasn't previously required - use fun ⟨φ, ψ⟩ ⟨(hφ : φ '' K ⊆ interior L), hψ⟩ => - subset_trans hφ (interior_subset.trans <| image_subset_iff.mp hψ) - use (ContinuousMap.isOpen_gen hK isOpen_interior).prod (ContinuousMap.isOpen_gen hL hU) - exact mem_prod.mpr ⟨hKL, image_subset_iff.mpr hLU⟩) +theorem continuous_comp' [LocallyCompactPair β γ] : + Continuous fun x : C(α, β) × C(β, γ) => x.2.comp x.1 := by + simp_rw [continuous_iff_continuousAt, ContinuousAt, tendsto_nhds_compactOpen] + intro ⟨f, g⟩ K hK U hU (hKU : MapsTo (g ∘ f) K U) + obtain ⟨L, hKL, hLc, hLU⟩ : ∃ L ∈ 𝓝ˢ (f '' K), IsCompact L ∧ MapsTo g L U := + exists_mem_nhdsSet_isCompact_mapsTo g.continuous (hK.image f.continuous) hU + (mapsTo_image_iff.2 hKU) + rw [← subset_interior_iff_mem_nhdsSet, ← mapsTo'] at hKL + exact ((eventually_mapsTo hK isOpen_interior hKL).prod_nhds + (eventually_mapsTo hLc hU hLU)).mono fun ⟨f', g'⟩ ⟨hf', hg'⟩ ↦ + hg'.comp <| hf'.mono_right interior_subset #align continuous_map.continuous_comp' ContinuousMap.continuous_comp' -theorem continuous.comp' {X : Type*} [TopologicalSpace X] [LocallyCompactSpace β] {f : X → C(α, β)} +theorem continuous.comp' {X : Type*} [TopologicalSpace X] [LocallyCompactPair β γ] {f : X → C(α, β)} {g : X → C(β, γ)} (hf : Continuous f) (hg : Continuous g) : Continuous fun x => (g x).comp (f x) := continuous_comp'.comp (hf.prod_mk hg : Continuous fun x => (f x, g x)) @@ -168,30 +175,18 @@ end Functorial section Ev -/-- The evaluation map `C(α, β) × α → β` is continuous if `α` is locally compact. - -See also `ContinuousMap.continuous_eval` -/ -theorem continuous_eval' [LocallyCompactSpace α] : Continuous fun p : C(α, β) × α => p.1 p.2 := - continuous_iff_continuousAt.mpr fun ⟨f, x⟩ n hn => - let ⟨v, vn, vo, fxv⟩ := mem_nhds_iff.mp hn - have : v ∈ 𝓝 (f x) := IsOpen.mem_nhds vo fxv - let ⟨s, hs, sv, sc⟩ := - LocallyCompactSpace.local_compact_nhds x (f ⁻¹' v) (f.continuous.tendsto x this) - let ⟨u, us, uo, xu⟩ := mem_nhds_iff.mp hs - show (fun p : C(α, β) × α => p.1 p.2) ⁻¹' n ∈ 𝓝 (f, x) from - let w := CompactOpen.gen s v ×ˢ u - have : w ⊆ (fun p : C(α, β) × α => p.1 p.2) ⁻¹' n := fun ⟨f', x'⟩ ⟨hf', hx'⟩ => - vn <| hf' <| mem_image_of_mem f' (us hx') - --Porting note: The following `calc` block fails here. - --calc - -- f' x' ∈ f' '' s := mem_image_of_mem f' (us hx') - -- _ ⊆ v := hf' - -- _ ⊆ n := vn - - have : IsOpen w := (ContinuousMap.isOpen_gen sc vo).prod uo - have : (f, x) ∈ w := ⟨image_subset_iff.mpr sv, xu⟩ - mem_nhds_iff.mpr ⟨w, by assumption, by assumption, by assumption⟩ -#align continuous_map.continuous_eval' ContinuousMap.continuous_eval' +/-- The evaluation map `C(α, β) × α → β` is continuous +if `α, β` is a locally compact pair of spaces. -/ +@[continuity] +theorem continuous_eval [LocallyCompactPair α β] : Continuous fun p : C(α, β) × α => p.1 p.2 := by + simp_rw [continuous_iff_continuousAt, ContinuousAt, (nhds_basis_opens _).tendsto_right_iff] + rintro ⟨f, x⟩ U ⟨hx : f x ∈ U, hU : IsOpen U⟩ + rcases exists_mem_nhds_isCompact_mapsTo f.continuous (hU.mem_nhds hx) with ⟨K, hxK, hK, hKU⟩ + filter_upwards [prod_mem_nhds (eventually_mapsTo hK hU hKU) hxK] using fun _ h ↦ h.1 h.2 +#align continuous_map.continuous_eval' ContinuousMap.continuous_eval +#align continuous_map.continuous_eval ContinuousMap.continuous_eval + +@[deprecated] alias continuous_eval' := continuous_eval /-- Evaluation of a continuous map `f` at a point `a` is continuous in `f`. @@ -395,13 +390,13 @@ theorem continuous_curry [LocallyCompactSpace (α × β)] : apply continuous_of_continuous_uncurry apply continuous_of_continuous_uncurry rw [← (Homeomorph.prodAssoc _ _ _).symm.comp_continuous_iff'] - exact continuous_eval' + exact continuous_eval #align continuous_map.continuous_curry ContinuousMap.continuous_curry /-- The uncurried form of a continuous map `α → C(β, γ)` is a continuous map `α × β → γ`. -/ theorem continuous_uncurry_of_continuous [LocallyCompactSpace β] (f : C(α, C(β, γ))) : Continuous (Function.uncurry fun x y => f x y) := - continuous_eval'.comp <| f.continuous.prod_map continuous_id + continuous_eval.comp <| f.continuous.prod_map continuous_id #align continuous_map.continuous_uncurry_of_continuous ContinuousMap.continuous_uncurry_of_continuous /-- The uncurried form of a continuous map `α → C(β, γ)` as a continuous map `α × β → γ` (if `β` is @@ -417,7 +412,7 @@ theorem continuous_uncurry [LocallyCompactSpace α] [LocallyCompactSpace β] : Continuous (uncurry : C(α, C(β, γ)) → C(α × β, γ)) := by apply continuous_of_continuous_uncurry rw [← (Homeomorph.prodAssoc _ _ _).comp_continuous_iff'] - apply continuous_eval'.comp (continuous_eval'.prod_map continuous_id) + apply continuous_eval.comp (continuous_eval.prod_map continuous_id) #align continuous_map.continuous_uncurry ContinuousMap.continuous_uncurry /-- The family of constant maps: `β → C(α, β)` as a continuous map. -/ diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index 821878173534c..26a392c956c3d 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.lean @@ -191,20 +191,31 @@ theorem IsCompact.elim_finite_subcover {ι : Type v} (hs : IsCompact s) (U : ι (directed_of_isDirected_le fun _ _ h => biUnion_subset_biUnion_left h) #align is_compact.elim_finite_subcover IsCompact.elim_finite_subcover +lemma IsCompact.elim_nhds_subcover_nhdsSet' (hs : IsCompact s) (U : ∀ x ∈ s, Set X) + (hU : ∀ x hx, U x hx ∈ 𝓝 x) : ∃ t : Finset s, (⋃ x ∈ t, U x.1 x.2) ∈ 𝓝ˢ s := by + rcases hs.elim_finite_subcover (fun x : s ↦ interior (U x x.2)) (fun _ ↦ isOpen_interior) + fun x hx ↦ mem_iUnion.2 ⟨⟨x, hx⟩, mem_interior_iff_mem_nhds.2 <| hU _ _⟩ with ⟨t, hst⟩ + refine ⟨t, mem_nhdsSet_iff_forall.2 fun x hx ↦ ?_⟩ + rcases mem_iUnion₂.1 (hst hx) with ⟨y, hyt, hy⟩ + refine mem_of_superset ?_ (subset_biUnion_of_mem hyt) + exact mem_interior_iff_mem_nhds.1 hy + +lemma IsCompact.elim_nhds_subcover_nhdsSet (hs : IsCompact s) {U : X → Set X} + (hU : ∀ x ∈ s, U x ∈ 𝓝 x) : ∃ t : Finset X, (∀ x ∈ t, x ∈ s) ∧ (⋃ x ∈ t, U x) ∈ 𝓝ˢ s := + let ⟨t, ht⟩ := hs.elim_nhds_subcover_nhdsSet' (fun x _ => U x) hU + ⟨t.image (↑), fun x hx => + let ⟨y, _, hyx⟩ := Finset.mem_image.1 hx + hyx ▸ y.2, + by rwa [Finset.set_biUnion_finset_image]⟩ + theorem IsCompact.elim_nhds_subcover' (hs : IsCompact s) (U : ∀ x ∈ s, Set X) (hU : ∀ x (hx : x ∈ s), U x ‹x ∈ s› ∈ 𝓝 x) : ∃ t : Finset s, s ⊆ ⋃ x ∈ t, U (x : s) x.2 := - (hs.elim_finite_subcover (fun x : s => interior (U x x.2)) (fun _ => isOpen_interior) fun x hx => - mem_iUnion.2 ⟨⟨x, hx⟩, mem_interior_iff_mem_nhds.2 <| hU _ _⟩).imp - fun _t ht => ht.trans <| iUnion₂_mono fun _ _ => interior_subset + (hs.elim_nhds_subcover_nhdsSet' U hU).imp fun _ ↦ subset_of_mem_nhdsSet #align is_compact.elim_nhds_subcover' IsCompact.elim_nhds_subcover' theorem IsCompact.elim_nhds_subcover (hs : IsCompact s) (U : X → Set X) (hU : ∀ x ∈ s, U x ∈ 𝓝 x) : ∃ t : Finset X, (∀ x ∈ t, x ∈ s) ∧ s ⊆ ⋃ x ∈ t, U x := - let ⟨t, ht⟩ := hs.elim_nhds_subcover' (fun x _ => U x) hU - ⟨t.image (↑), fun x hx => - let ⟨y, _, hyx⟩ := Finset.mem_image.1 hx - hyx ▸ y.2, - by rwa [Finset.set_biUnion_finset_image]⟩ + (hs.elim_nhds_subcover_nhdsSet hU).imp fun _ h ↦ h.imp_right subset_of_mem_nhdsSet #align is_compact.elim_nhds_subcover IsCompact.elim_nhds_subcover /-- The neighborhood filter of a compact set is disjoint with a filter `l` if and only if the diff --git a/Mathlib/Topology/Compactness/LocallyCompact.lean b/Mathlib/Topology/Compactness/LocallyCompact.lean index fdb99c4e8e14d..9a9a0708e76cc 100644 --- a/Mathlib/Topology/Compactness/LocallyCompact.lean +++ b/Mathlib/Topology/Compactness/LocallyCompact.lean @@ -149,6 +149,36 @@ instance Function.locallyCompactSpace [LocallyCompactSpace Y] [CompactSpace Y] : end Pi +/-- We say that `X` and `Y` are a locally compact pair of topological spaces, +if for any continuous map `f : X → Y`, a point `x : X`, and a neighbourhood `s ∈ 𝓝 (f x)`, +there exists a compact neighbourhood `K ∈ 𝓝 x` such that `f` maps `K` to `s`. + +This is a technical assumption that appears in several theorems, +most notably in `ContinuousMap.continuous_comp'` and `ContinuousMap.continuous_eval`. +It is satisfied in two cases: + +- if `X` is a locally compact topological space, for obvious reasons; +- if `X` is a weakly locally compact topological space and `Y` is a Hausdorff space; + this fact is a simple generalization of the theorem + saying that a weakly locally compact Hausdorff topological space is locally compact. +-/ +class LocallyCompactPair (X Y : Type*) [TopologicalSpace X] [TopologicalSpace Y] : Prop where + /-- If `f : X → Y` is a continuous map in a locally compact pair of topological spaces + and `s : Set Y` is a neighbourhood of `f x`, `x : X`, + then there exists a compact neighbourhood `K` of `x` such that `f` maps `K` to `s`. -/ + exists_mem_nhds_isCompact_mapsTo : ∀ {f : X → Y} {x : X} {s : Set Y}, + Continuous f → s ∈ 𝓝 (f x) → ∃ K ∈ 𝓝 x, IsCompact K ∧ MapsTo f K s + +export LocallyCompactPair (exists_mem_nhds_isCompact_mapsTo) + +instance (priority := 900) [LocallyCompactSpace X] : LocallyCompactPair X Y where + exists_mem_nhds_isCompact_mapsTo hf hs := + let ⟨K, hKx, hKs, hKc⟩ := local_compact_nhds (hf.continuousAt hs); ⟨K, hKx, hKc, hKs⟩ + +instance (priority := 100) [LocallyCompactSpace X] : WeaklyLocallyCompactSpace X where + exists_compact_mem_nhds (x : X) := + let ⟨K, hx, _, hKc⟩ := local_compact_nhds (x := x) univ_mem; ⟨K, hKc, hx⟩ + /-- A reformulation of the definition of locally compact space: In a locally compact space, every open set containing `x` has a compact subset containing `x` in its interior. -/ theorem exists_compact_subset [LocallyCompactSpace X] {x : X} {U : Set X} (hU : IsOpen U) @@ -157,25 +187,29 @@ theorem exists_compact_subset [LocallyCompactSpace X] {x : X} {U : Set X} (hU : exact ⟨K, h3K, mem_interior_iff_mem_nhds.2 h1K, h2K⟩ #align exists_compact_subset exists_compact_subset -instance (priority := 100) [LocallyCompactSpace X] : WeaklyLocallyCompactSpace X where - exists_compact_mem_nhds (x : X) := - let ⟨K, hKc, hx, _⟩ := exists_compact_subset isOpen_univ (mem_univ x) - ⟨K, hKc, mem_interior_iff_mem_nhds.1 hx⟩ +/-- If `f : X → Y` is a continuous map in a locally compact pair of topological spaces, +`K : set X` is a compact set, and `U` is an open neighbourhood of `f '' K`, +then there exists a compact neighbourhood `L` of `K` such that `f` maps `L` to `U`. + +This is a generalization of `exists_mem_nhds_isCompact_mapsTo`. -/ +lemma exists_mem_nhdsSet_isCompact_mapsTo [LocallyCompactPair X Y] {f : X → Y} {K : Set X} + {U : Set Y} (hf : Continuous f) (hK : IsCompact K) (hU : IsOpen U) (hKU : MapsTo f K U) : + ∃ L ∈ 𝓝ˢ K, IsCompact L ∧ MapsTo f L U := by + choose! V hxV hVc hVU using fun x (hx : x ∈ K) ↦ + exists_mem_nhds_isCompact_mapsTo hf (hU.mem_nhds (hKU hx)) + rcases hK.elim_nhds_subcover_nhdsSet hxV with ⟨s, hsK, hKs⟩ + exact ⟨_, hKs, s.isCompact_biUnion fun x hx ↦ hVc x (hsK x hx), mapsTo_iUnion₂ fun x hx ↦ + hVU x (hsK x hx)⟩ /-- In a locally compact space, for every containment `K ⊆ U` of a compact set `K` in an open set `U`, there is a compact neighborhood `L` such that `K ⊆ L ⊆ U`: equivalently, there is a compact `L` such that `K ⊆ interior L` and `L ⊆ U`. See also `exists_compact_closed_between`, in which one guarantees additionally that `L` is closed if the space is regular. -/ -theorem exists_compact_between [hX : LocallyCompactSpace X] {K U : Set X} (hK : IsCompact K) - (hU : IsOpen U) (h_KU : K ⊆ U) : ∃ L, IsCompact L ∧ K ⊆ interior L ∧ L ⊆ U := by - choose V hVc hxV hKV using fun x : K => exists_compact_subset hU (h_KU x.2) - have : K ⊆ ⋃ x, interior (V x) := fun x hx => mem_iUnion.2 ⟨⟨x, hx⟩, hxV _⟩ - rcases hK.elim_finite_subcover _ (fun x => @isOpen_interior X _ (V x)) this with ⟨t, ht⟩ - refine' - ⟨_, t.isCompact_biUnion fun x _ => hVc x, fun x hx => _, Set.iUnion₂_subset fun i _ => hKV i⟩ - rcases mem_iUnion₂.1 (ht hx) with ⟨y, hyt, hy⟩ - exact interior_mono (subset_iUnion₂ y hyt) hy +theorem exists_compact_between [LocallyCompactSpace X] {K U : Set X} (hK : IsCompact K) + (hU : IsOpen U) (h_KU : K ⊆ U) : ∃ L, IsCompact L ∧ K ⊆ interior L ∧ L ⊆ U := + let ⟨L, hKL, hL, hLU⟩ := exists_mem_nhdsSet_isCompact_mapsTo continuous_id hK hU h_KU + ⟨L, hL, subset_interior_iff_mem_nhdsSet.2 hKL, hLU⟩ #align exists_compact_between exists_compact_between protected theorem ClosedEmbedding.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} diff --git a/Mathlib/Topology/Connected/PathConnected.lean b/Mathlib/Topology/Connected/PathConnected.lean index 0385c423b6f71..5f6a426f7a65e 100644 --- a/Mathlib/Topology/Connected/PathConnected.lean +++ b/Mathlib/Topology/Connected/PathConnected.lean @@ -215,7 +215,7 @@ instance topologicalSpace : TopologicalSpace (Path x y) := TopologicalSpace.induced ((↑) : _ → C(I, X)) ContinuousMap.compactOpen theorem continuous_eval : Continuous fun p : Path x y × I => p.1 p.2 := - continuous_eval'.comp <| (continuous_induced_dom (α := Path x y)).prod_map continuous_id + continuous_eval.comp <| (continuous_induced_dom (α := Path x y)).prod_map continuous_id #align path.continuous_eval Path.continuous_eval @[continuity] diff --git a/Mathlib/Topology/ContinuousFunction/Algebra.lean b/Mathlib/Topology/ContinuousFunction/Algebra.lean index 7016e0cf2cff1..091f3f3efc1bd 100644 --- a/Mathlib/Topology/ContinuousFunction/Algebra.lean +++ b/Mathlib/Topology/ContinuousFunction/Algebra.lean @@ -336,9 +336,9 @@ instance [LocallyCompactSpace α] [Mul β] [ContinuousMul β] : ContinuousMul C( ⟨by refine' continuous_of_continuous_uncurry _ _ have h1 : Continuous fun x : (C(α, β) × C(α, β)) × α => x.fst.fst x.snd := - continuous_eval'.comp (continuous_fst.prod_map continuous_id) + continuous_eval.comp (continuous_fst.prod_map continuous_id) have h2 : Continuous fun x : (C(α, β) × C(α, β)) × α => x.fst.snd x.snd := - continuous_eval'.comp (continuous_snd.prod_map continuous_id) + continuous_eval.comp (continuous_snd.prod_map continuous_id) exact h1.mul h2⟩ /-- Coercion to a function as a `MonoidHom`. Similar to `MonoidHom.coeFn`. -/ @@ -603,7 +603,7 @@ instance instSMul [SMul R M] [ContinuousConstSMul R M] : SMul R C(α, M) := @[to_additive] instance [LocallyCompactSpace α] [SMul R M] [ContinuousConstSMul R M] : ContinuousConstSMul R C(α, M) := - ⟨fun γ => continuous_of_continuous_uncurry _ (continuous_eval'.const_smul γ)⟩ + ⟨fun γ => continuous_of_continuous_uncurry _ (continuous_eval.const_smul γ)⟩ @[to_additive] instance [LocallyCompactSpace α] [TopologicalSpace R] [SMul R M] [ContinuousSMul R M] : @@ -611,7 +611,7 @@ instance [LocallyCompactSpace α] [TopologicalSpace R] [SMul R M] [ContinuousSMu ⟨by refine' continuous_of_continuous_uncurry _ _ have h : Continuous fun x : (R × C(α, M)) × α => x.fst.snd x.snd := - continuous_eval'.comp (continuous_snd.prod_map continuous_id) + continuous_eval.comp (continuous_snd.prod_map continuous_id) exact (continuous_fst.comp continuous_fst).smul h⟩ @[to_additive (attr := simp, norm_cast)] diff --git a/Mathlib/Topology/ContinuousFunction/Compact.lean b/Mathlib/Topology/ContinuousFunction/Compact.lean index c752c972667ce..8a3aaa324933b 100644 --- a/Mathlib/Topology/ContinuousFunction/Compact.lean +++ b/Mathlib/Topology/ContinuousFunction/Compact.lean @@ -159,12 +159,6 @@ end instance [CompleteSpace β] : CompleteSpace C(α, β) := (isometryEquivBoundedOfCompact α β).completeSpace -/-- See also `ContinuousMap.continuous_eval'`. -/ -@[continuity] -theorem continuous_eval : Continuous fun p : C(α, β) × α => p.1 p.2 := - continuous_eval.comp ((isometryEquivBoundedOfCompact α β).continuous.prod_map continuous_id) -#align continuous_map.continuous_eval ContinuousMap.continuous_eval - -- TODO at some point we will need lemmas characterising this norm! -- At the moment the only way to reason about it is to transfer `f : C(α,E)` back to `α →ᵇ E`. instance : Norm C(α, E) where norm x := dist x 0 diff --git a/Mathlib/Topology/Homotopy/HomotopyGroup.lean b/Mathlib/Topology/Homotopy/HomotopyGroup.lean index 978727379c757..95031d6846a99 100644 --- a/Mathlib/Topology/Homotopy/HomotopyGroup.lean +++ b/Mathlib/Topology/Homotopy/HomotopyGroup.lean @@ -214,7 +214,7 @@ def toLoop (i : N) (p : Ω^ N X x) : Ω (Ω^ { j // j ≠ i } X x) const theorem continuous_toLoop (i : N) : Continuous (@toLoop N X _ x _ i) := Path.continuous_uncurry_iff.1 <| Continuous.subtype_mk - (ContinuousMap.continuous_eval'.comp <| + (ContinuousMap.continuous_eval.comp <| Continuous.prod_map (ContinuousMap.continuous_curry.comp <| (ContinuousMap.continuous_comp_left _).comp continuous_subtype_val) diff --git a/Mathlib/Topology/Separation.lean b/Mathlib/Topology/Separation.lean index 792e8fd7b27b4..66319310d70d6 100644 --- a/Mathlib/Topology/Separation.lean +++ b/Mathlib/Topology/Separation.lean @@ -1477,23 +1477,28 @@ theorem IsCompact.finite_compact_cover [T2Space X] {s : Set X} (hs : IsCompact s end +instance (priority := 900) [WeaklyLocallyCompactSpace X] [T2Space Y] : LocallyCompactPair X Y where + exists_mem_nhds_isCompact_mapsTo := by + intro f x s hf hs + rcases exists_compact_mem_nhds x with ⟨K, hKc, hKx⟩ + have hc : IsCompact (f '' K \ interior s) := (hKc.image hf).diff isOpen_interior + have hd : Disjoint {f x} (f '' K \ interior s) := disjoint_singleton_left.2 fun h ↦ + h.2 <| mem_interior_iff_mem_nhds.2 hs + rcases isCompact_isCompact_separated isCompact_singleton hc hd + with ⟨U, V, Uo, Vo, hxU, hV, hd⟩ + refine ⟨K \ f ⁻¹' V, diff_mem hKx ?_, hKc.diff <| Vo.preimage hf, fun y hy ↦ ?_⟩ + · filter_upwards [hf.continuousAt <| Uo.mem_nhds (hxU rfl)] with x hx + using Set.disjoint_left.1 hd hx + · by_contra hys + exact hy.2 (hV ⟨mem_image_of_mem _ hy.1, not_mem_subset interior_subset hys⟩) + -- see Note [lower instance priority] /-- A weakly locally compact Hausdorff space is locally compact. -/ instance WeaklyLocallyCompactSpace.locallyCompactSpace [WeaklyLocallyCompactSpace X] [T2Space X] : LocallyCompactSpace X := - ⟨fun x _n hn => - let ⟨_u, un, uo, xu⟩ := mem_nhds_iff.mp hn - let ⟨k, kc, kx⟩ := exists_compact_mem_nhds x - -- K is compact but not necessarily contained in N. - -- K \ U is again compact and doesn't contain x, so - -- we may find open sets V, W separating x from K \ U. - -- Then K \ W is a compact neighborhood of x contained in U. - let ⟨v, w, vo, wo, xv, kuw, vw⟩ := - isCompact_isCompact_separated isCompact_singleton (kc.diff uo) - (disjoint_singleton_left.2 fun h => h.2 xu) - have wn : wᶜ ∈ 𝓝 x := - mem_nhds_iff.mpr ⟨v, vw.subset_compl_right, vo, singleton_subset_iff.mp xv⟩ - ⟨k \ w, Filter.inter_mem kx wn, Subset.trans (diff_subset_comm.mp kuw) un, kc.diff wo⟩⟩ + ⟨fun _ _ h => + let ⟨K, hKx, hKc, hKs⟩ := exists_mem_nhds_isCompact_mapsTo continuous_id h + ⟨K, hKx, hKs, hKc⟩⟩ #align locally_compact_of_compact_nhds WeaklyLocallyCompactSpace.locallyCompactSpace @[deprecated WeaklyLocallyCompactSpace.locallyCompactSpace] From cb221686c8d8b56a19cef310d1c1038cc7e046a7 Mon Sep 17 00:00:00 2001 From: Alex Kassil Date: Tue, 26 Dec 2023 07:50:42 +0000 Subject: [PATCH 192/353] doc(Algebra/Order/Group/Defs): fix typo `monoid` -> `group` for `LinearOrderedAddCommGroupWithTop` (#9266) --- Mathlib/Algebra/Order/Group/Defs.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Algebra/Order/Group/Defs.lean b/Mathlib/Algebra/Order/Group/Defs.lean index 50d8582b69997..573400b9a22ec 100644 --- a/Mathlib/Algebra/Order/Group/Defs.lean +++ b/Mathlib/Algebra/Order/Group/Defs.lean @@ -1097,7 +1097,7 @@ addition is monotone. -/ class LinearOrderedAddCommGroup (α : Type u) extends OrderedAddCommGroup α, LinearOrder α #align linear_ordered_add_comm_group LinearOrderedAddCommGroup -/-- A linearly ordered commutative monoid with an additively absorbing `⊤` element. +/-- A linearly ordered commutative group with an additively absorbing `⊤` element. Instances should include number systems with an infinite element adjoined. -/ class LinearOrderedAddCommGroupWithTop (α : Type*) extends LinearOrderedAddCommMonoidWithTop α, SubNegMonoid α, Nontrivial α where From 9672388ba07a802f39f605cdf13057c2795d5951 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Dec 2023 07:50:43 +0000 Subject: [PATCH 193/353] chore(SpecialFunctions/Gamma): golf a proof (#9277) Use `induction .. generalizing` instead of `suffices`. --- .../Analysis/SpecialFunctions/Gamma/Beta.lean | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean index 82d5e3c41cabd..f8b6c25e9c37e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean @@ -532,26 +532,21 @@ theorem one_div_Gamma_eq_self_mul_one_div_Gamma_add_one (s : ℂ) : · rw [zero_add, Gamma_zero, inv_zero, zero_mul] #align complex.one_div_Gamma_eq_self_mul_one_div_Gamma_add_one Complex.one_div_Gamma_eq_self_mul_one_div_Gamma_add_one -/-- The reciprocal of the Gamma function is differentiable everywhere (including the points where -Gamma itself is not). -/ -theorem differentiable_one_div_Gamma : Differentiable ℂ fun s : ℂ => (Gamma s)⁻¹ := by - suffices : ∀ n : ℕ, ∀ (s : ℂ) (_ : -s.re < n), DifferentiableAt ℂ (fun u : ℂ => (Gamma u)⁻¹) s - exact fun s => - let ⟨n, h⟩ := exists_nat_gt (-s.re) - this n s h - intro n - induction' n with m hm - · intro s hs +/-- The reciprocal of the Gamma function is differentiable everywhere +(including the points where Gamma itself is not). -/ +theorem differentiable_one_div_Gamma : Differentiable ℂ fun s : ℂ => (Gamma s)⁻¹ := fun s ↦ by + rcases exists_nat_gt (-s.re) with ⟨n, hs⟩ + induction n generalizing s with + | zero => rw [Nat.cast_zero, neg_lt_zero] at hs suffices : ∀ m : ℕ, s ≠ -↑m; exact (differentiableAt_Gamma _ this).inv (Gamma_ne_zero this) - contrapose! hs - rcases hs with ⟨m, rfl⟩ - simpa only [neg_re, ← ofReal_nat_cast, ofReal_re, neg_nonpos] using Nat.cast_nonneg m - · intro s hs + rintro m rfl + apply hs.not_le + simp + | succ n ihn => rw [funext one_div_Gamma_eq_self_mul_one_div_Gamma_add_one] - specialize hm (s + 1) (by rwa [add_re, one_re, neg_add', sub_lt_iff_lt_add, ← Nat.cast_succ]) - refine' differentiableAt_id.mul (hm.comp s _) - exact differentiableAt_id.add (differentiableAt_const _) + specialize ihn (s + 1) (by rwa [add_re, one_re, neg_add', sub_lt_iff_lt_add, ← Nat.cast_succ]) + exact differentiableAt_id.mul (ihn.comp s <| differentiableAt_id.add_const _) #align complex.differentiable_one_div_Gamma Complex.differentiable_one_div_Gamma end Complex From 499d53818b170da7d91a3c0a7ec2073e66dc409f Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 26 Dec 2023 10:38:23 +0000 Subject: [PATCH 194/353] feat: define `QuadraticForm.IsOrtho` as `Q (x + y) = Q x + Q y` (#9141) This includes some basic API, and the connection with `BilinForm.IsOrtho`. The motivation for this definition are the results about vectors commuting in a clifford algebra. --- .../LinearAlgebra/CliffordAlgebra/Basic.lean | 27 ++++++++- .../LinearAlgebra/ExteriorAlgebra/Basic.lean | 4 +- .../LinearAlgebra/QuadraticForm/Basic.lean | 59 +++++++++++++++++++ .../QuadraticForm/IsometryEquiv.lean | 2 +- Mathlib/LinearAlgebra/QuadraticForm/Prod.lean | 23 ++++++++ 5 files changed, 108 insertions(+), 7 deletions(-) diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean index 79fd91e5fd90b..d789db8ce06e1 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean @@ -262,15 +262,36 @@ theorem ι_mul_ι_add_swap (a b : M) : mul_add_swap_eq_polar_of_forall_mul_self_eq _ (ι_sq_scalar _) _ _ #align clifford_algebra.ι_mul_ι_add_swap CliffordAlgebra.ι_mul_ι_add_swap -theorem ι_mul_comm (a b : M) : +theorem ι_mul_ι_comm (a b : M) : ι Q a * ι Q b = algebraMap R _ (QuadraticForm.polar Q a b) - ι Q b * ι Q a := eq_sub_of_add_eq (ι_mul_ι_add_swap a b) -#align clifford_algebra.ι_mul_comm CliffordAlgebra.ι_mul_comm +#align clifford_algebra.ι_mul_comm CliffordAlgebra.ι_mul_ι_comm + +section isOrtho + +@[simp] theorem ι_mul_ι_add_swap_of_isOrtho {a b : M} (h : Q.IsOrtho a b) : + ι Q a * ι Q b + ι Q b * ι Q a = 0 := by + rw [ι_mul_ι_add_swap, h.polar_eq_zero] + simp + +theorem ι_mul_ι_comm_of_isOrtho {a b : M} (h : Q.IsOrtho a b) : + ι Q a * ι Q b = -(ι Q b * ι Q a) := + eq_neg_of_add_eq_zero_left <| ι_mul_ι_add_swap_of_isOrtho h + +theorem mul_ι_mul_ι_of_isOrtho (x : CliffordAlgebra Q) {a b : M} (h : Q.IsOrtho a b) : + x * ι Q a * ι Q b = -(x * ι Q b * ι Q a) := by + rw [mul_assoc, ι_mul_ι_comm_of_isOrtho h, mul_neg, mul_assoc] + +theorem ι_mul_ι_mul_of_isOrtho (x : CliffordAlgebra Q) {a b : M} (h : Q.IsOrtho a b) : + ι Q a * (ι Q b * x) = -(ι Q b * (ι Q a * x)) := by + rw [← mul_assoc, ι_mul_ι_comm_of_isOrtho h, neg_mul, mul_assoc] + +end isOrtho /-- $aba$ is a vector. -/ theorem ι_mul_ι_mul_ι (a b : M) : ι Q a * ι Q b * ι Q a = ι Q (QuadraticForm.polar Q a b • a - Q a • b) := by - rw [ι_mul_comm, sub_mul, mul_assoc, ι_sq_scalar, ← Algebra.smul_def, ← Algebra.commutes, ← + rw [ι_mul_ι_comm, sub_mul, mul_assoc, ι_sq_scalar, ← Algebra.smul_def, ← Algebra.commutes, ← Algebra.smul_def, ← map_smul, ← map_smul, ← map_sub] #align clifford_algebra.ι_mul_ι_mul_ι CliffordAlgebra.ι_mul_ι_mul_ι diff --git a/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean b/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean index bb3c66403d649..8783494ac3016 100644 --- a/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean @@ -252,9 +252,7 @@ theorem ι_range_disjoint_one : @[simp] theorem ι_add_mul_swap (x y : M) : ι R x * ι R y + ι R y * ι R x = 0 := - calc - _ = ι R (y + x) * ι R (y + x) := by simp [mul_add, add_mul] - _ = _ := ι_sq_zero _ + CliffordAlgebra.ι_mul_ι_add_swap_of_isOrtho <| .all _ _ #align exterior_algebra.ι_add_mul_swap ExteriorAlgebra.ι_add_mul_swap theorem ι_mul_prod_list {n : ℕ} (f : Fin n → M) (i : Fin n) : diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean index b26969e9f24f4..2a21b5fa08c4e 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean @@ -37,6 +37,7 @@ and composition with linear maps `f`, `Q.comp f x = Q (f x)`. * `QuadraticForm.PosDef`: positive definite quadratic forms * `QuadraticForm.Anisotropic`: anisotropic quadratic forms * `QuadraticForm.discr`: discriminant of a quadratic form + * `QuadraticForm.IsOrtho`: orthogonality of vectors with respect to a quadratic form. ## Main statements @@ -933,6 +934,64 @@ lemma associated_sq : associated (R := R) sq = LinearMap.toBilin (LinearMap.mul end Associated +section IsOrtho + +/-! ### Orthogonality -/ + +section CommSemiring +variable [CommSemiring R] [AddCommMonoid M] [Module R M] {Q : QuadraticForm R M} + +/-- The proposition that two elements of a quadratic form space are orthogonal. -/ +def IsOrtho (Q : QuadraticForm R M) (x y : M) : Prop := + Q (x + y) = Q x + Q y + +theorem isOrtho_def {Q : QuadraticForm R M} {x y : M} : Q.IsOrtho x y ↔ Q (x + y) = Q x + Q y := + Iff.rfl + +theorem IsOrtho.all (x y : M) : IsOrtho (0 : QuadraticForm R M) x y := (zero_add _).symm + +theorem IsOrtho.zero_left (x : M) : IsOrtho Q (0 : M) x := by simp [isOrtho_def] + +theorem IsOrtho.zero_right (x : M) : IsOrtho Q x (0 : M) := by simp [isOrtho_def] + +theorem ne_zero_of_not_isOrtho_self {Q : QuadraticForm R M} (x : M) (hx₁ : ¬Q.IsOrtho x x) : + x ≠ 0 := + fun hx₂ => hx₁ (hx₂.symm ▸ .zero_left _) + +theorem isOrtho_comm {x y : M} : IsOrtho Q x y ↔ IsOrtho Q y x := by simp_rw [isOrtho_def, add_comm] + +alias ⟨IsOrtho.symm, _⟩ := isOrtho_comm + +theorem _root_.BilinForm.toQuadraticForm_isOrtho [IsCancelAdd R] + [NoZeroDivisors R] [CharZero R] {B : BilinForm R M} {x y : M} (h : B.IsSymm): + B.toQuadraticForm.IsOrtho x y ↔ B.IsOrtho x y := by + letI : AddCancelMonoid R := { ‹IsCancelAdd R›, (inferInstanceAs <| AddCommMonoid R) with } + simp_rw [isOrtho_def, BilinForm.isOrtho_def, toQuadraticForm_apply, bilin_add_left, + bilin_add_right, add_comm _ (B y y), add_add_add_comm _ _ (B y y), add_comm (B y y)] + rw [add_right_eq_self (a := B x x + B y y), h, add_self_eq_zero (R := R)] + +end CommSemiring + +section CommRing +variable [CommRing R] [AddCommGroup M] [Module R M] {Q : QuadraticForm R M} + +@[simp] +theorem isOrtho_polarBilin {x y : M} : Q.polarBilin.IsOrtho x y ↔ IsOrtho Q x y := by + simp_rw [isOrtho_def, BilinForm.isOrtho_def, polarBilin_apply, polar, sub_sub, sub_eq_zero] + +theorem IsOrtho.polar_eq_zero {x y : M} (h : IsOrtho Q x y) : polar Q x y = 0 := + isOrtho_polarBilin.mpr h + +@[simp] +theorem associated_isOrtho [Invertible (2 : R)] {x y : M} : + Q.associated.IsOrtho x y ↔ Q.IsOrtho x y := by + simp_rw [isOrtho_def, BilinForm.isOrtho_def, associated_apply, invOf_mul_eq_iff_eq_mul_left, + mul_zero, sub_sub, sub_eq_zero] + +end CommRing + +end IsOrtho + section Anisotropic section Semiring diff --git a/Mathlib/LinearAlgebra/QuadraticForm/IsometryEquiv.lean b/Mathlib/LinearAlgebra/QuadraticForm/IsometryEquiv.lean index c8a3a1419ee95..fe3b9fa18f455 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/IsometryEquiv.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/IsometryEquiv.lean @@ -174,7 +174,7 @@ theorem equivalent_weightedSumSquares_units_of_nondegenerate' (Q : QuadraticForm ∃ w : Fin (FiniteDimensional.finrank K V) → Kˣ, Equivalent Q (weightedSumSquares K w) := by obtain ⟨v, hv₁⟩ := exists_orthogonal_basis (associated_isSymm K Q) have hv₂ := hv₁.not_isOrtho_basis_self_of_nondegenerate hQ - simp_rw [IsOrtho, associated_eq_self_apply] at hv₂ + simp_rw [BilinForm.IsOrtho, associated_eq_self_apply] at hv₂ exact ⟨fun i => Units.mk0 _ (hv₂ i), ⟨Q.isometryEquivWeightedSumSquares v hv₁⟩⟩ #align quadratic_form.equivalent_weighted_sum_squares_units_of_nondegenerate' QuadraticForm.equivalent_weightedSumSquares_units_of_nondegenerate' diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean b/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean index 89a3f2f180042..474aaceb3d6ec 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean @@ -147,6 +147,29 @@ theorem PosDef.prod {R} [OrderedCommRing R] [Module R M₁] [Module R M₂] posDef_prod_iff.mpr ⟨h₁, h₂⟩ #align quadratic_form.pos_def.prod QuadraticForm.PosDef.prod +theorem IsOrtho.prod {Q₁ : QuadraticForm R M₁} {Q₂ : QuadraticForm R M₂} + {v w : M₁ × M₂} (h₁ : Q₁.IsOrtho v.1 w.1) (h₂ : Q₂.IsOrtho v.2 w.2) : + (Q₁.prod Q₂).IsOrtho v w := + (congr_arg₂ HAdd.hAdd h₁ h₂).trans <| add_add_add_comm _ _ _ _ + +@[simp] theorem IsOrtho.inl_inr {Q₁ : QuadraticForm R M₁} {Q₂ : QuadraticForm R M₂} + (m₁ : M₁) (m₂ : M₂) : + (Q₁.prod Q₂).IsOrtho (m₁, 0) (0, m₂) := .prod (.zero_right _) (.zero_left _) + +@[simp] theorem IsOrtho.inr_inl {Q₁ : QuadraticForm R M₁} {Q₂ : QuadraticForm R M₂} + (m₁ : M₁) (m₂ : M₂) : + (Q₁.prod Q₂).IsOrtho (0, m₂) (m₁, 0) := (IsOrtho.inl_inr _ _).symm + +@[simp] theorem isOrtho_inl_inl_iff {Q₁ : QuadraticForm R M₁} {Q₂ : QuadraticForm R M₂} + (m₁ m₁' : M₁) : + (Q₁.prod Q₂).IsOrtho (m₁, 0) (m₁', 0) ↔ Q₁.IsOrtho m₁ m₁' := by + simp [isOrtho_def] + +@[simp] theorem isOrtho_inr_inr_iff {Q₁ : QuadraticForm R M₁} {Q₂ : QuadraticForm R M₂} + (m₂ m₂' : M₂) : + (Q₁.prod Q₂).IsOrtho (0, m₂) (0, m₂') ↔ Q₂.IsOrtho m₂ m₂' := by + simp [isOrtho_def] + end Semiring section Ring From 37eaeb06daeb349f898dfebd4add36ebfaf8e2be Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 26 Dec 2023 11:03:25 +0000 Subject: [PATCH 195/353] feat(Algebra/Ring/CentroidHom): CentroidHom and algebras (#8699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explore the relationship between the Centroid of a ring and algebra: - A a non-unital, non-associative semiring α is an algebra over the Semiring CentroidHom α - When the non-unital, non-associative semiring α is an algebra over the commutative semiring R, then CentroidHom α is a ring over R, provided the range of the natural ring homomorphism from R into CentroidHom α lies in the center of CentroidHom α. Co-authored-by: Christopher Hoskin Co-authored-by: Eric Wieser --- Mathlib/Algebra/Ring/CentroidHom.lean | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Mathlib/Algebra/Ring/CentroidHom.lean b/Mathlib/Algebra/Ring/CentroidHom.lean index 8b8d7d42272b1..ac7410b2864d0 100644 --- a/Mathlib/Algebra/Ring/CentroidHom.lean +++ b/Mathlib/Algebra/Ring/CentroidHom.lean @@ -3,6 +3,7 @@ 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, Christopher Hoskin -/ +import Mathlib.Algebra.Algebra.Basic import Mathlib.Algebra.Module.Hom import Mathlib.RingTheory.NonUnitalSubsemiring.Basic import Mathlib.RingTheory.Subsemiring.Basic @@ -432,6 +433,55 @@ instance : DistribMulAction M (CentroidHom α) := instance : Module R (CentroidHom α) := toEnd_injective.module R (toEndRingHom α).toAddMonoidHom toEnd_smul +/-! +The following instances show that `α` is a non-unital and non-associative algebra over +`CentroidHom α`. +-/ + +/-- The tautological action by `CentroidHom α` on `α`. + +This generalizes `Function.End.applyMulAction`. -/ +instance applyModule : Module (CentroidHom α) α where + smul T a := T a + add_smul _ _ _ := rfl + zero_smul _ := rfl + one_smul _ := rfl + mul_smul _ _ _:= rfl + smul_zero := map_zero + smul_add := map_add + +@[simp] +lemma smul_def (T : CentroidHom α) (a : α) : T • a = T a := rfl + +instance : SMulCommClass (CentroidHom α) α α where + smul_comm _ _ _ := map_mul_left _ _ _ + +instance : SMulCommClass α (CentroidHom α) α := SMulCommClass.symm _ _ _ + +instance : IsScalarTower (CentroidHom α) α α where + smul_assoc _ _ _ := (map_mul_right _ _ _).symm + +/-! +Let `α` be an algebra over `R`, such that the canonical ring homomorphism of `R` into +`CentroidHom α` lies in the center of `CentroidHom α`. Then `CentroidHom α` is an algebra over `R` +-/ + +variable {R : Type*} + +variable [CommSemiring R] +variable [Module R α] [SMulCommClass R α α] [IsScalarTower R α α] + +/-- The natural ring homomorphism from `R` into `CentroidHom α`. + +This is a stronger version of `Module.toAddMonoidEnd`. -/ +@[simps! apply_toFun] +def _root_.Module.toCentroidHom : R →+* CentroidHom α := RingHom.smulOneHom + +open Module in +/-- `CentroidHom α` as an algebra over `R`. -/ +example (h : ∀ (r : R) (T : CentroidHom α), toCentroidHom r * T = T * toCentroidHom r) : + Algebra R (CentroidHom α) := toCentroidHom.toAlgebra' h + local notation "L" => AddMonoid.End.mulLeft local notation "R" => AddMonoid.End.mulRight From 10597c9e3b0fd523e9e276a2f693d1fb0bd19619 Mon Sep 17 00:00:00 2001 From: Thomas Zhu Date: Tue, 26 Dec 2023 11:03:26 +0000 Subject: [PATCH 196/353] feat: Lemmas about `ZMod` (#9143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added some lemmas about `ZMod` and its units: * Generalized `lt` to `le` in two lemmas * `((a : ZMod n) : ZMod m) = a` if `m ≤ n` * `unitsMap` is surjective * `Units.map f (-a) = -Units.map f a` (which can be applied to `unitsMap`) * `Units.map (-1) = -1` (which can be applied to `unitsMap`) --- Mathlib/Algebra/Ring/Units.lean | 12 +++++++++++- Mathlib/Data/ZMod/Basic.lean | 13 +++++++++---- Mathlib/Data/ZMod/Units.lean | 29 +++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/Mathlib/Algebra/Ring/Units.lean b/Mathlib/Algebra/Ring/Units.lean index c1e778d912710..aa1a1f9e6e8b9 100644 --- a/Mathlib/Algebra/Ring/Units.lean +++ b/Mathlib/Algebra/Ring/Units.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Yury Kudryashov, Neil Strickland -/ import Mathlib.Algebra.Ring.InjSurj -import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.Group.Units.Hom +import Mathlib.Algebra.Ring.Hom.Defs #align_import algebra.ring.units from "leanprover-community/mathlib"@"2ed7e4aec72395b6a7c3ac4ac7873a7a43ead17c" @@ -88,6 +89,15 @@ theorem divp_sub (a b : α) (u : αˣ) : a /ₚ u - b = (a - b * u) /ₚ u := by rw [mul_assoc, Units.mul_inv, mul_one] #align units.divp_sub Units.divp_sub +@[simp] +protected theorem map_neg {F : Type*} [Ring β] [RingHomClass F α β] (f : F) (u : αˣ) : + map (f : α →* β) (-u) = -map (f : α →* β) u := + ext (by simp only [coe_map, Units.val_neg, MonoidHom.coe_coe, map_neg]) + +protected theorem map_neg_one {F : Type*} [Ring β] [RingHomClass F α β] (f : F) : + map (f : α →* β) (-1) = -1 := + by simp only [Units.map_neg, map_one] + end Ring end Units diff --git a/Mathlib/Data/ZMod/Basic.lean b/Mathlib/Data/ZMod/Basic.lean index c0f99cf4d0983..4569ab747172a 100644 --- a/Mathlib/Data/ZMod/Basic.lean +++ b/Mathlib/Data/ZMod/Basic.lean @@ -569,21 +569,21 @@ theorem ker_int_castRingHom (n : ℕ) : rw [Ideal.mem_span_singleton, RingHom.mem_ker, Int.coe_castRingHom, int_cast_zmod_eq_zero_iff_dvd] #align zmod.ker_int_cast_ring_hom ZMod.ker_int_castRingHom -theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) : +theorem cast_injective_of_le {m n : ℕ} [nzm : NeZero m] (h : m ≤ n) : Function.Injective (@cast (ZMod n) _ m) := by cases m with | zero => cases nzm; simp_all | succ m => rintro ⟨x, hx⟩ ⟨y, hy⟩ f simp only [cast, val, nat_cast_eq_nat_cast_iff', - Nat.mod_eq_of_lt (lt_trans hx h), Nat.mod_eq_of_lt (lt_trans hy h)] at f + Nat.mod_eq_of_lt (hx.trans_le h), Nat.mod_eq_of_lt (hy.trans_le h)] at f apply Fin.ext exact f -theorem cast_zmod_eq_zero_iff_of_lt {m n : ℕ} [NeZero m] (h : m < n) (a : ZMod m) : +theorem cast_zmod_eq_zero_iff_of_le {m n : ℕ} [NeZero m] (h : m ≤ n) (a : ZMod m) : (a : ZMod n) = 0 ↔ a = 0 := by rw [← ZMod.cast_zero (n := m)] - exact Injective.eq_iff' (cast_injective_of_lt h) rfl + exact Injective.eq_iff' (cast_injective_of_le h) rfl --Porting note: commented -- attribute [local semireducible] Int.NonNeg @@ -947,6 +947,11 @@ theorem val_cast_eq_val_of_lt {m n : ℕ} [nzm : NeZero m] {a : ZMod m} | zero => cases nzn; simp_all | succ n => exact Fin.val_cast_of_lt h +theorem cast_cast_zmod_of_le {m n : ℕ} [hm : NeZero m] (h : m ≤ n) (a : ZMod m) : + ((a : ZMod n) : ZMod m) = a := by + have : NeZero n := ⟨((Nat.zero_lt_of_ne_zero hm.out).trans_le h).ne'⟩ + rw [cast_eq_val, val_cast_eq_val_of_lt (a.val_lt.trans_le h), nat_cast_zmod_val] + /-- `valMinAbs x` returns the integer in the same equivalence class as `x` that is closest to `0`, The result will be in the interval `(-n/2, n/2]`. -/ def valMinAbs : ∀ {n : ℕ}, ZMod n → ℤ diff --git a/Mathlib/Data/ZMod/Units.lean b/Mathlib/Data/ZMod/Units.lean index be63e460b092f..b595a21592145 100644 --- a/Mathlib/Data/ZMod/Units.lean +++ b/Mathlib/Data/ZMod/Units.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Moritz Firsching, Ashvni Narayanan, Michael Stoll -/ import Mathlib.Data.ZMod.Basic +import Mathlib.Data.Nat.PrimeFin +import Mathlib.Algebra.BigOperators.Associated /-! @@ -33,4 +35,31 @@ lemma unitsMap_self (n : ℕ) : unitsMap (dvd_refl n) = MonoidHom.id _ := by lemma IsUnit_cast_of_dvd (hm : n ∣ m) (a : Units (ZMod m)) : IsUnit ((a : ZMod m) : ZMod n) := Units.isUnit (unitsMap hm a) +theorem unitsMap_surjective [hm : NeZero m] (h : n ∣ m) : + Function.Surjective (unitsMap h) := by + suffices ∀ x : ℕ, x.Coprime n → ∃ k : ℕ, (x + k * n).Coprime m by + intro x + have ⟨k, hk⟩ := this x.val.val (val_coe_unit_coprime x) + refine ⟨unitOfCoprime _ hk, Units.ext ?_⟩ + have : NeZero n := ⟨fun hn ↦ hm.out (eq_zero_of_zero_dvd (hn ▸ h))⟩ + simp [unitsMap_def] + intro x hx + let ps := m.primeFactors.filter (fun p ↦ ¬p ∣ x) + use ps.prod id + apply Nat.coprime_of_dvd + intro p pp hp hpn + by_cases hpx : p ∣ x + · have h := Nat.dvd_sub' hp hpx + rw [add_comm, Nat.add_sub_cancel] at h + rcases pp.dvd_mul.mp h with h | h + · have ⟨q, hq, hq'⟩ := (pp.prime.dvd_finset_prod_iff id).mp h + rw [Finset.mem_filter, Nat.mem_primeFactors, + ← (Nat.prime_dvd_prime_iff_eq pp hq.1.1).mp hq'] at hq + exact hq.2 hpx + · exact Nat.Prime.not_coprime_iff_dvd.mpr ⟨p, pp, hpx, h⟩ hx + · have pps : p ∈ ps := Finset.mem_filter.mpr ⟨Nat.mem_primeFactors.mpr ⟨pp, hpn, hm.out⟩, hpx⟩ + have h := Nat.dvd_sub' hp ((Finset.dvd_prod_of_mem id pps).mul_right n) + rw [Nat.add_sub_cancel] at h + contradiction + end ZMod From 40d7ce18c4ab0f4427db2ca13c8c175781a09a5b Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Dec 2023 11:03:27 +0000 Subject: [PATCH 197/353] feat(Set/NAry): add `Set.image2_range` (#9220) Generalize `Set.range_smul_range` to any `Set.image2`. --- Mathlib/Data/Set/NAry.lean | 4 ++++ Mathlib/Data/Set/Pointwise/SMul.lean | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mathlib/Data/Set/NAry.lean b/Mathlib/Data/Set/NAry.lean index c149dfbacb515..033d089ee0410 100644 --- a/Mathlib/Data/Set/NAry.lean +++ b/Mathlib/Data/Set/NAry.lean @@ -248,6 +248,10 @@ theorem image2_right (h : s.Nonempty) : image2 (fun _ y => y) s t = t := by simp [nonempty_def.mp h, ext_iff] #align set.image2_right Set.image2_right +lemma image2_range (f : α' → β' → γ) (g : α → α') (h : β → β') : + image2 f (range g) (range h) = range fun x : α × β ↦ f (g x.1) (h x.2) := by + simp_rw [← image_univ, image2_image_left, image2_image_right, ← image_prod, univ_prod_univ] + theorem image2_assoc {f : δ → γ → ε} {g : α → β → δ} {f' : α → ε' → ε} {g' : β → γ → ε'} (h_assoc : ∀ a b c, f (g a b) c = f' a (g' b c)) : image2 f (image2 g s t) u = image2 f' s (image2 g' t u) := by diff --git a/Mathlib/Data/Set/Pointwise/SMul.lean b/Mathlib/Data/Set/Pointwise/SMul.lean index 3ccec146eb2ab..a8ca3f1fc3045 100644 --- a/Mathlib/Data/Set/Pointwise/SMul.lean +++ b/Mathlib/Data/Set/Pointwise/SMul.lean @@ -445,11 +445,7 @@ variable {s s₁ s₂ : Set α} {t t₁ t₂ : Set β} {a : α} {b : β} @[to_additive] theorem range_smul_range {ι κ : Type*} [SMul α β] (b : ι → α) (c : κ → β) : range b • range c = range fun p : ι × κ ↦ b p.1 • c p.2 := - ext fun _x ↦ - ⟨fun hx ↦ - let ⟨_p, _q, ⟨i, hi⟩, ⟨j, hj⟩, hpq⟩ := Set.mem_smul.1 hx - ⟨(i, j), hpq ▸ hi ▸ hj ▸ rfl⟩, - fun ⟨⟨i, j⟩, h⟩ ↦ Set.mem_smul.2 ⟨b i, c j, ⟨i, rfl⟩, ⟨j, rfl⟩, h⟩⟩ + image2_range .. #align set.range_smul_range Set.range_smul_range #align set.range_vadd_range Set.range_vadd_range From 9d8e41e6d887501a289ae7a84ce954b642f7dffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Tue, 26 Dec 2023 12:09:03 +0000 Subject: [PATCH 198/353] feat(CategoryTheory/Triangulated): Functor.mapTriangle commutes with the shift (#9073) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If `F : C ⥤ D` is an additive functor which commutes with a shift by `ℤ`, then `F.mapTriangle : Triangle C ⥤ Triangle D` also commutes with the shift. --- Mathlib/CategoryTheory/Shift/CommShift.lean | 25 +++++++++++++++- .../CategoryTheory/Triangulated/Functor.lean | 30 ++++++++++++++++++- .../Triangulated/TriangleShift.lean | 27 +++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/Mathlib/CategoryTheory/Shift/CommShift.lean b/Mathlib/CategoryTheory/Shift/CommShift.lean index 57e14d367929f..565d69a61be59 100644 --- a/Mathlib/CategoryTheory/Shift/CommShift.lean +++ b/Mathlib/CategoryTheory/Shift/CommShift.lean @@ -33,8 +33,9 @@ open Category namespace Functor variable {C D E : Type*} [Category C] [Category D] [Category E] - (F : C ⥤ D) (G : D ⥤ E) (A : Type*) [AddMonoid A] + (F : C ⥤ D) (G : D ⥤ E) (A B : Type*) [AddMonoid A] [AddCommMonoid B] [HasShift C A] [HasShift D A] [HasShift E A] + [HasShift C B] [HasShift D B] namespace CommShift @@ -153,6 +154,28 @@ instance id : CommShift (𝟭 C) A where end CommShift +variable {B} + +lemma map_shiftFunctorComm_hom_app (F : C ⥤ D) [F.CommShift B] (X : C) (a b : B) : + F.map ((shiftFunctorComm C a b).hom.app X) = (F.commShiftIso b).hom.app (X⟦a⟧) ≫ + ((F.commShiftIso a).hom.app X)⟦b⟧' ≫ (shiftFunctorComm D a b).hom.app (F.obj X) ≫ + ((F.commShiftIso b).inv.app X)⟦a⟧' ≫ (F.commShiftIso a).inv.app (X⟦b⟧) := by + have eq := NatTrans.congr_app (congr_arg Iso.hom (F.commShiftIso_add a b)) X + simp only [comp_obj, CommShift.isoAdd_hom_app, + ← cancel_epi (F.map ((shiftFunctorAdd C a b).inv.app X)), Category.assoc, + ← F.map_comp_assoc, Iso.inv_hom_id_app, F.map_id, Category.id_comp, F.map_comp] at eq + simp only [shiftFunctorComm_eq D a b _ rfl] + dsimp + simp only [Functor.map_comp, shiftFunctorAdd'_eq_shiftFunctorAdd, Category.assoc, + ← reassoc_of% eq, shiftFunctorComm_eq C a b _ rfl] + dsimp + rw [Functor.map_comp] + simp only [NatTrans.congr_app (congr_arg Iso.hom (F.commShiftIso_add' (add_comm b a))) X, + CommShift.isoAdd'_hom_app, Category.assoc, Iso.inv_hom_id_app_assoc, + ← Functor.map_comp_assoc, Iso.hom_inv_id_app, + Functor.map_id, Category.id_comp, comp_obj, Category.comp_id] + + end Functor end CategoryTheory diff --git a/Mathlib/CategoryTheory/Triangulated/Functor.lean b/Mathlib/CategoryTheory/Triangulated/Functor.lean index 4d0f691369ac9..12a2acd7deef1 100644 --- a/Mathlib/CategoryTheory/Triangulated/Functor.lean +++ b/Mathlib/CategoryTheory/Triangulated/Functor.lean @@ -20,7 +20,7 @@ distinguished triangles: this defines the typeclass `Functor.IsTriangulated`. namespace CategoryTheory -open Category Limits Pretriangulated +open Category Limits Pretriangulated Preadditive namespace Functor @@ -65,6 +65,34 @@ instance [Full F] [Faithful F] : Full F.mapTriangle where simpa only [mapTriangle_obj, map_comp, assoc, commShiftIso_hom_naturality, image_preimage, Triangle.mk_mor₃] using f.comm₃) } +section Additive + +variable [Preadditive C] [Preadditive D] [F.Additive] + +/-- The functor `F.mapTriangle` commutes with the shift. -/ +@[simps!] +noncomputable def mapTriangleCommShiftIso (n : ℤ) : + Triangle.shiftFunctor C n ⋙ F.mapTriangle ≅ F.mapTriangle ⋙ Triangle.shiftFunctor D n := + NatIso.ofComponents (fun T => Triangle.isoMk _ _ + ((F.commShiftIso n).app _) ((F.commShiftIso n).app _) ((F.commShiftIso n).app _) + (by aesop_cat) (by aesop_cat) (by + dsimp + simp only [map_units_smul, map_comp, Linear.units_smul_comp, assoc, + Linear.comp_units_smul, ← F.commShiftIso_hom_naturality_assoc] + rw [F.map_shiftFunctorComm_hom_app T.obj₁ 1 n] + simp only [comp_obj, assoc, Iso.inv_hom_id_app_assoc, + ← Functor.map_comp, Iso.inv_hom_id_app, map_id, comp_id])) (by aesop_cat) + +attribute [local simp] commShiftIso_zero commShiftIso_add + shiftFunctorAdd'_eq_shiftFunctorAdd + +set_option maxHeartbeats 400000 in +noncomputable instance [∀ (n : ℤ), (shiftFunctor C n).Additive] + [∀ (n : ℤ), (shiftFunctor D n).Additive] : (F.mapTriangle).CommShift ℤ where + iso := F.mapTriangleCommShiftIso + +end Additive + variable [HasZeroObject C] [HasZeroObject D] [Preadditive C] [Preadditive D] [∀ (n : ℤ), (shiftFunctor C n).Additive] [∀ (n : ℤ), (shiftFunctor D n).Additive] [Pretriangulated C] [Pretriangulated D] diff --git a/Mathlib/CategoryTheory/Triangulated/TriangleShift.lean b/Mathlib/CategoryTheory/Triangulated/TriangleShift.lean index e01550af5e5b5..c622deb96d3eb 100644 --- a/Mathlib/CategoryTheory/Triangulated/TriangleShift.lean +++ b/Mathlib/CategoryTheory/Triangulated/TriangleShift.lean @@ -143,6 +143,8 @@ noncomputable def invRotateIsoRotateRotateShiftFunctorNegOne : isoWhiskerRight (triangleRotation C).counitIso _ _ ≅ _ := Functor.leftUnitor _ +namespace Triangle + noncomputable instance : HasShift (Triangle C) ℤ := hasShiftMk (Triangle C) ℤ { F := Triangle.shiftFunctor C @@ -156,6 +158,31 @@ noncomputable instance : HasShift (Triangle C) ℤ := dsimp only [CategoryTheory.shiftFunctorAdd'] simp } +@[simp] +lemma shiftFunctor_eq (n : ℤ) : + CategoryTheory.shiftFunctor (Triangle C) n = Triangle.shiftFunctor C n := rfl + +@[simp] +lemma shiftFunctorZero_eq : + CategoryTheory.shiftFunctorZero (Triangle C) ℤ = Triangle.shiftFunctorZero C := + ShiftMkCore.shiftFunctorZero_eq _ + +@[simp] +lemma shiftFunctorAdd_eq (a b : ℤ) : + CategoryTheory.shiftFunctorAdd (Triangle C) a b = + Triangle.shiftFunctorAdd' C a b _ rfl := + ShiftMkCore.shiftFunctorAdd_eq _ _ _ + +@[simp] +lemma shiftFunctorAdd'_eq (a b c : ℤ) (h : a + b = c) : + CategoryTheory.shiftFunctorAdd' (Triangle C) a b c h = + Triangle.shiftFunctorAdd' C a b c h := by + subst h + rw [shiftFunctorAdd'_eq_shiftFunctorAdd] + apply shiftFunctorAdd_eq + +end Triangle + end Pretriangulated end CategoryTheory From 9a4fb8ec99a5a7479ce6f3a5c76fa77bdf800951 Mon Sep 17 00:00:00 2001 From: Alex Meiburg Date: Tue, 26 Dec 2023 12:09:04 +0000 Subject: [PATCH 199/353] Adding Descartes' Rule of Signs to the 100 problems (#9086) Adding Descartes' Rule of Signs to the 100 problems Co-authored-by: Alex Meiburg --- docs/100.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/100.yaml b/docs/100.yaml index 6b782040b2647..a59949d8c4cdd 100644 --- a/docs/100.yaml +++ b/docs/100.yaml @@ -412,3 +412,6 @@ title : Buffon Needle Problem 100: title : Descartes Rule of Signs + links : + github : https://github.com/Timeroot/lean-descartes-signs/ + author : Alex Meiburg From 351b5cc4de50773693e2bd7b5bec183e6400f774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 12:09:05 +0000 Subject: [PATCH 200/353] feat: Positivity extensions for `Real.sinh`, `Real.cosh` (#9098) Also fix the name of `Real.Mathlib.Meta.Positivity.evalExp` to `Mathlib.Meta.Positivity.evalRealPi`. --- .../SpecialFunctions/Trigonometric/Basic.lean | 21 ++++++----- .../SpecialFunctions/Trigonometric/Deriv.lean | 35 +++++++++++++++++++ Mathlib/Data/Complex/Exponential.lean | 13 +++++++ 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean index 7b81a2bc54f53..c5a7067b57b25 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean @@ -164,17 +164,6 @@ theorem pi_pos : 0 < π := lt_of_lt_of_le (by norm_num) two_le_pi #align real.pi_pos Real.pi_pos -namespace Mathlib.Meta.Positivity -open Lean.Meta Qq - -/-- Extension for the `positivity` tactic: `π` is always positive. -/ -@[positivity π] -def evalExp : Mathlib.Meta.Positivity.PositivityExt where eval {_ _} _ _ _ := do - pure (.positive (q(Real.pi_pos) : Lean.Expr)) - -end Mathlib.Meta.Positivity - - theorem pi_ne_zero : π ≠ 0 := ne_of_gt pi_pos #align real.pi_ne_zero Real.pi_ne_zero @@ -188,6 +177,16 @@ theorem two_pi_pos : 0 < 2 * π := by linarith [pi_pos] end Real +namespace Mathlib.Meta.Positivity +open Lean.Meta Qq + +/-- Extension for the `positivity` tactic: `π` is always positive. -/ +@[positivity Real.pi] +def evalRealPi : Mathlib.Meta.Positivity.PositivityExt where eval {_ _} _ _ _ := do + pure (.positive (q(Real.pi_pos) : Lean.Expr)) + +end Mathlib.Meta.Positivity + namespace NNReal open Real diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Deriv.lean index b8b3df4bc1d60..c083d3f2d081f 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Deriv.lean @@ -698,6 +698,10 @@ theorem sinh_lt_sinh : sinh x < sinh y ↔ x < y := sinh_strictMono.lt_iff_lt #align real.sinh_lt_sinh Real.sinh_lt_sinh +@[simp] lemma sinh_eq_zero : sinh x = 0 ↔ x = 0 := by rw [← @sinh_inj x, sinh_zero] + +lemma sinh_ne_zero : sinh x ≠ 0 ↔ x ≠ 0 := sinh_eq_zero.not + @[simp] theorem sinh_pos_iff : 0 < sinh x ↔ 0 < x := by simpa only [sinh_zero] using @sinh_lt_sinh 0 x #align real.sinh_pos_iff Real.sinh_pos_iff @@ -1183,3 +1187,34 @@ theorem ContDiffWithinAt.sinh {n} (hf : ContDiffWithinAt ℝ n f s x) : #align cont_diff_within_at.sinh ContDiffWithinAt.sinh end + +namespace Mathlib.Meta.Positivity +open Lean Meta Qq + +private alias ⟨_, sinh_pos_of_pos⟩ := Real.sinh_pos_iff +private alias ⟨_, sinh_nonneg_of_nonneg⟩ := Real.sinh_nonneg_iff +private alias ⟨_, sinh_ne_zero_of_ne_zero⟩ := Real.sinh_ne_zero + +/-- Extension for the `positivity` tactic: `Real.sinh` is positive/nonnegative/nonzero if its input +is. -/ +@[positivity Real.sinh _] +def evalSinh : PositivityExt where eval {u α} _ _ e := do + let zα : Q(Zero ℝ) := q(inferInstance) + let pα : Q(PartialOrder ℝ) := q(inferInstance) + if let 0 := u then -- lean4#3060 means we can't combine this with the match below + match α, e with + | ~q(ℝ), ~q(Real.sinh $a) => + assumeInstancesCommute + match ← core zα pα a with + | .positive pa => return .positive q(sinh_pos_of_pos $pa) + | .nonnegative pa => return .nonnegative q(sinh_nonneg_of_nonneg $pa) + | .nonzero pa => return .nonzero q(sinh_ne_zero_of_ne_zero $pa) + | _ => return .none + | _, _ => throwError "not Real.sinh" + else throwError "not Real.sinh" + +example (x : ℝ) (hx : 0 < x) : 0 < x.sinh := by positivity +example (x : ℝ) (hx : 0 ≤ x) : 0 ≤ x.sinh := by positivity +example (x : ℝ) (hx : x ≠ 0) : x.sinh ≠ 0 := by positivity + +end Mathlib.Meta.Positivity diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index dd362c906dc7a..94daa0ee28250 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -2033,6 +2033,19 @@ def evalExp : PositivityExt where eval {_ _} _ _ e := do let (.app _ (a : Q(ℝ))) ← withReducible (whnf e) | throwError "not Real.exp" pure (.positive (q(Real.exp_pos $a) : Lean.Expr)) +/-- Extension for the `positivity` tactic: `Real.cosh` is always positive. -/ +@[positivity Real.cosh _] +def evalCosh : PositivityExt where eval {u α} _ _ e := do + if let 0 := u then -- lean4#3060 means we can't combine this with the match below + match α, e with + | ~q(ℝ), ~q(Real.cosh $a) => + assumeInstancesCommute + return .positive q(Real.cosh_pos $a) + | _, _ => throwError "not Real.cosh" + else throwError "not Real.cosh" + +example (x : ℝ) : 0 < x.cosh := by positivity + end Mathlib.Meta.Positivity namespace Complex From cd497dfda2969bec9c1af7cceab419b87d9f95a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 12:09:06 +0000 Subject: [PATCH 201/353] feat: Taylor series for `cosh` and `sinh` (#9100) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and derive `cosh x ≤ exp (x ^ 2 / 2)` as a corollary --- .../Trigonometric/Series.lean | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Series.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Series.lean index 980468b619b32..16fd6f486ed8e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Series.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Series.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2023 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Eric Wieser +Authors: Eric Wieser, Yaël Dillies -/ import Mathlib.Analysis.SpecialFunctions.Exponential @@ -121,3 +121,50 @@ theorem Real.sin_eq_tsum (r : ℝ) : #align real.sin_eq_tsum Real.sin_eq_tsum end SinCos + +/-! ### `cosh` and `sinh` for `ℝ` and `ℂ` -/ + +section SinhCosh +namespace Complex + +/-- The power series expansion of `Complex.cosh`. -/ +lemma hasSum_cosh (z : ℂ) : HasSum (fun n ↦ z ^ (2 * n) / ↑(2 * n)!) (cosh z) := by + simpa [mul_assoc, cos_mul_I] using hasSum_cos' (z * I) + +/-- The power series expansion of `Complex.sinh`. -/ +lemma hasSum_sinh (z : ℂ) : HasSum (fun n ↦ z ^ (2 * n + 1) / ↑(2 * n + 1)!) (sinh z) := by + simpa [mul_assoc, sin_mul_I, neg_pow z, pow_add, pow_mul, neg_mul, neg_div] + using (hasSum_sin' (z * I)).mul_right (-I) + +lemma cosh_eq_tsum (z : ℂ) : cosh z = ∑' n, z ^ (2 * n) / ↑(2 * n)! := z.hasSum_cosh.tsum_eq.symm + +lemma sinh_eq_tsum (z : ℂ) : sinh z = ∑' n, z ^ (2 * n + 1) / ↑(2 * n + 1)! := + z.hasSum_sinh.tsum_eq.symm + +end Complex + +namespace Real + +/-- The power series expansion of `Real.cosh`. -/ +lemma hasSum_cosh (r : ℝ) : HasSum (fun n ↦ r ^ (2 * n) / ↑(2 * n)!) (cosh r) := + mod_cast Complex.hasSum_cosh r + +/-- The power series expansion of `Real.sinh`. -/ +lemma hasSum_sinh (r : ℝ) : HasSum (fun n ↦ r ^ (2 * n + 1) / ↑(2 * n + 1)!) (sinh r) := + mod_cast Complex.hasSum_sinh r + +lemma cosh_eq_tsum (r : ℝ) : cosh r = ∑' n, r ^ (2 * n) / ↑(2 * n)! := r.hasSum_cosh.tsum_eq.symm + +lemma sinh_eq_tsum (r : ℝ) : sinh r = ∑' n, r ^ (2 * n + 1) / ↑(2 * n + 1)! := + r.hasSum_sinh.tsum_eq.symm + +lemma cosh_le_exp_half_sq (x : ℝ) : cosh x ≤ exp (x ^ 2 / 2) := by + rw [cosh_eq_tsum, exp_eq_exp_ℝ, exp_eq_tsum] + refine tsum_le_tsum (fun i ↦ ?_) x.hasSum_cosh.summable $ expSeries_summable' (x ^ 2 / 2) + simp only [div_pow, pow_mul, smul_eq_mul, inv_mul_eq_div, div_div] + gcongr + norm_cast + exact Nat.two_pow_mul_factorial_le_factorial_two_mul _ + +end Real +end SinhCosh From 08636fb93a0723e4c04ee9e06a62c41bc7ea1189 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 26 Dec 2023 13:18:05 +0000 Subject: [PATCH 202/353] feat: derivative of minpoly is in the different ideal. (#9283) --- Mathlib/NumberTheory/KummerDedekind.lean | 22 +++++ .../RingTheory/DedekindDomain/Different.lean | 99 +++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/Mathlib/NumberTheory/KummerDedekind.lean b/Mathlib/NumberTheory/KummerDedekind.lean index 056e4a27284ab..15d364df10e52 100644 --- a/Mathlib/NumberTheory/KummerDedekind.lean +++ b/Mathlib/NumberTheory/KummerDedekind.lean @@ -90,6 +90,28 @@ theorem conductor_eq_top_of_powerBasis (pb : PowerBasis R S) : conductor R pb.ge conductor_eq_top_of_adjoin_eq_top pb.adjoin_gen_eq_top #align conductor_eq_top_of_power_basis conductor_eq_top_of_powerBasis +open IsLocalization in +lemma mem_coeSubmodule_conductor {L} [CommRing L] [Algebra S L] [Algebra R L] + [IsScalarTower R S L] [NoZeroSMulDivisors S L] {x : S} {y : L} : + y ∈ coeSubmodule L (conductor R x) ↔ ∀ z : S, + y * (algebraMap S L) z ∈ Algebra.adjoin R {algebraMap S L x} := by + cases subsingleton_or_nontrivial L + · rw [Subsingleton.elim (coeSubmodule L _) ⊤, Subsingleton.elim (Algebra.adjoin R _) ⊤]; simp + trans ∀ z, y * (algebraMap S L) z ∈ (Algebra.adjoin R {x}).map (IsScalarTower.toAlgHom R S L) + · simp only [coeSubmodule, Submodule.mem_map, Algebra.linearMap_apply, Subalgebra.mem_map, + IsScalarTower.coe_toAlgHom'] + constructor + · rintro ⟨y, hy, rfl⟩ z + exact ⟨_, hy z, map_mul _ _ _⟩ + · intro H + obtain ⟨y, _, e⟩ := H 1 + rw [_root_.map_one, mul_one] at e + subst e + simp only [← _root_.map_mul, (NoZeroSMulDivisors.algebraMap_injective S L).eq_iff, + exists_eq_right] at H + exact ⟨_, H, rfl⟩ + · rw [AlgHom.map_adjoin, Set.image_singleton]; rfl + variable {I : Ideal R} /-- This technical lemma tell us that if `C` is the conductor of `R` and `I` is an ideal of `R` diff --git a/Mathlib/RingTheory/DedekindDomain/Different.lean b/Mathlib/RingTheory/DedekindDomain/Different.lean index 145c346ce267b..8f9ceb422b74b 100644 --- a/Mathlib/RingTheory/DedekindDomain/Different.lean +++ b/Mathlib/RingTheory/DedekindDomain/Different.lean @@ -6,6 +6,7 @@ Authors: Andrew Yang import Mathlib.RingTheory.DedekindDomain.Ideal import Mathlib.RingTheory.Discriminant import Mathlib.RingTheory.DedekindDomain.IntegralClosure +import Mathlib.NumberTheory.KummerDedekind /-! # The different ideal @@ -15,6 +16,14 @@ import Mathlib.RingTheory.DedekindDomain.IntegralClosure - `FractionalIdeal.dual`: The dual fractional ideal under the trace form. - `differentIdeal`: The different ideal of an extension of integral domains. +## Main results +- `conductor_mul_differentIdeal`: + If `L = K[x]`, with `x` integral over `A`, then `𝔣 * 𝔇 = (f'(x))` + with `f` being the minimal polynomial of `x`. +- `aeval_derivative_mem_differentIdeal`: + If `L = K[x]`, with `x` integral over `A`, then `f'(x) ∈ 𝔇` + with `f` being the minimal polynomial of `x`. + ## TODO - Show properties of the different ideal -/ @@ -432,3 +441,93 @@ lemma differentialIdeal_le_iff {I : Ideal B} (hI : I ≠ ⊥) [NoZeroSMulDivisor ((Algebra.trace K L).restrictScalars A) ≤ 1 := (FractionalIdeal.coeIdeal_le_coeIdeal _).symm.trans (differentialIdeal_le_fractionalIdeal_iff (I := (I : FractionalIdeal B⁰ L)) (by simpa)) + +variable (A K) + +open Pointwise Polynomial in +lemma traceForm_dualSubmodule_adjoin + {x : L} (hx : Algebra.adjoin K {x} = ⊤) (hAx : IsIntegral A x) : + (traceForm K L).dualSubmodule (Subalgebra.toSubmodule (Algebra.adjoin A {x})) = + (aeval x (derivative <| minpoly K x) : L)⁻¹ • + (Subalgebra.toSubmodule (Algebra.adjoin A {x})) := by + classical + have hKx : IsIntegral K x := Algebra.IsIntegral.of_finite (R := K) (B := L) x + let pb := (Algebra.adjoin.powerBasis' hKx).map + ((Subalgebra.equivOfEq _ _ hx).trans (Subalgebra.topEquiv)) + have pbgen : pb.gen = x := by simp + have hpb : ⇑(BilinForm.dualBasis (traceForm K L) _ pb.basis) = _ := + _root_.funext (traceForm_dualBasis_powerBasis_eq pb) + have : (Subalgebra.toSubmodule (Algebra.adjoin A {x})) = Submodule.span A (Set.range pb.basis) + · rw [← span_range_natDegree_eq_adjoin (minpoly.monic hAx) (minpoly.aeval _ _)] + congr; ext y + have : natDegree (minpoly A x) = natDegree (minpoly K x) + · rw [minpoly.isIntegrallyClosed_eq_field_fractions' K hAx, (minpoly.monic hAx).natDegree_map] + simp only [Finset.coe_image, Finset.coe_range, Set.mem_image, Set.mem_Iio, Set.mem_range, + pb.basis_eq_pow, pbgen] + simp only [PowerBasis.map_dim, adjoin.powerBasis'_dim, this] + exact ⟨fun ⟨a, b, c⟩ ↦ ⟨⟨a, b⟩, c⟩, fun ⟨⟨a, b⟩, c⟩ ↦ ⟨a, b, c⟩⟩ + clear_value pb + conv_lhs => rw [this] + rw [← span_coeff_minpolyDiv hAx, BilinForm.dualSubmodule_span_of_basis, + Submodule.smul_span, hpb] + show _ = Submodule.span A (_ '' _) + simp only [← Set.range_comp, smul_eq_mul, div_eq_inv_mul, pbgen, + minpolyDiv_eq_of_isIntegrallyClosed K hAx] + apply le_antisymm <;> rw [Submodule.span_le] + · rintro _ ⟨i, rfl⟩; exact Submodule.subset_span ⟨i, rfl⟩ + · rintro _ ⟨i, rfl⟩ + by_cases hi : i < pb.dim + · exact Submodule.subset_span ⟨⟨i, hi⟩, rfl⟩ + · rw [Function.comp_apply, coeff_eq_zero_of_natDegree_lt, mul_zero]; exact zero_mem _ + rw [← pb.natDegree_minpoly, pbgen, ← natDegree_minpolyDiv_succ hKx, + ← Nat.succ_eq_add_one] at hi + exact le_of_not_lt hi + +variable (L) + +open Polynomial Pointwise in +lemma conductor_mul_differentIdeal [NoZeroSMulDivisors A B] + (x : B) (hx : Algebra.adjoin K {algebraMap B L x} = ⊤) : + (conductor A x) * differentIdeal A B = Ideal.span {aeval x (derivative (minpoly A x))} := by + classical + have hAx : IsIntegral A x := IsIntegralClosure.isIntegral A L x + haveI := IsIntegralClosure.isFractionRing_of_finite_extension A K L B + apply FractionalIdeal.coeIdeal_injective (K := L) + simp only [FractionalIdeal.coeIdeal_mul, FractionalIdeal.coeIdeal_span_singleton] + rw [coeIdeal_differentIdeal A K L B, + mul_inv_eq_iff_eq_mul₀] + swap; exact FractionalIdeal.dual_ne_zero A K one_ne_zero + apply FractionalIdeal.coeToSubmodule_injective + simp only [FractionalIdeal.coe_coeIdeal, FractionalIdeal.coe_mul, + FractionalIdeal.coe_spanSingleton, Submodule.span_singleton_mul] + ext y + have hne₁ : aeval (algebraMap B L x) (derivative (minpoly K (algebraMap B L x))) ≠ 0 + · exact (IsSeparable.separable _ _).aeval_derivative_ne_zero (minpoly.aeval _ _) + have : algebraMap B L (aeval x (derivative (minpoly A x))) ≠ 0 + · rwa [minpoly.isIntegrallyClosed_eq_field_fractions K L hAx, derivative_map, + aeval_map_algebraMap, aeval_algebraMap_apply] at hne₁ + rw [Submodule.mem_smul_iff_inv_mul_mem this, FractionalIdeal.mem_coe, FractionalIdeal.mem_dual, + mem_coeSubmodule_conductor] + swap; exact one_ne_zero + have hne₂ : (aeval (algebraMap B L x) (derivative (minpoly K (algebraMap B L x))))⁻¹ ≠ 0 + · rwa [ne_eq, inv_eq_zero] + have : IsIntegral A (algebraMap B L x) := IsIntegral.map (IsScalarTower.toAlgHom A B L) hAx + simp_rw [← Subalgebra.mem_toSubmodule, ← Submodule.mul_mem_smul_iff (y := y * _) + (mem_nonZeroDivisors_of_ne_zero hne₂)] + rw [← traceForm_dualSubmodule_adjoin A K hx this] + simp only [BilinForm.mem_dualSubmodule, traceForm_apply, Subalgebra.mem_toSubmodule, + minpoly.isIntegrallyClosed_eq_field_fractions K L hAx, + derivative_map, aeval_map_algebraMap, aeval_algebraMap_apply, mul_assoc, + FractionalIdeal.mem_one_iff, forall_exists_index, forall_apply_eq_imp_iff] + simp_rw [← IsScalarTower.toAlgHom_apply A B L x, ← AlgHom.map_adjoin_singleton] + simp only [Subalgebra.mem_map, IsScalarTower.coe_toAlgHom', + forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, ← _root_.map_mul] + exact ⟨fun H b ↦ (mul_one b) ▸ H b 1 (one_mem _), fun H _ _ _ ↦ H _⟩ + +open Polynomial Pointwise in +lemma aeval_derivative_mem_differentIdeal [NoZeroSMulDivisors A B] + (x : B) (hx : Algebra.adjoin K {algebraMap B L x} = ⊤) : + aeval x (derivative (minpoly A x)) ∈ differentIdeal A B := by + refine SetLike.le_def.mp ?_ (Ideal.mem_span_singleton_self _) + rw [← conductor_mul_differentIdeal A K L x hx] + exact Ideal.mul_le_left From 2d7e88a5774dc231a27040b50ca5107264e90747 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 26 Dec 2023 13:40:31 +0000 Subject: [PATCH 203/353] feat: A dedekind domain that is local is a PID. (#9282) Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib/RingTheory/Artinian.lean | 4 +- .../DiscreteValuationRing/TFAE.lean | 162 +++++++++--------- Mathlib/RingTheory/Filtration.lean | 13 ++ Mathlib/RingTheory/Ideal/Cotangent.lean | 48 ++++++ Mathlib/RingTheory/Nakayama.lean | 13 +- .../RingTheory/Valuation/ValuationRing.lean | 7 +- 6 files changed, 158 insertions(+), 89 deletions(-) diff --git a/Mathlib/RingTheory/Artinian.lean b/Mathlib/RingTheory/Artinian.lean index 5c5f7b67c8d16..58f9fcfe7b919 100644 --- a/Mathlib/RingTheory/Artinian.lean +++ b/Mathlib/RingTheory/Artinian.lean @@ -448,8 +448,8 @@ theorem isNilpotent_jacobson_bot : IsNilpotent (Ideal.jacobson (⊥ : Ideal R)) sup_le_sup_left (smul_le.2 fun _ _ _ => Submodule.smul_mem _ _) _ have : Jac * Ideal.span {x} ≤ J := by -- Need version 4 of Nakayama's lemma on Stacks by_contra H - refine' H (smul_le_of_le_smul_of_le_jacobson_bot (fg_span_singleton _) le_rfl - (this.eq_of_not_lt (hJ' _ _)).ge) + refine H (Ideal.mul_le_left.trans (le_of_le_smul_of_le_jacobson_bot (fg_span_singleton _) le_rfl + (le_sup_right.trans_eq (this.eq_of_not_lt (hJ' _ ?_)).symm))) exact lt_of_le_of_ne le_sup_left fun h => H <| h.symm ▸ le_sup_right have : Ideal.span {x} * Jac ^ (n + 1) ≤ ⊥ calc diff --git a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean index 8afc40f01f2f1..94f6f695c3917 100644 --- a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean +++ b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean @@ -15,7 +15,7 @@ import Mathlib.RingTheory.Nakayama # Equivalent conditions for DVR In `DiscreteValuationRing.TFAE`, we show that the following are equivalent for a -noetherian local domain `(R, m, k)`: +noetherian local domain that is not a field `(R, m, k)`: - `R` is a discrete valuation ring - `R` is a valuation ring - `R` is a dedekind domain @@ -24,20 +24,21 @@ noetherian local domain `(R, m, k)`: - `dimₖ m/m² = 1` - Every nonzero ideal is a power of `m`. +Also see `tfae_of_isNoetherianRing_of_localRing_of_isDomain` for a version without `¬ IsField R`. -/ variable (R : Type*) [CommRing R] (K : Type*) [Field K] [Algebra R K] [IsFractionRing R K] -open scoped DiscreteValuation +open scoped DiscreteValuation BigOperators -open LocalRing - -open scoped BigOperators +open LocalRing FiniteDimensional theorem exists_maximalIdeal_pow_eq_of_principal [IsNoetherianRing R] [LocalRing R] [IsDomain R] - (h : ¬IsField R) (h' : (maximalIdeal R).IsPrincipal) (I : Ideal R) (hI : I ≠ ⊥) : + (h' : (maximalIdeal R).IsPrincipal) (I : Ideal R) (hI : I ≠ ⊥) : ∃ n : ℕ, I = maximalIdeal R ^ n := by + by_cases h : IsField R; + · exact ⟨0, by simp [letI := h.toField; (eq_bot_or_eq_top I).resolve_left hI]⟩ classical obtain ⟨x, hx : _ = Ideal.span _⟩ := h' by_cases hI' : I = ⊤ @@ -149,87 +150,42 @@ theorem maximalIdeal_isPrincipal_of_isDedekindDomain [LocalRing R] [IsDomain R] · rwa [Submodule.span_le, Set.singleton_subset_iff] #align maximal_ideal_is_principal_of_is_dedekind_domain maximalIdeal_isPrincipal_of_isDedekindDomain -theorem DiscreteValuationRing.TFAE [IsNoetherianRing R] [LocalRing R] [IsDomain R] - (h : ¬IsField R) : +/-- +Let `(R, m, k)` be a noetherian local domain (possibly a field). +The following are equivalent: +0. `R` is a PID +1. `R` is a valuation ring +2. `R` is a dedekind domain +3. `R` is integrally closed with at most one non-zero prime ideal +4. `m` is principal +5. `dimₖ m/m² ≤ 1` +6. Every nonzero ideal is a power of `m`. + +Also see `DiscreteValuationRing.TFAE` for a version assuming `¬ IsField R`. +-/ +theorem tfae_of_isNoetherianRing_of_localRing_of_isDomain + [IsNoetherianRing R] [LocalRing R] [IsDomain R] : List.TFAE - [DiscreteValuationRing R, ValuationRing R, IsDedekindDomain R, - IsIntegrallyClosed R ∧ ∃! P : Ideal R, P ≠ ⊥ ∧ P.IsPrime, (maximalIdeal R).IsPrincipal, - FiniteDimensional.finrank (ResidueField R) (CotangentSpace R) = 1, + [IsPrincipalIdealRing R, ValuationRing R, IsDedekindDomain R, + IsIntegrallyClosed R ∧ ∀ P : Ideal R, P ≠ ⊥ → P.IsPrime → P = maximalIdeal R, + (maximalIdeal R).IsPrincipal, + finrank (ResidueField R) (CotangentSpace R) ≤ 1, ∀ (I) (_ : I ≠ ⊥), ∃ n : ℕ, I = maximalIdeal R ^ n] := by - have ne_bot := Ring.ne_bot_of_isMaximal_of_not_isField (maximalIdeal.isMaximal R) h - classical - rw [finrank_eq_one_iff'] tfae_have 1 → 2 - · intro; infer_instance + · exact fun _ ↦ inferInstance tfae_have 2 → 1 - · intro - haveI := IsBezout.toGCDDomain R - haveI : UniqueFactorizationMonoid R := ufm_of_gcd_of_wfDvdMonoid - apply DiscreteValuationRing.of_ufd_of_unique_irreducible - · obtain ⟨x, hx₁, hx₂⟩ := Ring.exists_not_isUnit_of_not_isField h - obtain ⟨p, hp₁, -⟩ := WfDvdMonoid.exists_irreducible_factor hx₂ hx₁ - exact ⟨p, hp₁⟩ - · exact ValuationRing.unique_irreducible + · exact fun _ ↦ ((IsBezout.TFAE (R := R)).out 0 1).mp ‹_› tfae_have 1 → 4 · intro H - exact ⟨inferInstance, ((DiscreteValuationRing.iff_pid_with_one_nonzero_prime R).mp H).2⟩ + exact ⟨inferInstance, fun P hP hP' ↦ eq_maximalIdeal (hP'.isMaximal hP)⟩ tfae_have 4 → 3 - · rintro ⟨h₁, h₂⟩; - exact { h₁ with - maximalOfPrime := fun hI hI' => ExistsUnique.unique h₂ ⟨ne_bot, inferInstance⟩ ⟨hI, hI'⟩ ▸ - maximalIdeal.isMaximal R, } + · exact fun ⟨h₁, h₂⟩ ↦ { h₁ with maximalOfPrime := (h₂ _ · · ▸ maximalIdeal.isMaximal R) } tfae_have 3 → 5 - · intro h; exact maximalIdeal_isPrincipal_of_isDedekindDomain R - tfae_have 5 → 6 - · rintro ⟨x, hx⟩ - have : x ∈ maximalIdeal R := by rw [hx]; exact Submodule.subset_span (Set.mem_singleton x) - let x' : maximalIdeal R := ⟨x, this⟩ - use Submodule.Quotient.mk x' - constructor - swap - · intro e - rw [Submodule.Quotient.mk_eq_zero] at e - apply Ring.ne_bot_of_isMaximal_of_not_isField (maximalIdeal.isMaximal R) h - apply Submodule.eq_bot_of_le_smul_of_le_jacobson_bot (maximalIdeal R) - · exact ⟨{x}, (Finset.coe_singleton x).symm ▸ hx.symm⟩ - · conv_lhs => rw [hx] - rw [Submodule.mem_smul_top_iff] at e - rwa [Submodule.span_le, Set.singleton_subset_iff] - · rw [LocalRing.jacobson_eq_maximalIdeal (⊥ : Ideal R) bot_ne_top] - · refine' fun w => Quotient.inductionOn' w fun y => _ - obtain ⟨y, hy⟩ := y - rw [hx, Submodule.mem_span_singleton] at hy - obtain ⟨a, rfl⟩ := hy - exact ⟨Ideal.Quotient.mk _ a, rfl⟩ - tfae_have 6 → 5 - · rintro ⟨x, hx, hx'⟩ - induction x using Quotient.inductionOn' with | h x => ?_ - use x - apply le_antisymm - swap; · rw [Submodule.span_le, Set.singleton_subset_iff]; exact x.prop - have h₁ : - (Ideal.span {(x : R)} : Ideal R) ⊔ maximalIdeal R ≤ - Ideal.span {(x : R)} ⊔ maximalIdeal R • maximalIdeal R := by - refine' sup_le le_sup_left _ - rintro m hm - obtain ⟨c, hc⟩ := hx' (Submodule.Quotient.mk ⟨m, hm⟩) - induction c using Quotient.inductionOn' with | h c => ?_ - rw [← sub_sub_cancel (c * x) m] - apply sub_mem _ _ - · refine' Ideal.mem_sup_left (Ideal.mem_span_singleton'.mpr ⟨c, rfl⟩) - · have := (Submodule.Quotient.eq _).mp hc - rw [Submodule.mem_smul_top_iff] at this - exact Ideal.mem_sup_right this - have h₂ : maximalIdeal R ≤ (⊥ : Ideal R).jacobson := by - rw [LocalRing.jacobson_eq_maximalIdeal] - exact bot_ne_top - have := - Submodule.sup_smul_eq_sup_smul_of_le_smul_of_le_jacobson (IsNoetherian.noetherian _) h₂ h₁ - rw [Submodule.bot_smul, sup_bot_eq] at this - rw [← sup_eq_left, eq_comm] - exact le_sup_left.antisymm (h₁.trans <| le_of_eq this) + · exact fun h ↦ maximalIdeal_isPrincipal_of_isDedekindDomain R + tfae_have 6 ↔ 5 + · exact finrank_cotangentSpace_le_one_iff tfae_have 5 → 7 - · exact exists_maximalIdeal_pow_eq_of_principal R h + · exact exists_maximalIdeal_pow_eq_of_principal R tfae_have 7 → 2 · rw [ValuationRing.iff_ideal_total] intro H @@ -249,4 +205,54 @@ theorem DiscreteValuationRing.TFAE [IsNoetherianRing R] [LocalRing R] [IsDomain · left; exact Ideal.pow_le_pow_right h' · right; exact Ideal.pow_le_pow_right h' tfae_finish + +/-- +The following are equivalent for a +noetherian local domain that is not a field `(R, m, k)`: +0. `R` is a discrete valuation ring +1. `R` is a valuation ring +2. `R` is a dedekind domain +3. `R` is integrally closed with a unique non-zero prime ideal +4. `m` is principal +5. `dimₖ m/m² = 1` +6. Every nonzero ideal is a power of `m`. + +Also see `tfae_of_isNoetherianRing_of_localRing_of_isDomain` for a version without `¬ IsField R`. +-/ +theorem DiscreteValuationRing.TFAE [IsNoetherianRing R] [LocalRing R] [IsDomain R] + (h : ¬IsField R) : + List.TFAE + [DiscreteValuationRing R, ValuationRing R, IsDedekindDomain R, + IsIntegrallyClosed R ∧ ∃! P : Ideal R, P ≠ ⊥ ∧ P.IsPrime, (maximalIdeal R).IsPrincipal, + finrank (ResidueField R) (CotangentSpace R) = 1, + ∀ (I) (_ : I ≠ ⊥), ∃ n : ℕ, I = maximalIdeal R ^ n] := by + have : finrank (ResidueField R) (CotangentSpace R) = 1 ↔ + finrank (ResidueField R) (CotangentSpace R) ≤ 1 + · simp [Nat.le_one_iff_eq_zero_or_eq_one, finrank_cotangentSpace_eq_zero_iff, h] + rw [this] + have : maximalIdeal R ≠ ⊥ := isField_iff_maximalIdeal_eq.not.mp h + convert tfae_of_isNoetherianRing_of_localRing_of_isDomain R + · exact ⟨fun _ ↦ inferInstance, fun h ↦ { h with not_a_field' := this }⟩ + · exact ⟨fun h P h₁ h₂ ↦ h.unique ⟨h₁, h₂⟩ ⟨this, inferInstance⟩, + fun H ↦ ⟨_, ⟨this, inferInstance⟩, fun P hP ↦ H P hP.1 hP.2⟩⟩ #align discrete_valuation_ring.tfae DiscreteValuationRing.TFAE + +variable {R} + +lemma LocalRing.finrank_CotangentSpace_eq_one_iff [IsNoetherianRing R] [LocalRing R] [IsDomain R] : + finrank (ResidueField R) (CotangentSpace R) = 1 ↔ DiscreteValuationRing R := by + by_cases hR : IsField R + · letI := hR.toField + simp only [finrank_cotangentSpace_eq_zero, zero_ne_one, false_iff] + exact fun h ↦ h.3 maximalIdeal_eq_bot + · exact (DiscreteValuationRing.TFAE R hR).out 5 0 + +variable (R) + +lemma LocalRing.finrank_CotangentSpace_eq_one [IsDomain R] [DiscreteValuationRing R] : + finrank (ResidueField R) (CotangentSpace R) = 1 := + finrank_CotangentSpace_eq_one_iff.mpr ‹_› + +instance (priority := 100) IsDedekindDomain.isPrincipalIdealRing + [LocalRing R] [IsDedekindDomain R] : + IsPrincipalIdealRing R := ((tfae_of_isNoetherianRing_of_localRing_of_isDomain R).out 2 0).mp ‹_› diff --git a/Mathlib/RingTheory/Filtration.lean b/Mathlib/RingTheory/Filtration.lean index bd6c52b15feab..107850e6a4a87 100644 --- a/Mathlib/RingTheory/Filtration.lean +++ b/Mathlib/RingTheory/Filtration.lean @@ -472,6 +472,19 @@ theorem Ideal.iInf_pow_eq_bot_of_localRing [IsNoetherianRing R] [LocalRing R] (h rw [smul_eq_mul, ← Ideal.one_eq_top, mul_one] #align ideal.infi_pow_eq_bot_of_local_ring Ideal.iInf_pow_eq_bot_of_localRing +/-- Also see `Ideal.isIdempotentElem_iff_eq_bot_or_top` for integral domains. -/ +theorem Ideal.isIdempotentElem_iff_eq_bot_or_top_of_localRing {R} [CommRing R] + [IsNoetherianRing R] [LocalRing R] (I : Ideal R) : + IsIdempotentElem I ↔ I = ⊥ ∨ I = ⊤ := by + constructor + · intro H + by_cases I = ⊤; · exact Or.inr ‹_› + refine Or.inl (eq_bot_iff.mpr ?_) + rw [← Ideal.iInf_pow_eq_bot_of_localRing I ‹_›] + apply le_iInf + rintro (_|n) <;> simp [H.pow_succ_eq] + · rintro (rfl | rfl) <;> simp [IsIdempotentElem] + /-- **Krull's intersection theorem** for noetherian domains. -/ theorem Ideal.iInf_pow_eq_bot_of_isDomain [IsNoetherianRing R] [IsDomain R] (h : I ≠ ⊤) : ⨅ i : ℕ, I ^ i = ⊥ := by diff --git a/Mathlib/RingTheory/Ideal/Cotangent.lean b/Mathlib/RingTheory/Ideal/Cotangent.lean index 5fc7f4f793fe2..981529c976a68 100644 --- a/Mathlib/RingTheory/Ideal/Cotangent.lean +++ b/Mathlib/RingTheory/Ideal/Cotangent.lean @@ -8,6 +8,8 @@ import Mathlib.Algebra.Module.Torsion import Mathlib.Algebra.Ring.Idempotents import Mathlib.LinearAlgebra.FiniteDimensional import Mathlib.RingTheory.Ideal.LocalRing +import Mathlib.RingTheory.Filtration +import Mathlib.RingTheory.Nakayama #align_import ring_theory.ideal.cotangent from "leanprover-community/mathlib"@"4b92a463033b5587bb011657e25e4710bfca7364" @@ -211,4 +213,50 @@ instance : IsScalarTower R (ResidueField R) (CotangentSpace R) := instance [IsNoetherianRing R] : FiniteDimensional (ResidueField R) (CotangentSpace R) := Module.Finite.of_restrictScalars_finite R _ _ +variable {R} + +lemma subsingleton_cotangentSpace_iff [IsNoetherianRing R] : + Subsingleton (CotangentSpace R) ↔ IsField R := by + refine (maximalIdeal R).cotangent_subsingleton_iff.trans ?_ + rw [LocalRing.isField_iff_maximalIdeal_eq, Ideal.isIdempotentElem_iff_eq_bot_or_top_of_localRing] + simp [(maximalIdeal.isMaximal R).ne_top] + +lemma CotangentSpace.map_eq_top_iff [IsNoetherianRing R] {M : Submodule R (maximalIdeal R)} : + M.map (maximalIdeal R).toCotangent = ⊤ ↔ M = ⊤ := by + refine ⟨fun H ↦ eq_top_iff.mpr ?_, by rintro rfl; simp [Ideal.toCotangent_range]⟩ + refine (Submodule.map_le_map_iff_of_injective (Submodule.injective_subtype _) _ _).mp ?_ + rw [Submodule.map_top, Submodule.range_subtype] + apply Submodule.le_of_le_smul_of_le_jacobson_bot (IsNoetherian.noetherian _) + (LocalRing.jacobson_eq_maximalIdeal _ bot_ne_top).ge + rw [smul_eq_mul, ← pow_two, ← Ideal.map_toCotangent_ker, ← Submodule.map_sup, + ← Submodule.comap_map_eq, H, Submodule.comap_top, Submodule.map_top, Submodule.range_subtype] + +lemma CotangentSpace.span_image_eq_top_iff [IsNoetherianRing R] {s : Set (maximalIdeal R)} : + Submodule.span (ResidueField R) ((maximalIdeal R).toCotangent '' s) = ⊤ ↔ + Submodule.span R s = ⊤ := by + rw [← map_eq_top_iff, ← (Submodule.restrictScalars_injective R ..).eq_iff, + Submodule.restrictScalars_span] + simp only [Ideal.toCotangent_apply, Submodule.restrictScalars_top, Submodule.map_span] + exact Ideal.Quotient.mk_surjective + +open FiniteDimensional + +lemma finrank_cotangentSpace_eq_zero_iff [IsNoetherianRing R] : + finrank (ResidueField R) (CotangentSpace R) = 0 ↔ IsField R := by + rw [finrank_zero_iff, subsingleton_cotangentSpace_iff] + +lemma finrank_cotangentSpace_eq_zero (R) [Field R] : + finrank (ResidueField R) (CotangentSpace R) = 0 := + finrank_cotangentSpace_eq_zero_iff.mpr (Field.toIsField R) + +open Submodule in +theorem finrank_cotangentSpace_le_one_iff [IsNoetherianRing R] : + finrank (ResidueField R) (CotangentSpace R) ≤ 1 ↔ (maximalIdeal R).IsPrincipal := by + rw [Module.finrank_le_one_iff_top_isPrincipal, IsPrincipal_iff, + (maximalIdeal R).toCotangent_surjective.exists, IsPrincipal_iff] + simp_rw [← Set.image_singleton, eq_comm (a := ⊤), CotangentSpace.span_image_eq_top_iff, + ← (map_injective_of_injective (injective_subtype _)).eq_iff, map_span, Set.image_singleton, + Submodule.map_top, range_subtype, eq_comm (a := maximalIdeal R)] + exact ⟨fun ⟨x, h⟩ ↦ ⟨_, h⟩, fun ⟨x, h⟩ ↦ ⟨⟨x, h ▸ subset_span (Set.mem_singleton x)⟩, h⟩⟩ + end LocalRing diff --git a/Mathlib/RingTheory/Nakayama.lean b/Mathlib/RingTheory/Nakayama.lean index 5118641504432..9b6ce6129ac89 100644 --- a/Mathlib/RingTheory/Nakayama.lean +++ b/Mathlib/RingTheory/Nakayama.lean @@ -71,9 +71,10 @@ theorem eq_bot_of_le_smul_of_le_jacobson_bot (I : Ideal R) (N : Submodule R M) ( #align submodule.eq_bot_of_le_smul_of_le_jacobson_bot Submodule.eq_bot_of_le_smul_of_le_jacobson_bot theorem sup_eq_sup_smul_of_le_smul_of_le_jacobson {I J : Ideal R} {N N' : Submodule R M} - (hN' : N'.FG) (hIJ : I ≤ jacobson J) (hNN : N ⊔ N' ≤ N ⊔ I • N') : N ⊔ N' = N ⊔ J • N' := by + (hN' : N'.FG) (hIJ : I ≤ jacobson J) (hNN : N' ≤ N ⊔ I • N') : N ⊔ N' = N ⊔ J • N' := by have hNN' : N ⊔ N' = N ⊔ I • N' := - le_antisymm hNN (sup_le_sup_left (Submodule.smul_le.2 fun _ _ _ => Submodule.smul_mem _ _) _) + le_antisymm (sup_le le_sup_left hNN) + (sup_le_sup_left (Submodule.smul_le.2 fun _ _ _ => Submodule.smul_mem _ _) _) have h_comap := Submodule.comap_injective_of_surjective (LinearMap.range_eq_top.1 N.range_mkQ) have : (I • N').map N.mkQ = N'.map N.mkQ := by rw [← h_comap.eq_iff] @@ -88,14 +89,14 @@ theorem sup_eq_sup_smul_of_le_smul_of_le_jacobson {I J : Ideal R} {N N' : Submod [Stacks 00DV](https://stacks.math.columbia.edu/tag/00DV). See also `smul_le_of_le_smul_of_le_jacobson_bot` for the special case when `J = ⊥`. -/ theorem sup_smul_eq_sup_smul_of_le_smul_of_le_jacobson {I J : Ideal R} {N N' : Submodule R M} - (hN' : N'.FG) (hIJ : I ≤ jacobson J) (hNN : N ⊔ N' ≤ N ⊔ I • N') : N ⊔ I • N' = N ⊔ J • N' := - ((sup_le_sup_left smul_le_right _).antisymm hNN).trans + (hN' : N'.FG) (hIJ : I ≤ jacobson J) (hNN : N' ≤ N ⊔ I • N') : N ⊔ I • N' = N ⊔ J • N' := + ((sup_le_sup_left smul_le_right _).antisymm (sup_le le_sup_left hNN)).trans (sup_eq_sup_smul_of_le_smul_of_le_jacobson hN' hIJ hNN) #align submodule.sup_smul_eq_sup_smul_of_le_smul_of_le_jacobson Submodule.sup_smul_eq_sup_smul_of_le_smul_of_le_jacobson theorem le_of_le_smul_of_le_jacobson_bot {R M} [CommRing R] [AddCommGroup M] [Module R M] {I : Ideal R} {N N' : Submodule R M} (hN' : N'.FG) - (hIJ : I ≤ jacobson ⊥) (hNN : N ⊔ N' ≤ N ⊔ I • N') : N' ≤ N := by + (hIJ : I ≤ jacobson ⊥) (hNN : N' ≤ N ⊔ I • N') : N' ≤ N := by rw [← sup_eq_left, sup_eq_sup_smul_of_le_smul_of_le_jacobson hN' hIJ hNN, bot_smul, sup_bot_eq] /-- **Nakayama's Lemma** - Statement (4) in @@ -103,7 +104,7 @@ theorem le_of_le_smul_of_le_jacobson_bot {R M} [CommRing R] [AddCommGroup M] [Mo See also `sup_smul_eq_sup_smul_of_le_smul_of_le_jacobson` for a generalisation to the `jacobson` of any ideal -/ theorem smul_le_of_le_smul_of_le_jacobson_bot {I : Ideal R} {N N' : Submodule R M} (hN' : N'.FG) - (hIJ : I ≤ jacobson ⊥) (hNN : N ⊔ N' ≤ N ⊔ I • N') : I • N' ≤ N := + (hIJ : I ≤ jacobson ⊥) (hNN : N' ≤ N ⊔ I • N') : I • N' ≤ N := smul_le_right.trans (le_of_le_smul_of_le_jacobson_bot hN' hIJ hNN) #align submodule.smul_le_of_le_smul_of_le_jacobson_bot Submodule.smul_le_of_le_smul_of_le_jacobson_bot diff --git a/Mathlib/RingTheory/Valuation/ValuationRing.lean b/Mathlib/RingTheory/Valuation/ValuationRing.lean index 16304e2540146..24a273fe06b7d 100644 --- a/Mathlib/RingTheory/Valuation/ValuationRing.lean +++ b/Mathlib/RingTheory/Valuation/ValuationRing.lean @@ -356,10 +356,8 @@ instance (priority := 100) [ValuationRing R] : IsBezout R := by · erw [sup_eq_right.mpr h]; exact ⟨⟨_, rfl⟩⟩ · erw [sup_eq_left.mpr h]; exact ⟨⟨_, rfl⟩⟩ -theorem iff_local_bezout_domain : ValuationRing R ↔ LocalRing R ∧ IsBezout R := by +instance (priority := 100) [LocalRing R] [IsBezout R] : ValuationRing R := by classical - refine ⟨fun H => ⟨inferInstance, inferInstance⟩, ?_⟩ - rintro ⟨h₁, h₂⟩ refine iff_dvd_total.mpr ⟨fun a b => ?_⟩ obtain ⟨g, e : _ = Ideal.span _⟩ := IsBezout.span_pair_isPrincipal a b obtain ⟨a, rfl⟩ := Ideal.mem_span_singleton'.mp @@ -377,6 +375,9 @@ theorem iff_local_bezout_domain : ValuationRing R ↔ LocalRing R ∧ IsBezout R swap right all_goals exact mul_dvd_mul_right (isUnit_iff_forall_dvd.mp (isUnit_of_mul_isUnit_right h') _) _ + +theorem iff_local_bezout_domain : ValuationRing R ↔ LocalRing R ∧ IsBezout R := + ⟨fun _ ↦ ⟨inferInstance, inferInstance⟩, fun ⟨_, _⟩ ↦ inferInstance⟩ #align valuation_ring.iff_local_bezout_domain ValuationRing.iff_local_bezout_domain protected theorem tFAE (R : Type u) [CommRing R] [IsDomain R] : From 5a809b6adb326ce351012b12a484544844277798 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 26 Dec 2023 13:40:32 +0000 Subject: [PATCH 204/353] feat: Define `IsUnramified` for infinite places (#9285) --- .../NumberTheory/NumberField/Embeddings.lean | 263 +++++++++++++++++- 1 file changed, 260 insertions(+), 3 deletions(-) diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index 78333f019d378..2e567a148a1cd 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -221,13 +221,45 @@ lemma exists_comp_symm_eq_of_comp_eq [Algebra k K] [IsGalois k K] (φ ψ : K → ext1 x exact AlgHom.restrictNormal_commutes ψ' K x +variable [Algebra k K] (φ : K →+* ℂ) (σ : K ≃ₐ[k] K) + +/-- +`IsConj φ σ` states that `σ : K ≃ₐ[k] K` is the conjugation under the embedding `φ : K →+* ℂ`. +-/ +def IsConj : Prop := conjugate φ = φ.comp σ + +variable {φ σ} + +lemma IsConj.eq (h : IsConj φ σ) (x) : φ (σ x) = star (φ x) := RingHom.congr_fun h.symm x + +lemma IsConj.ext {σ₁ σ₂ : K ≃ₐ[k] K} (h₁ : IsConj φ σ₁) (h₂ : IsConj φ σ₂) : σ₁ = σ₂ := + AlgEquiv.ext fun x ↦ φ.injective ((h₁.eq x).trans (h₂.eq x).symm) + +lemma IsConj.ext_iff {σ₁ σ₂ : K ≃ₐ[k] K} (h₁ : IsConj φ σ₁) : σ₁ = σ₂ ↔ IsConj φ σ₂ := + ⟨fun e ↦ e ▸ h₁, h₁.ext⟩ + +lemma IsConj.isReal_comp (h : IsConj φ σ) : IsReal (φ.comp (algebraMap k K)) := by + ext1 x + simp only [conjugate_coe_eq, RingHom.coe_comp, Function.comp_apply, ← h.eq, + starRingEnd_apply, AlgEquiv.commutes] + +lemma isConj_one_iff : IsConj φ (1 : K ≃ₐ[k] K) ↔ IsReal φ := Iff.rfl + +alias ⟨_, IsReal.isConjGal_one⟩ := ComplexEmbedding.isConj_one_iff + +lemma IsConj.symm (hσ : IsConj φ σ) : + IsConj φ σ.symm := RingHom.ext fun x ↦ by simpa using congr_arg star (hσ.eq (σ.symm x)) + +lemma isConj_symm : IsConj φ σ.symm ↔ IsConj φ σ := + ⟨IsConj.symm, IsConj.symm⟩ + end NumberField.ComplexEmbedding section InfinitePlace open NumberField -variable (K : Type*) [Field K] {k : Type*} [Field k] {F : Type*} [Field F] +variable {k : Type*} [Field k] (K : Type*) [Field K] {F : Type*} [Field F] /-- An infinite place of a number field `K` is a place associated to a complex embedding. -/ def NumberField.InfinitePlace := { w : AbsoluteValue K ℝ // ∃ φ : K →+* ℂ, place φ = w } @@ -377,6 +409,10 @@ theorem not_isReal_iff_isComplex {w : InfinitePlace K} : ¬IsReal w ↔ IsComple rw [isComplex_iff, isReal_iff] #align number_field.infinite_place.not_is_real_iff_is_complex NumberField.InfinitePlace.not_isReal_iff_isComplex +@[simp] +theorem not_isComplex_iff_isReal {w : InfinitePlace K} : ¬IsComplex w ↔ IsReal w := by + rw [isComplex_iff, isReal_iff, not_not] + theorem isReal_or_isComplex (w : InfinitePlace K) : IsReal w ∨ IsComplex w := by rw [← not_isReal_iff_isComplex]; exact em _ #align number_field.infinite_place.is_real_or_is_complex NumberField.InfinitePlace.isReal_or_isComplex @@ -588,7 +624,7 @@ lemma ComplexEmbedding.exists_comp_symm_eq_of_comp_eq [Algebra k K] [IsGalois k ext1 x exact AlgHom.restrictNormal_commutes ψ' K x -lemma exists_smul_eq_of_comap_eq [Algebra k K] [IsGalois k K] (w w' : InfinitePlace K) +lemma exists_smul_eq_of_comap_eq [Algebra k K] [IsGalois k K] {w w' : InfinitePlace K} (h : w.comap (algebraMap k K) = w'.comap (algebraMap k K)) : ∃ σ : K ≃ₐ[k] K, σ • w = w' := by rw [← mk_embedding w, ← mk_embedding w', comap_mk, comap_mk, mk_eq_iff] at h cases h with @@ -605,7 +641,7 @@ lemma exists_smul_eq_of_comap_eq [Algebra k K] [IsGalois k K] (w w' : InfinitePl lemma mem_orbit_iff [IsGalois k K] {w w' : InfinitePlace K} : w' ∈ MulAction.orbit (K ≃ₐ[k] K) w ↔ w.comap (algebraMap k K) = w'.comap (algebraMap k K) := by - refine ⟨?_, exists_smul_eq_of_comap_eq w w'⟩ + refine ⟨?_, exists_smul_eq_of_comap_eq⟩ rintro ⟨σ, rfl : σ • w = w'⟩ rw [← mk_embedding w, comap_mk, smul_mk, comap_mk] congr 1; ext1; simp @@ -626,6 +662,227 @@ def orbitRelEquiv [IsGalois k K] : lemma orbitRelEquiv_apply_mk'' [IsGalois k K] (w : InfinitePlace K) : orbitRelEquiv (Quotient.mk'' w) = comap w (algebraMap k K) := rfl +variable (k w) + +/-- +An infinite place is unramified in a field extension if the restriction has the same multiplicity. +-/ +def IsUnramified : Prop := mult (w.comap (algebraMap k K)) = mult w + +variable {k w} + +lemma not_isUnramified_iff : + ¬ IsUnramified k w ↔ IsComplex w ∧ IsReal (w.comap (algebraMap k K)) := by + rw [IsUnramified, mult, mult, ← not_isReal_iff_isComplex] + split_ifs with h₁ h₂ h₂ <;> + simp only [not_true_eq_false, false_iff, and_self, forall_true_left, IsEmpty.forall_iff, + not_and, OfNat.one_ne_ofNat, not_false_eq_true, true_iff, OfNat.ofNat_ne_one, h₁, h₂] + exact h₁ (h₂.comap _) + +lemma isUnramified_iff : + IsUnramified k w ↔ IsReal w ∨ IsComplex (w.comap (algebraMap k K)) := by + rw [← not_iff_not, not_isUnramified_iff, not_or, + not_isReal_iff_isComplex, not_isComplex_iff_isReal] + +variable (k) + +lemma IsReal.isUnramified (h : IsReal w) : IsUnramified k w := isUnramified_iff.mpr (Or.inl h) + +variable {k} + +lemma _root_.NumberField.ComplexEmbedding.IsConj.isUnramified_mk_iff + {φ : K →+* ℂ} (h : ComplexEmbedding.IsConj φ σ) : + IsUnramified k (mk φ) ↔ σ = 1 := by + rw [h.ext_iff, ComplexEmbedding.isConj_one_iff, ← not_iff_not, not_isUnramified_iff, + ← not_isReal_iff_isComplex, comap_mk, isReal_mk_iff, isReal_mk_iff, eq_true h.isReal_comp, + and_true] + +lemma isUnramified_mk_iff_forall_isConj [IsGalois k K] {φ : K →+* ℂ} : + IsUnramified k (mk φ) ↔ ∀ σ : K ≃ₐ[k] K, ComplexEmbedding.IsConj φ σ → σ = 1 := by + refine ⟨fun H σ hσ ↦ hσ.isUnramified_mk_iff.mp H, + fun H ↦ ?_⟩ + by_contra hφ + rw [not_isUnramified_iff] at hφ + rw [comap_mk, isReal_mk_iff, ← not_isReal_iff_isComplex, isReal_mk_iff, + ← ComplexEmbedding.isConj_one_iff (k := k)] at hφ + letI := (φ.comp (algebraMap k K)).toAlgebra + letI := φ.toAlgebra + have : IsScalarTower k K ℂ := IsScalarTower.of_algebraMap_eq' rfl + let φ' : K →ₐ[k] ℂ := { star φ with commutes' := fun r ↦ by simpa using RingHom.congr_fun hφ.2 r } + have : ComplexEmbedding.IsConj φ (AlgHom.restrictNormal' φ' K) := + (RingHom.ext <| AlgHom.restrictNormal_commutes φ' K).symm + exact hφ.1 (H _ this ▸ this) + +local notation "Stab" => MulAction.stabilizer (K ≃ₐ[k] K) + +lemma mem_stabilizer_mk_iff (φ : K →+* ℂ) (σ : K ≃ₐ[k] K) : + σ ∈ Stab (mk φ) ↔ σ = 1 ∨ ComplexEmbedding.IsConj φ σ := by + simp only [MulAction.mem_stabilizer_iff, smul_mk, mk_eq_iff] + rw [← ComplexEmbedding.isConj_symm, ComplexEmbedding.conjugate, star_eq_iff_star_eq] + refine or_congr ⟨fun H ↦ ?_, fun H ↦ H ▸ rfl⟩ Iff.rfl + exact congr_arg AlgEquiv.symm + (AlgEquiv.ext (g := AlgEquiv.refl) fun x ↦ φ.injective (RingHom.congr_fun H x)) + +lemma IsUnramified.stabilizer_eq_bot (h : IsUnramified k w) : Stab w = ⊥ := by + rw [eq_bot_iff, ← mk_embedding w, SetLike.le_def] + simp only [mem_stabilizer_mk_iff, Subgroup.mem_bot, forall_eq_or_imp, true_and] + exact fun σ hσ ↦ hσ.isUnramified_mk_iff.mp ((mk_embedding w).symm ▸ h) + +lemma _root_.NumberField.ComplexEmbedding.IsConj.coe_stabilzer_mk + {φ : K →+* ℂ} (h : ComplexEmbedding.IsConj φ σ) : + (Stab (mk φ) : Set (K ≃ₐ[k] K)) = {1, σ} := by + ext + rw [SetLike.mem_coe, mem_stabilizer_mk_iff, Set.mem_insert_iff, Set.mem_singleton_iff, + ← h.ext_iff, eq_comm (a := σ)] + +variable (k w) + +lemma nat_card_stabilizer_eq_one_or_two : + Nat.card (Stab w) = 1 ∨ Nat.card (Stab w) = 2 := by + rw [← SetLike.coe_sort_coe, ← mk_embedding w] + by_cases h : ∃ σ, ComplexEmbedding.IsConj (k := k) (embedding w) σ + · obtain ⟨σ, hσ⟩ := h + simp only [hσ.coe_stabilzer_mk, Nat.card_eq_fintype_card, card_ofFinset, Set.toFinset_singleton] + by_cases 1 = σ + · left; simp [*] + · right; simp [*] + · push_neg at h + left + convert show Nat.card ({1} : Set (K ≃ₐ[k] K)) = 1 by simp + ext + simp only [SetLike.mem_coe, mem_stabilizer_mk_iff, Set.mem_singleton_iff, or_iff_left_iff_imp] + exact fun x ↦ (h _ x).elim + +variable {k w} + +lemma isUnramified_iff_stabilizer_eq_bot [IsGalois k K] : IsUnramified k w ↔ Stab w = ⊥ := by + rw [← mk_embedding w, isUnramified_mk_iff_forall_isConj] + simp only [eq_bot_iff, SetLike.le_def, mem_stabilizer_mk_iff, + Subgroup.mem_bot, forall_eq_or_imp, true_and] + +lemma isUnramified_iff_card_stabilizer_eq_one [IsGalois k K] : + IsUnramified k w ↔ Nat.card (Stab w) = 1 := by + rw [isUnramified_iff_stabilizer_eq_bot, Subgroup.card_eq_one] + +lemma not_isUnramified_iff_card_stabilizer_eq_two [IsGalois k K] : + ¬ IsUnramified k w ↔ Nat.card (Stab w) = 2 := by + rw [isUnramified_iff_card_stabilizer_eq_one] + obtain (e|e) := nat_card_stabilizer_eq_one_or_two k w <;> rw [e] <;> decide + +lemma card_stabilizer [IsGalois k K] : + Nat.card (Stab w) = if IsUnramified k w then 1 else 2 := by + split + · rwa [← isUnramified_iff_card_stabilizer_eq_one] + · rwa [← not_isUnramified_iff_card_stabilizer_eq_two] + +lemma even_nat_card_aut_of_not_isUnramified [IsGalois k K] (hw : ¬ IsUnramified k w) : + Even (Nat.card <| K ≃ₐ[k] K) := by + by_cases H : Finite (K ≃ₐ[k] K) + · cases nonempty_fintype (K ≃ₐ[k] K) + rw [even_iff_two_dvd, Nat.card_eq_fintype_card, + ← not_isUnramified_iff_card_stabilizer_eq_two.mp hw, Nat.card_eq_fintype_card] + exact Subgroup.card_subgroup_dvd_card (Stab w) + · convert even_zero + by_contra e + exact H (Nat.finite_of_card_ne_zero e) + +lemma even_card_aut_of_not_isUnramified [IsGalois k K] [FiniteDimensional k K] + (hw : ¬ IsUnramified k w) : + Even (Fintype.card <| K ≃ₐ[k] K) := + Nat.card_eq_fintype_card (α := K ≃ₐ[k] K) ▸ even_nat_card_aut_of_not_isUnramified hw + +lemma even_finrank_of_not_isUnramified [IsGalois k K] + (hw : ¬ IsUnramified k w) : Even (finrank k K) := by + by_cases FiniteDimensional k K + · exact IsGalois.card_aut_eq_finrank k K ▸ even_card_aut_of_not_isUnramified hw + · exact finrank_of_not_finite ‹_› ▸ even_zero + +lemma isUnramified_smul_iff : + IsUnramified k (σ • w) ↔ IsUnramified k w := by + rw [isUnramified_iff, isUnramified_iff, isReal_smul_iff, comap_smul, + ← AlgEquiv.toAlgHom_toRingHom, AlgHom.comp_algebraMap] + +variable (K) + +/-- A infinite place of the base field is unramified in a field extension if every +infinite place over it is unramified. -/ +def IsUnramifiedIn (w : InfinitePlace k) : Prop := + ∀ v, comap v (algebraMap k K) = w → IsUnramified k v + +variable {K} + +lemma isUnramifiedIn_comap [IsGalois k K] {w : InfinitePlace K} : + (w.comap (algebraMap k K)).IsUnramifiedIn K ↔ w.IsUnramified k := by + refine ⟨fun H ↦ H _ rfl, fun H v hv ↦ ?_⟩ + obtain ⟨σ, rfl⟩ := exists_smul_eq_of_comap_eq hv + rwa [isUnramified_smul_iff] at H + +lemma even_card_aut_of_not_isUnramifiedIn [IsGalois k K] [FiniteDimensional k K] + {w : InfinitePlace k} (hw : ¬ w.IsUnramifiedIn K) : + Even (Fintype.card <| K ≃ₐ[k] K) := by + obtain ⟨v, rfl⟩ := comap_surjective (Normal.isAlgebraic' (K := K)) w + rw [isUnramifiedIn_comap] at hw + exact even_card_aut_of_not_isUnramified hw + +lemma even_finrank_of_not_isUnramifiedIn + [IsGalois k K] {w : InfinitePlace k} (hw : ¬ w.IsUnramifiedIn K) : + Even (finrank k K) := by + obtain ⟨v, rfl⟩ := comap_surjective (Normal.isAlgebraic' (K := K)) w + rw [isUnramifiedIn_comap] at hw + exact even_finrank_of_not_isUnramified hw + +variable (k K) + +open Finset BigOperators in +lemma card_isUnramified [NumberField k] [IsGalois k K] : + Finset.card (univ.filter <| IsUnramified k (K := K)) = + Finset.card (univ.filter <| IsUnramifiedIn K (k := k)) * (finrank k K) := by + letI := Module.Finite.of_restrictScalars_finite ℚ k K + rw [← IsGalois.card_aut_eq_finrank, + Finset.card_eq_sum_card_fiberwise (f := (comap · (algebraMap k K))) + (t := (univ.filter <| IsUnramifiedIn K (k := k))), ← smul_eq_mul, ← sum_const] + refine sum_congr rfl (fun w hw ↦ ?_) + obtain ⟨w, rfl⟩ := comap_surjective (Normal.isAlgebraic' (K := K)) w + simp only [mem_univ, forall_true_left, mem_filter, true_and] at hw + trans Finset.card (MulAction.orbit (K ≃ₐ[k] K) w).toFinset + · congr; ext w' + simp only [mem_univ, forall_true_left, filter_congr_decidable, mem_filter, true_and, + Set.mem_toFinset, mem_orbit_iff, @eq_comm _ (comap w' _), and_iff_right_iff_imp] + intro e; rwa [← isUnramifiedIn_comap, ← e] + · rw [← MulAction.card_orbit_mul_card_stabilizer_eq_card_group _ w, + ← Nat.card_eq_fintype_card (α := Stab w), card_stabilizer, if_pos, + mul_one, Set.toFinset_card] + rwa [← isUnramifiedIn_comap] + · simp [isUnramifiedIn_comap] + +open Finset BigOperators in +lemma card_isUnramified_compl [NumberField k] [IsGalois k K] : + Finset.card (univ.filter <| IsUnramified k (K := K))ᶜ = + Finset.card (univ.filter <| IsUnramifiedIn K (k := k))ᶜ * (finrank k K / 2) := by + letI := Module.Finite.of_restrictScalars_finite ℚ k K + rw [← IsGalois.card_aut_eq_finrank, + Finset.card_eq_sum_card_fiberwise (f := (comap · (algebraMap k K))) + (t := (univ.filter <| IsUnramifiedIn K (k := k))ᶜ), ← smul_eq_mul, ← sum_const] + refine sum_congr rfl (fun w hw ↦ ?_) + obtain ⟨w, rfl⟩ := comap_surjective (Normal.isAlgebraic' (K := K)) w + simp only [mem_univ, forall_true_left, compl_filter, not_not, mem_filter, true_and] at hw + trans Finset.card (MulAction.orbit (K ≃ₐ[k] K) w).toFinset + · congr; ext w' + simp only [compl_filter, filter_congr_decidable, mem_filter, mem_univ, true_and, + @eq_comm _ (comap w' _), Set.mem_toFinset, mem_orbit_iff, and_iff_right_iff_imp] + intro e; rwa [← isUnramifiedIn_comap, ← e] + · rw [← MulAction.card_orbit_mul_card_stabilizer_eq_card_group _ w, + ← Nat.card_eq_fintype_card (α := Stab w), InfinitePlace.card_stabilizer, if_neg, + Nat.mul_div_cancel _ zero_lt_two, Set.toFinset_card] + rwa [← isUnramifiedIn_comap] + · simp [isUnramifiedIn_comap] + +lemma card_eq_card_isUnramifiedIn [NumberField k] [IsGalois k K] : + Fintype.card (InfinitePlace K) = + Finset.card (Finset.univ.filter <| IsUnramifiedIn K (k := k)) * finrank k K + + Finset.card (Finset.univ.filter <| IsUnramifiedIn K (k := k))ᶜ * (finrank k K / 2) := by + rw [← card_isUnramified, ← card_isUnramified_compl, Finset.card_add_card_compl] + end NumberField.InfinitePlace end InfinitePlace From be0b59d276020004e21109a79cab71f259755349 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Dec 2023 16:00:04 +0000 Subject: [PATCH 205/353] =?UTF-8?q?chore(*):=20use=20`=E2=88=80=20s=20?= =?UTF-8?q?=E2=8A=86=20t,=20=5F`=20etc=20(#9276)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes in this PR shouldn't change the public API. The only changes about `∃ x ∈ s, _` is inside a proof. Co-authored-by: Jeremy Tan Jie Rui --- Archive/Imo/Imo2021Q1.lean | 2 +- Mathlib/Algebra/Function/Support.lean | 2 +- Mathlib/Analysis/Calculus/TangentCone.lean | 2 +- .../Analysis/InnerProductSpace/Projection.lean | 5 ++--- Mathlib/Analysis/NormedSpace/lpSpace.lean | 5 ++--- .../Combinatorics/Additive/PluenneckeRuzsa.lean | 8 ++++---- Mathlib/Computability/Partrec.lean | 5 ++--- Mathlib/Computability/Primrec.lean | 5 ++--- Mathlib/Data/Nat/Prime.lean | 2 +- Mathlib/GroupTheory/Submonoid/Membership.lean | 2 +- Mathlib/GroupTheory/Subsemigroup/Membership.lean | 2 +- Mathlib/LinearAlgebra/Eigenspace/Basic.lean | 2 +- Mathlib/LinearAlgebra/LinearIndependent.lean | 2 +- Mathlib/MeasureTheory/Measure/VectorMeasure.lean | 2 +- .../NumberTheory/DiophantineApproximation.lean | 3 +-- Mathlib/RingTheory/DedekindDomain/Dvr.lean | 4 ++-- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 4 ++-- .../Category/TopCat/Limits/Cofiltered.lean | 2 +- Mathlib/Topology/Semicontinuous.lean | 16 ++++++++-------- Mathlib/Topology/ShrinkingLemma.lean | 2 +- 20 files changed, 36 insertions(+), 41 deletions(-) diff --git a/Archive/Imo/Imo2021Q1.lean b/Archive/Imo/Imo2021Q1.lean index dbb1f65c63224..3a56e305e2b2f 100644 --- a/Archive/Imo/Imo2021Q1.lean +++ b/Archive/Imo/Imo2021Q1.lean @@ -110,7 +110,7 @@ end Imo2021Q1 open Imo2021Q1 theorem imo2021_q1 : - ∀ n : ℕ, 100 ≤ n → ∀ (A) (_ : A ⊆ Finset.Icc n (2 * n)), + ∀ n : ℕ, 100 ≤ n → ∀ A ⊆ Finset.Icc n (2 * n), (∃ a ∈ A, ∃ b ∈ A, a ≠ b ∧ ∃ k : ℕ, a + b = k ^ 2) ∨ ∃ a ∈ Finset.Icc n (2 * n) \ A, ∃ b ∈ Finset.Icc n (2 * n) \ A, a ≠ b ∧ ∃ k : ℕ, a + b = k ^ 2 := by diff --git a/Mathlib/Algebra/Function/Support.lean b/Mathlib/Algebra/Function/Support.lean index dab474ff28353..7aa21a278e370 100644 --- a/Mathlib/Algebra/Function/Support.lean +++ b/Mathlib/Algebra/Function/Support.lean @@ -70,7 +70,7 @@ theorem mulSupport_subset_iff {f : α → M} {s : Set α} : mulSupport f ⊆ s @[to_additive] theorem mulSupport_subset_iff' {f : α → M} {s : Set α} : - mulSupport f ⊆ s ↔ ∀ (x) (_ : x ∉ s), f x = 1 := + mulSupport f ⊆ s ↔ ∀ x ∉ s, f x = 1 := forall_congr' fun _ => not_imp_comm #align function.mul_support_subset_iff' Function.mulSupport_subset_iff' #align function.support_subset_iff' Function.support_subset_iff' diff --git a/Mathlib/Analysis/Calculus/TangentCone.lean b/Mathlib/Analysis/Calculus/TangentCone.lean index f78ccdb03a5bd..34e2f39c5bbb6 100644 --- a/Mathlib/Analysis/Calculus/TangentCone.lean +++ b/Mathlib/Analysis/Calculus/TangentCone.lean @@ -184,7 +184,7 @@ theorem subset_tangentCone_prod_right {t : Set F} {y : F} (hs : x ∈ closure s) /-- The tangent cone of a product contains the tangent cone of each factor. -/ theorem mapsTo_tangentCone_pi {ι : Type*} [DecidableEq ι] {E : ι → Type*} [∀ i, NormedAddCommGroup (E i)] [∀ i, NormedSpace 𝕜 (E i)] {s : ∀ i, Set (E i)} {x : ∀ i, E i} - {i : ι} (hi : ∀ (j) (_ : j ≠ i), x j ∈ closure (s j)) : + {i : ι} (hi : ∀ j ≠ i, x j ∈ closure (s j)) : MapsTo (LinearMap.single i : E i →ₗ[𝕜] ∀ j, E j) (tangentConeAt 𝕜 (s i) (x i)) (tangentConeAt 𝕜 (Set.pi univ s) x) := by rintro w ⟨c, d, hd, hc, hy⟩ diff --git a/Mathlib/Analysis/InnerProductSpace/Projection.lean b/Mathlib/Analysis/InnerProductSpace/Projection.lean index fae9a45834782..9d301c71a6cf5 100644 --- a/Mathlib/Analysis/InnerProductSpace/Projection.lean +++ b/Mathlib/Analysis/InnerProductSpace/Projection.lean @@ -1387,7 +1387,7 @@ open FiniteDimensional Submodule Set /-- An orthonormal set in an `InnerProductSpace` is maximal, if and only if the orthogonal complement of its span is empty. -/ theorem maximal_orthonormal_iff_orthogonalComplement_eq_bot (hv : Orthonormal 𝕜 ((↑) : v → E)) : - (∀ (u) (_ : u ⊇ v), Orthonormal 𝕜 ((↑) : u → E) → u = v) ↔ (span 𝕜 v)ᗮ = ⊥ := by + (∀ u ⊇ v, Orthonormal 𝕜 ((↑) : u → E) → u = v) ↔ (span 𝕜 v)ᗮ = ⊥ := by rw [Submodule.eq_bot_iff] constructor · contrapose! @@ -1453,8 +1453,7 @@ variable [FiniteDimensional 𝕜 E] /-- An orthonormal set in a finite-dimensional `InnerProductSpace` is maximal, if and only if it is a basis. -/ theorem maximal_orthonormal_iff_basis_of_finiteDimensional (hv : Orthonormal 𝕜 ((↑) : v → E)) : - (∀ (u) (_ : u ⊇ v), Orthonormal 𝕜 ((↑) : u → E) → u = v) ↔ - ∃ b : Basis v 𝕜 E, ⇑b = ((↑) : v → E) := by + (∀ u ⊇ v, Orthonormal 𝕜 ((↑) : u → E) → u = v) ↔ ∃ b : Basis v 𝕜 E, ⇑b = ((↑) : v → E) := by haveI := proper_isROrC 𝕜 (span 𝕜 v) rw [maximal_orthonormal_iff_orthogonalComplement_eq_bot hv] rw [Submodule.orthogonal_eq_bot_iff] diff --git a/Mathlib/Analysis/NormedSpace/lpSpace.lean b/Mathlib/Analysis/NormedSpace/lpSpace.lean index b88d4fc8f2f99..4e63558c7b96c 100644 --- a/Mathlib/Analysis/NormedSpace/lpSpace.lean +++ b/Mathlib/Analysis/NormedSpace/lpSpace.lean @@ -185,7 +185,7 @@ theorem of_exponent_ge {p q : ℝ≥0∞} {f : ∀ i, E i} (hfq : Memℓp f q) ( · simp [hi] · exact (hC ⟨i, hi, rfl⟩).trans (le_max_right _ _) · apply memℓp_gen - have : ∀ (i) (_ : i ∉ hfq.finite_dsupport.toFinset), ‖f i‖ ^ p.toReal = 0 := by + have : ∀ i ∉ hfq.finite_dsupport.toFinset, ‖f i‖ ^ p.toReal = 0 := by intro i hi have : f i = 0 := by simpa using hi simp [this, Real.zero_rpow hp.ne'] @@ -1039,8 +1039,7 @@ protected theorem norm_sum_single (hp : 0 < p.toReal) (f : ∀ i, E i) (s : Fins ‖∑ i in s, lp.single p i (f i)‖ ^ p.toReal = ∑ i in s, ‖f i‖ ^ p.toReal := by refine' (hasSum_norm hp (∑ i in s, lp.single p i (f i))).unique _ simp only [lp.single_apply, coeFn_sum, Finset.sum_apply, Finset.sum_dite_eq] - have h : ∀ (i) (_ : i ∉ s), ‖ite (i ∈ s) (f i) 0‖ ^ p.toReal = 0 := by - intro i hi + have h : ∀ i ∉ s, ‖ite (i ∈ s) (f i) 0‖ ^ p.toReal = 0 := fun i hi ↦ by simp [if_neg hi, Real.zero_rpow hp.ne'] have h' : ∀ i ∈ s, ‖f i‖ ^ p.toReal = ‖ite (i ∈ s) (f i) 0‖ ^ p.toReal := by intro i hi diff --git a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean index c94eb43a1ace6..0b3eb306ed10f 100644 --- a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean +++ b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean @@ -87,7 +87,7 @@ theorem card_mul_mul_le_card_mul_mul_card_div (A B C : Finset α) : @[to_additive] theorem mul_pluennecke_petridis (C : Finset α) - (hA : ∀ (A') (_ : A' ⊆ A), (A * B).card * A'.card ≤ (A' * B).card * A.card) : + (hA : ∀ A' ⊆ A, (A * B).card * A'.card ≤ (A' * B).card * A.card) : (A * B * C).card * A.card ≤ (A * B).card * (A * C).card := by induction' C using Finset.induction_on with x C _ ih · simp @@ -123,7 +123,7 @@ theorem mul_pluennecke_petridis (C : Finset α) @[to_additive] private theorem mul_aux (hA : A.Nonempty) (hAB : A ⊆ B) (h : ∀ A' ∈ B.powerset.erase ∅, ((A * C).card : ℚ≥0) / ↑A.card ≤ (A' * C).card / ↑A'.card) : - ∀ (A') (_ : A' ⊆ A), (A * C).card * A'.card ≤ (A' * C).card * A.card := by + ∀ A' ⊆ A, (A * C).card * A'.card ≤ (A' * C).card * A.card := by rintro A' hAA' obtain rfl | hA' := A'.eq_empty_or_nonempty · simp @@ -180,7 +180,7 @@ theorem card_div_mul_le_card_div_mul_card_mul (A B C : Finset α) : #align finset.card_div_mul_le_card_div_mul_card_mul Finset.card_div_mul_le_card_div_mul_card_mul theorem card_add_nsmul_le {α : Type*} [AddCommGroup α] [DecidableEq α] {A B : Finset α} - (hAB : ∀ (A') (_ : A' ⊆ A), (A + B).card * A'.card ≤ (A' + B).card * A.card) (n : ℕ) : + (hAB : ∀ A' ⊆ A, (A + B).card * A'.card ≤ (A' + B).card * A.card) (n : ℕ) : (A + n • B).card ≤ ((A + B).card / A.card : ℚ≥0) ^ n * A.card := by obtain rfl | hA := A.eq_empty_or_nonempty · simp @@ -195,7 +195,7 @@ theorem card_add_nsmul_le {α : Type*} [AddCommGroup α] [DecidableEq α] {A B : #align finset.card_add_nsmul_le Finset.card_add_nsmul_le @[to_additive existing] -theorem card_mul_pow_le (hAB : ∀ (A') (_ : A' ⊆ A), (A * B).card * A'.card ≤ (A' * B).card * A.card) +theorem card_mul_pow_le (hAB : ∀ A' ⊆ A, (A * B).card * A'.card ≤ (A' * B).card * A.card) (n : ℕ) : (A * B ^ n).card ≤ ((A * B).card / A.card : ℚ≥0) ^ n * A.card := by obtain rfl | hA := A.eq_empty_or_nonempty · simp diff --git a/Mathlib/Computability/Partrec.lean b/Mathlib/Computability/Partrec.lean index 9c3c8dde19db6..e7e4130c6fe31 100644 --- a/Mathlib/Computability/Partrec.lean +++ b/Mathlib/Computability/Partrec.lean @@ -828,9 +828,8 @@ theorem fix_aux {α σ} (f : α →. Sum σ α) (a : α) (b : σ) : · cases' h₁ (Nat.lt_succ_self _) with a' h injection mem_unique h h₂ · exact this _ _ am' (PFun.mem_fix_iff.2 (Or.inl fa')) - · suffices - ∀ (a') (_ : b ∈ PFun.fix f a') (k) (_ : Sum.inr a' ∈ F a k), - ∃ n, Sum.inl b ∈ F a n ∧ ∀ m < n, ∀ (_ : k ≤ m), ∃ a₂, Sum.inr a₂ ∈ F a m by + · suffices ∀ a', b ∈ PFun.fix f a' → ∀ k, Sum.inr a' ∈ F a k → + ∃ n, Sum.inl b ∈ F a n ∧ ∀ m < n, k ≤ m → ∃ a₂, Sum.inr a₂ ∈ F a m by rcases this _ h 0 (by simp) with ⟨n, hn₁, hn₂⟩ exact ⟨_, ⟨⟨_, hn₁⟩, fun {m} mn => hn₂ m mn (Nat.zero_le _)⟩, hn₁⟩ intro a₁ h₁ diff --git a/Mathlib/Computability/Primrec.lean b/Mathlib/Computability/Primrec.lean index 09b38d22f97d7..eec9bbc1a0dcd 100644 --- a/Mathlib/Computability/Primrec.lean +++ b/Mathlib/Computability/Primrec.lean @@ -971,9 +971,8 @@ instance list : Primcodable (List α) := intro n IH; simp cases' @decode α _ n.unpair.1 with a; · rfl simp only [decode_eq_ofNat, Option.some.injEq, Option.some_bind, Option.map_some'] - suffices : - ∀ (o : Option (List ℕ)) (p) (_ : encode o = encode p), - encode (Option.map (List.cons (encode a)) o) = encode (Option.map (List.cons a) p) + suffices : ∀ (o : Option (List ℕ)) (p), encode o = encode p → + encode (Option.map (List.cons (encode a)) o) = encode (Option.map (List.cons a) p) exact this _ _ (IH _ (Nat.unpair_right_le n)) intro o p IH cases o <;> cases p diff --git a/Mathlib/Data/Nat/Prime.lean b/Mathlib/Data/Nat/Prime.lean index 52562e5efe8af..b0c086aa962c9 100644 --- a/Mathlib/Data/Nat/Prime.lean +++ b/Mathlib/Data/Nat/Prime.lean @@ -95,7 +95,7 @@ theorem Prime.eq_one_or_self_of_dvd {p : ℕ} (pp : p.Prime) (m : ℕ) (hm : m rw [hn, mul_one] #align nat.prime.eq_one_or_self_of_dvd Nat.Prime.eq_one_or_self_of_dvd -theorem prime_def_lt'' {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ (m) (_ : m ∣ p), m = 1 ∨ m = p := by +theorem prime_def_lt'' {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m, m ∣ p → m = 1 ∨ m = p := by refine' ⟨fun h => ⟨h.two_le, h.eq_one_or_self_of_dvd⟩, fun h => _⟩ -- Porting note: needed to make ℕ explicit have h1 := (@one_lt_two ℕ ..).trans_le h.1 diff --git a/Mathlib/GroupTheory/Submonoid/Membership.lean b/Mathlib/GroupTheory/Submonoid/Membership.lean index 65e5e5ce0cfdb..c815ce3f0b156 100644 --- a/Mathlib/GroupTheory/Submonoid/Membership.lean +++ b/Mathlib/GroupTheory/Submonoid/Membership.lean @@ -580,7 +580,7 @@ theorem map_powers {N : Type*} {F : Type*} [Monoid N] [MonoidHomClass F M N] (f @[to_additive "If all the elements of a set `s` commute, then `closure s` forms an additive commutative monoid."] -def closureCommMonoidOfComm {s : Set M} (hcomm : ∀ (a) (_ : a ∈ s) (b) (_ : b ∈ s), a * b = b * a) : +def closureCommMonoidOfComm {s : Set M} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : CommMonoid (closure s) := { (closure s).toMonoid with mul_comm := fun x y => by diff --git a/Mathlib/GroupTheory/Subsemigroup/Membership.lean b/Mathlib/GroupTheory/Subsemigroup/Membership.lean index a46be74b9a2c0..5fbf1f8cc37ad 100644 --- a/Mathlib/GroupTheory/Subsemigroup/Membership.lean +++ b/Mathlib/GroupTheory/Subsemigroup/Membership.lean @@ -119,7 +119,7 @@ then it holds for all elements of the supremum of `S`. -/ elements of `S i` for all `i`, and is preserved under addition, then it holds for all elements of the supremum of `S`."] theorem iSup_induction (S : ι → Subsemigroup M) {C : M → Prop} {x₁ : M} (hx₁ : x₁ ∈ ⨆ i, S i) - (hp : ∀ (i) (x₂ : M) (_hxS : x₂ ∈ S i), C x₂) (hmul : ∀ x y, C x → C y → C (x * y)) : C x₁ := by + (hp : ∀ i, ∀ x₂ ∈ S i, C x₂) (hmul : ∀ x y, C x → C y → C (x * y)) : C x₁ := by rw [iSup_eq_closure] at hx₁ refine' closure_induction hx₁ (fun x₂ hx₂ => _) hmul obtain ⟨i, hi⟩ := Set.mem_iUnion.mp hx₂ diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean index c5b30f32b3f3d..b0c4ba710772c 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean @@ -358,7 +358,7 @@ lemma injOn_generalizedEigenspace [NoZeroSMulDivisors R M] (f : End R M) : theorem independent_generalizedEigenspace [NoZeroSMulDivisors R M] (f : End R M) : CompleteLattice.Independent (fun μ ↦ ⨆ k, f.generalizedEigenspace μ k) := by classical - suffices ∀ μ (s : Finset R) (_ : μ ∉ s), Disjoint (⨆ k, f.generalizedEigenspace μ k) + suffices ∀ μ (s : Finset R), μ ∉ s → Disjoint (⨆ k, f.generalizedEigenspace μ k) (s.sup fun μ ↦ ⨆ k, f.generalizedEigenspace μ k) by simp_rw [CompleteLattice.independent_iff_supIndep_of_injOn f.injOn_generalizedEigenspace, Finset.supIndep_iff_disjoint_erase] diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index ce6061878003c..e2818f02d8c9b 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -1005,7 +1005,7 @@ theorem exists_maximal_independent' (s : ι → M) : theorem exists_maximal_independent (s : ι → M) : ∃ I : Set ι, (LinearIndependent R fun x : I => s x) ∧ - ∀ (i) (_ : i ∉ I), ∃ a : R, a ≠ 0 ∧ a • s i ∈ span R (s '' I) := by + ∀ i ∉ I, ∃ a : R, a ≠ 0 ∧ a • s i ∈ span R (s '' I) := by classical rcases exists_maximal_independent' R s with ⟨I, hIlinind, hImaximal⟩ use I, hIlinind diff --git a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean index 32f40dfef6f7e..065e55fffb0bf 100644 --- a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean @@ -1167,7 +1167,7 @@ namespace MutuallySingular variable {v v₁ v₂ : VectorMeasure α M} {w w₁ w₂ : VectorMeasure α N} theorem mk (s : Set α) (hs : MeasurableSet s) (h₁ : ∀ t ⊆ s, MeasurableSet t → v t = 0) - (h₂ : ∀ (t) (_ : t ⊆ sᶜ), MeasurableSet t → w t = 0) : v ⟂ᵥ w := by + (h₂ : ∀ t ⊆ sᶜ, MeasurableSet t → w t = 0) : v ⟂ᵥ w := by refine' ⟨s, hs, fun t hst => _, fun t hst => _⟩ <;> by_cases ht : MeasurableSet t · exact h₁ t hst ht · exact not_measurable v ht diff --git a/Mathlib/NumberTheory/DiophantineApproximation.lean b/Mathlib/NumberTheory/DiophantineApproximation.lean index 9ea505ff15bdf..f5af3c4ba8849 100644 --- a/Mathlib/NumberTheory/DiophantineApproximation.lean +++ b/Mathlib/NumberTheory/DiophantineApproximation.lean @@ -122,11 +122,10 @@ theorem exists_int_int_abs_mul_sub_le (ξ : ℝ) {n : ℕ} (n_pos : 0 < n) : have hwd : ∀ m : ℤ, m ∈ D → f m ∈ Ico (0 : ℤ) n := fun x hx => mem_Ico.mpr ⟨floor_nonneg.mpr (mul_nonneg (fract_nonneg (ξ * x)) hn.le), Ne.lt_of_le (H x hx) (hfu' x)⟩ - have : ∃ (x : ℤ) (_ : x ∈ D) (y : ℤ) (_ : y ∈ D), x < y ∧ f x = f y := by + obtain ⟨x, hx, y, hy, x_lt_y, hxy⟩ : ∃ x ∈ D, ∃ y ∈ D, x < y ∧ f x = f y := by obtain ⟨x, hx, y, hy, x_ne_y, hxy⟩ := exists_ne_map_eq_of_card_lt_of_maps_to hD hwd rcases lt_trichotomy x y with (h | h | h) exacts [⟨x, hx, y, hy, h, hxy⟩, False.elim (x_ne_y h), ⟨y, hy, x, hx, h, hxy.symm⟩] - obtain ⟨x, hx, y, hy, x_lt_y, hxy⟩ := this refine' ⟨⌊ξ * y⌋ - ⌊ξ * x⌋, y - x, sub_pos_of_lt x_lt_y, sub_le_iff_le_add.mpr <| le_add_of_le_of_nonneg (mem_Icc.mp hy).2 (mem_Icc.mp hx).1, _⟩ diff --git a/Mathlib/RingTheory/DedekindDomain/Dvr.lean b/Mathlib/RingTheory/DedekindDomain/Dvr.lean index 6dcbeb736b11c..b32fe71a7be3e 100644 --- a/Mathlib/RingTheory/DedekindDomain/Dvr.lean +++ b/Mathlib/RingTheory/DedekindDomain/Dvr.lean @@ -59,8 +59,8 @@ TODO: prove the equivalence. -/ structure IsDedekindDomainDvr : Prop where isNoetherianRing : IsNoetherianRing A - is_dvr_at_nonzero_prime : - ∀ (P) (_ : P ≠ (⊥ : Ideal A)) (_ : P.IsPrime), DiscreteValuationRing (Localization.AtPrime P) + is_dvr_at_nonzero_prime : ∀ P ≠ (⊥ : Ideal A), ∀ _ : P.IsPrime, + DiscreteValuationRing (Localization.AtPrime P) #align is_dedekind_domain_dvr IsDedekindDomainDvr /-- Localizing a domain of Krull dimension `≤ 1` gives another ring of Krull dimension `≤ 1`. diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 1be9caa7c604c..ed723c0b17f4a 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -245,7 +245,7 @@ assuming `IsDedekindDomain A`, which implies `IsDedekindDomainInv`. For **integr `IsDedekindDomain`(`_inv`) implies only `Ideal.cancelCommMonoidWithZero`. -/ def IsDedekindDomainInv : Prop := - ∀ (I) (_ : I ≠ (⊥ : FractionalIdeal A⁰ (FractionRing A))), I * I⁻¹ = 1 + ∀ I ≠ (⊥ : FractionalIdeal A⁰ (FractionRing A)), I * I⁻¹ = 1 #align is_dedekind_domain_inv IsDedekindDomainInv open FractionalIdeal @@ -253,7 +253,7 @@ open FractionalIdeal variable {R A K} theorem isDedekindDomainInv_iff [Algebra A K] [IsFractionRing A K] : - IsDedekindDomainInv A ↔ ∀ (I) (_ : I ≠ (⊥ : FractionalIdeal A⁰ K)), I * I⁻¹ = 1 := by + IsDedekindDomainInv A ↔ ∀ I ≠ (⊥ : FractionalIdeal A⁰ K), I * I⁻¹ = 1 := by let h : FractionalIdeal A⁰ (FractionRing A) ≃+* FractionalIdeal A⁰ K := FractionalIdeal.mapEquiv (FractionRing.algEquiv A K) refine h.toEquiv.forall_congr (fun {x} => ?_) diff --git a/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean b/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean index 1f342f7f6693b..fac47af6971ac 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Cofiltered.lean @@ -76,7 +76,7 @@ theorem isTopologicalBasis_cofiltered_limit (T : ∀ j, Set (Set (F.obj j))) · simp · rintro ⟨U, G, h1, h2⟩ obtain ⟨j, hj⟩ := IsCofiltered.inf_objs_exists G - let g : ∀ (e) (_he : e ∈ G), j ⟶ e := fun _ he => (hj he).some + let g : ∀ e ∈ G, j ⟶ e := fun _ he => (hj he).some let Vs : J → Set (F.obj j) := fun e => if h : e ∈ G then F.map (g e h) ⁻¹' U e else Set.univ let V : Set (F.obj j) := ⋂ (e : J) (_he : e ∈ G), Vs e refine' ⟨j, V, _, _⟩ diff --git a/Mathlib/Topology/Semicontinuous.lean b/Mathlib/Topology/Semicontinuous.lean index 4ca4fa36d269f..7e7a6811d6e86 100644 --- a/Mathlib/Topology/Semicontinuous.lean +++ b/Mathlib/Topology/Semicontinuous.lean @@ -564,7 +564,7 @@ theorem lowerSemicontinuousWithinAt_iSup {f : ι → α → δ} lowerSemicontinuousWithinAt_ciSup (by simp) h #align lower_semicontinuous_within_at_supr lowerSemicontinuousWithinAt_iSup -theorem lowerSemicontinuousWithinAt_biSup {p : ι → Prop} {f : ∀ (i) (_h : p i), α → δ} +theorem lowerSemicontinuousWithinAt_biSup {p : ι → Prop} {f : ∀ i, p i → α → δ} (h : ∀ i hi, LowerSemicontinuousWithinAt (f i hi) s x) : LowerSemicontinuousWithinAt (fun x' => ⨆ (i) (hi), f i hi x') s x := lowerSemicontinuousWithinAt_iSup fun i => lowerSemicontinuousWithinAt_iSup fun hi => h i hi @@ -583,7 +583,7 @@ theorem lowerSemicontinuousAt_iSup {f : ι → α → δ} (h : ∀ i, LowerSemic lowerSemicontinuousAt_ciSup (by simp) h #align lower_semicontinuous_at_supr lowerSemicontinuousAt_iSup -theorem lowerSemicontinuousAt_biSup {p : ι → Prop} {f : ∀ (i) (_h : p i), α → δ} +theorem lowerSemicontinuousAt_biSup {p : ι → Prop} {f : ∀ i, p i → α → δ} (h : ∀ i hi, LowerSemicontinuousAt (f i hi) x) : LowerSemicontinuousAt (fun x' => ⨆ (i) (hi), f i hi x') x := lowerSemicontinuousAt_iSup fun i => lowerSemicontinuousAt_iSup fun hi => h i hi @@ -600,7 +600,7 @@ theorem lowerSemicontinuousOn_iSup {f : ι → α → δ} (h : ∀ i, LowerSemic lowerSemicontinuousOn_ciSup (by simp) h #align lower_semicontinuous_on_supr lowerSemicontinuousOn_iSup -theorem lowerSemicontinuousOn_biSup {p : ι → Prop} {f : ∀ (i) (_h : p i), α → δ} +theorem lowerSemicontinuousOn_biSup {p : ι → Prop} {f : ∀ i, p i → α → δ} (h : ∀ i hi, LowerSemicontinuousOn (f i hi) s) : LowerSemicontinuousOn (fun x' => ⨆ (i) (hi), f i hi x') s := lowerSemicontinuousOn_iSup fun i => lowerSemicontinuousOn_iSup fun hi => h i hi @@ -616,7 +616,7 @@ theorem lowerSemicontinuous_iSup {f : ι → α → δ} (h : ∀ i, LowerSemicon lowerSemicontinuous_ciSup (by simp) h #align lower_semicontinuous_supr lowerSemicontinuous_iSup -theorem lowerSemicontinuous_biSup {p : ι → Prop} {f : ∀ (i) (_h : p i), α → δ} +theorem lowerSemicontinuous_biSup {p : ι → Prop} {f : ∀ i, p i → α → δ} (h : ∀ i hi, LowerSemicontinuous (f i hi)) : LowerSemicontinuous fun x' => ⨆ (i) (hi), f i hi x' := lowerSemicontinuous_iSup fun i => lowerSemicontinuous_iSup fun hi => h i hi @@ -1006,7 +1006,7 @@ theorem upperSemicontinuousWithinAt_iInf {f : ι → α → δ} @lowerSemicontinuousWithinAt_iSup α _ x s ι δᵒᵈ _ f h #align upper_semicontinuous_within_at_infi upperSemicontinuousWithinAt_iInf -theorem upperSemicontinuousWithinAt_biInf {p : ι → Prop} {f : ∀ (i) (_h : p i), α → δ} +theorem upperSemicontinuousWithinAt_biInf {p : ι → Prop} {f : ∀ i, p i → α → δ} (h : ∀ i hi, UpperSemicontinuousWithinAt (f i hi) s x) : UpperSemicontinuousWithinAt (fun x' => ⨅ (i) (hi), f i hi x') s x := upperSemicontinuousWithinAt_iInf fun i => upperSemicontinuousWithinAt_iInf fun hi => h i hi @@ -1023,7 +1023,7 @@ theorem upperSemicontinuousAt_iInf {f : ι → α → δ} (h : ∀ i, UpperSemic @lowerSemicontinuousAt_iSup α _ x ι δᵒᵈ _ f h #align upper_semicontinuous_at_infi upperSemicontinuousAt_iInf -theorem upperSemicontinuousAt_biInf {p : ι → Prop} {f : ∀ (i) (_h : p i), α → δ} +theorem upperSemicontinuousAt_biInf {p : ι → Prop} {f : ∀ i, p i → α → δ} (h : ∀ i hi, UpperSemicontinuousAt (f i hi) x) : UpperSemicontinuousAt (fun x' => ⨅ (i) (hi), f i hi x') x := upperSemicontinuousAt_iInf fun i => upperSemicontinuousAt_iInf fun hi => h i hi @@ -1040,7 +1040,7 @@ theorem upperSemicontinuousOn_iInf {f : ι → α → δ} (h : ∀ i, UpperSemic upperSemicontinuousWithinAt_iInf fun i => h i x hx #align upper_semicontinuous_on_infi upperSemicontinuousOn_iInf -theorem upperSemicontinuousOn_biInf {p : ι → Prop} {f : ∀ (i) (_h : p i), α → δ} +theorem upperSemicontinuousOn_biInf {p : ι → Prop} {f : ∀ i, p i → α → δ} (h : ∀ i hi, UpperSemicontinuousOn (f i hi) s) : UpperSemicontinuousOn (fun x' => ⨅ (i) (hi), f i hi x') s := upperSemicontinuousOn_iInf fun i => upperSemicontinuousOn_iInf fun hi => h i hi @@ -1055,7 +1055,7 @@ theorem upperSemicontinuous_iInf {f : ι → α → δ} (h : ∀ i, UpperSemicon UpperSemicontinuous fun x' => ⨅ i, f i x' := fun x => upperSemicontinuousAt_iInf fun i => h i x #align upper_semicontinuous_infi upperSemicontinuous_iInf -theorem upperSemicontinuous_biInf {p : ι → Prop} {f : ∀ (i) (_h : p i), α → δ} +theorem upperSemicontinuous_biInf {p : ι → Prop} {f : ∀ i, p i → α → δ} (h : ∀ i hi, UpperSemicontinuous (f i hi)) : UpperSemicontinuous fun x' => ⨅ (i) (hi), f i hi x' := upperSemicontinuous_iInf fun i => upperSemicontinuous_iInf fun hi => h i hi diff --git a/Mathlib/Topology/ShrinkingLemma.lean b/Mathlib/Topology/ShrinkingLemma.lean index 768d8e28e0227..9339ed5884f62 100644 --- a/Mathlib/Topology/ShrinkingLemma.lean +++ b/Mathlib/Topology/ShrinkingLemma.lean @@ -185,7 +185,7 @@ theorem exists_gt (v : PartialRefinement u s) (hs : IsClosed s) (i : ι) (hi : i · intro j rcases eq_or_ne j i with (rfl| hne) <;> simp [*, v.isOpen] · refine' fun x hx => mem_iUnion.2 _ - rcases em (∃ (j : _) (_ : j ≠ i), x ∈ v j) with (⟨j, hji, hj⟩ | h) + rcases em (∃ j ≠ i, x ∈ v j) with (⟨j, hji, hj⟩ | h) · use j rwa [update_noteq hji] · push_neg at h From e62554d20db4062cf7dd9ad01990cabf59167e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 19:32:16 +0000 Subject: [PATCH 206/353] feat: Basic probability lemmas assuming null-measurability (#9222) and transferring probabiity measures across `ULift` From LeanCamCombi and PFR --- .../MeasureTheory/Measure/Typeclasses.lean | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/Mathlib/MeasureTheory/Measure/Typeclasses.lean b/Mathlib/MeasureTheory/Measure/Typeclasses.lean index bc3dacabea3b3..fcc5f1ddc700f 100644 --- a/Mathlib/MeasureTheory/Measure/Typeclasses.lean +++ b/Mathlib/MeasureTheory/Measure/Typeclasses.lean @@ -251,35 +251,47 @@ instance isProbabilityMeasureSMul [IsFiniteMeasure μ] [NeZero μ] : ⟨ENNReal.inv_mul_cancel (NeZero.ne (μ univ)) (measure_ne_top _ _)⟩ #align measure_theory.is_probability_measure_smul MeasureTheory.isProbabilityMeasureSMulₓ -theorem isProbabilityMeasure_map [IsProbabilityMeasure μ] {f : α → β} (hf : AEMeasurable f μ) : +variable [IsProbabilityMeasure μ] {p : α → Prop} {f : β → α} + +theorem isProbabilityMeasure_map {f : α → β} (hf : AEMeasurable f μ) : IsProbabilityMeasure (map f μ) := ⟨by simp [map_apply_of_aemeasurable, hf]⟩ #align measure_theory.is_probability_measure_map MeasureTheory.isProbabilityMeasure_map @[simp] -theorem one_le_prob_iff [IsProbabilityMeasure μ] : 1 ≤ μ s ↔ μ s = 1 := +theorem one_le_prob_iff : 1 ≤ μ s ↔ μ s = 1 := ⟨fun h => le_antisymm prob_le_one h, fun h => h ▸ le_refl _⟩ #align measure_theory.one_le_prob_iff MeasureTheory.one_le_prob_iff /-- Note that this is not quite as useful as it looks because the measure takes values in `ℝ≥0∞`. Thus the subtraction appearing is the truncated subtraction of `ℝ≥0∞`, rather than the better-behaved subtraction of `ℝ`. -/ -theorem prob_compl_eq_one_sub [IsProbabilityMeasure μ] (hs : MeasurableSet s) : μ sᶜ = 1 - μ s := - by simpa only [measure_univ] using measure_compl hs (measure_lt_top μ s).ne +lemma prob_compl_eq_one_sub₀ (h : NullMeasurableSet s μ) : μ sᶜ = 1 - μ s := by + rw [measure_compl₀ h (measure_ne_top _ _), measure_univ] + +/-- Note that this is not quite as useful as it looks because the measure takes values in `ℝ≥0∞`. +Thus the subtraction appearing is the truncated subtraction of `ℝ≥0∞`, rather than the +better-behaved subtraction of `ℝ`. -/ +theorem prob_compl_eq_one_sub (hs : MeasurableSet s) : μ sᶜ = 1 - μ s := + prob_compl_eq_one_sub₀ hs.nullMeasurableSet #align measure_theory.prob_compl_eq_one_sub MeasureTheory.prob_compl_eq_one_sub -@[simp] -theorem prob_compl_eq_zero_iff [IsProbabilityMeasure μ] (hs : MeasurableSet s) : - μ sᶜ = 0 ↔ μ s = 1 := by - rw [prob_compl_eq_one_sub hs, tsub_eq_zero_iff_le, one_le_prob_iff] +@[simp] lemma prob_compl_eq_zero_iff₀ (hs : NullMeasurableSet s μ) : μ sᶜ = 0 ↔ μ s = 1 := by + rw [prob_compl_eq_one_sub₀ hs, tsub_eq_zero_iff_le, one_le_prob_iff] + +@[simp] lemma prob_compl_eq_zero_iff (hs : MeasurableSet s) : μ sᶜ = 0 ↔ μ s = 1 := + prob_compl_eq_zero_iff₀ hs.nullMeasurableSet #align measure_theory.prob_compl_eq_zero_iff MeasureTheory.prob_compl_eq_zero_iff -@[simp] -theorem prob_compl_eq_one_iff [IsProbabilityMeasure μ] (hs : MeasurableSet s) : - μ sᶜ = 1 ↔ μ s = 0 := by rw [← prob_compl_eq_zero_iff hs.compl, compl_compl] +@[simp] lemma prob_compl_eq_one_iff₀ (hs : NullMeasurableSet s μ) : μ sᶜ = 1 ↔ μ s = 0 := by + rw [← prob_compl_eq_zero_iff₀ hs.compl, compl_compl] + +@[simp] lemma prob_compl_eq_one_iff (hs : MeasurableSet s) : μ sᶜ = 1 ↔ μ s = 0 := + prob_compl_eq_one_iff₀ hs.nullMeasurableSet #align measure_theory.prob_compl_eq_one_iff MeasureTheory.prob_compl_eq_one_iff -variable [IsProbabilityMeasure μ] {p : α → Prop} {f : β → α} +lemma mem_ae_iff_prob_eq_one₀ (hs : NullMeasurableSet s μ) : s ∈ μ.ae ↔ μ s = 1 := + mem_ae_iff.trans $ prob_compl_eq_zero_iff₀ hs lemma mem_ae_iff_prob_eq_one (hs : MeasurableSet s) : s ∈ μ.ae ↔ μ s = 1 := mem_ae_iff.trans $ prob_compl_eq_zero_iff hs @@ -299,6 +311,14 @@ protected lemma _root_.MeasurableEmbedding.isProbabilityMeasure_comap (hf : Meas (hf' : ∀ᵐ a ∂μ, a ∈ range f) : IsProbabilityMeasure (μ.comap f) := isProbabilityMeasure_comap hf.injective hf' hf.measurableSet_image' +instance isProbabilityMeasure_map_up [IsProbabilityMeasure μ] : + IsProbabilityMeasure (μ.map ULift.up) := isProbabilityMeasure_map measurable_up.aemeasurable + +instance isProbabilityMeasure_comap_down [IsProbabilityMeasure μ] : + IsProbabilityMeasure (μ.comap ULift.down) := + MeasurableEquiv.ulift.measurableEmbedding.isProbabilityMeasure_comap <| ae_of_all _ <| by + simp [Function.Surjective.range_eq <| EquivLike.surjective _] + end IsProbabilityMeasure section NoAtoms From fae2023047641e473313c6a2939ff2ed38489862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 20:26:20 +0000 Subject: [PATCH 207/353] =?UTF-8?q?chore:=20Make=20Szem=C3=A9redi=20regula?= =?UTF-8?q?rity=20calculation=20more=20readable=20(#9284)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit by using `calc`, `gcongr` and `positivity`. This should be much more maintainable now. Nicely enough, this reduces the total number of lines. --- .../SimpleGraph/Regularity/Bound.lean | 3 + .../SimpleGraph/Regularity/Increment.lean | 154 ++++++++---------- .../SimpleGraph/Regularity/Lemma.lean | 6 +- 3 files changed, 78 insertions(+), 85 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean index c26f2522c11c7..0d5b6573704be 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean @@ -56,6 +56,9 @@ theorem stepBound_pos_iff {n : ℕ} : 0 < stepBound n ↔ 0 < n := alias ⟨_, stepBound_pos⟩ := stepBound_pos_iff #align szemeredi_regularity.step_bound_pos SzemerediRegularity.stepBound_pos +@[norm_cast] lemma coe_stepBound {α : Type*} [Semiring α] (n : ℕ) : + (stepBound n : α) = n * 4 ^ n := by unfold stepBound; norm_cast + end SzemerediRegularity open SzemerediRegularity diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean index 0be6b52ec2371..6d8628c353e76 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean @@ -86,112 +86,102 @@ theorem increment_isEquipartition (hP : P.IsEquipartition) (G : SimpleGraph α) exact card_eq_of_mem_parts_chunk hA #align szemeredi_regularity.increment_is_equipartition SzemerediRegularity.increment_isEquipartition -private theorem distinct_pairs_increment : - (P.parts.offDiag.attach.biUnion fun UV => - (chunk hP G ε (mem_offDiag.1 UV.2).1).parts ×ˢ - (chunk hP G ε (mem_offDiag.1 UV.2).2.1).parts) ⊆ - (increment hP G ε).parts.offDiag := by +/-- The contribution to `Finpartition.energy` of a pair of distinct parts of a `Finpartition`. -/ +private noncomputable def distinctPairs (G : SimpleGraph α) (ε : ℝ) (hP : P.IsEquipartition) + (x : {x // x ∈ P.parts.offDiag}) : Finset (Finset α × Finset α) := + (chunk hP G ε (mem_offDiag.1 x.2).1).parts ×ˢ (chunk hP G ε (mem_offDiag.1 x.2).2.1).parts + +private theorem distinctPairs_increment : + P.parts.offDiag.attach.biUnion (distinctPairs G ε hP) ⊆ (increment hP G ε).parts.offDiag := by rintro ⟨Ui, Vj⟩ - simp only [increment, mem_offDiag, bind_parts, mem_biUnion, Prod.exists, exists_and_left, - exists_prop, mem_product, mem_attach, true_and_iff, Subtype.exists, and_imp, mem_offDiag, - forall_exists_index, bex_imp, Ne.def] + simp only [distinctPairs, increment, mem_offDiag, bind_parts, mem_biUnion, Prod.exists, + exists_and_left, exists_prop, mem_product, mem_attach, true_and_iff, Subtype.exists, and_imp, + mem_offDiag, forall_exists_index, bex_imp, Ne.def] refine' fun U V hUV hUi hVj => ⟨⟨_, hUV.1, hUi⟩, ⟨_, hUV.2.1, hVj⟩, _⟩ rintro rfl obtain ⟨i, hi⟩ := nonempty_of_mem_parts _ hUi exact hUV.2.2 (P.disjoint.elim_finset hUV.1 hUV.2.1 i (Finpartition.le _ hUi hi) <| Finpartition.le _ hVj hi) -/-- The contribution to `Finpartition.energy` of a pair of distinct parts of a `Finpartition`. -/ -private noncomputable def pairContrib (G : SimpleGraph α) (ε : ℝ) (hP : P.IsEquipartition) - (x : { x // x ∈ P.parts.offDiag }) : ℚ := - ∑ i in (chunk hP G ε (mem_offDiag.1 x.2).1).parts ×ˢ (chunk hP G ε (mem_offDiag.1 x.2).2.1).parts, - (G.edgeDensity i.fst i.snd : ℚ) ^ 2 - -theorem offDiag_pairs_le_increment_energy : - ∑ x in P.parts.offDiag.attach, pairContrib G ε hP x / ((increment hP G ε).parts.card : ℚ) ^ 2 ≤ - (increment hP G ε).energy G := by - simp_rw [pairContrib, ← sum_div] - refine' div_le_div_of_le_of_nonneg (α := ℚ) _ (sq_nonneg _) - rw [← sum_biUnion] - · exact sum_le_sum_of_subset_of_nonneg distinct_pairs_increment fun i _ _ => sq_nonneg _ - simp (config := { unfoldPartialApp := true }) only [Set.PairwiseDisjoint, Function.onFun, - disjoint_left, inf_eq_inter, mem_inter, mem_product] +private lemma pairwiseDisjoint_distinctPairs : + (P.parts.offDiag.attach : Set {x // x ∈ P.parts.offDiag}).PairwiseDisjoint + (distinctPairs G ε hP) := by + simp (config := { unfoldPartialApp := true }) only [distinctPairs, Set.PairwiseDisjoint, + Function.onFun, disjoint_left, inf_eq_inter, mem_inter, mem_product] rintro ⟨⟨s₁, s₂⟩, hs⟩ _ ⟨⟨t₁, t₂⟩, ht⟩ _ hst ⟨u, v⟩ huv₁ huv₂ rw [mem_offDiag] at hs ht obtain ⟨a, ha⟩ := Finpartition.nonempty_of_mem_parts _ huv₁.1 obtain ⟨b, hb⟩ := Finpartition.nonempty_of_mem_parts _ huv₁.2 - exact hst (Subtype.ext_val <| Prod.ext + exact hst $ Subtype.ext_val <| Prod.ext (P.disjoint.elim_finset hs.1 ht.1 a (Finpartition.le _ huv₁.1 ha) <| Finpartition.le _ huv₂.1 ha) <| P.disjoint.elim_finset hs.2.1 ht.2.1 b (Finpartition.le _ huv₁.2 hb) <| - Finpartition.le _ huv₂.2 hb) -#align szemeredi_regularity.off_diag_pairs_le_increment_energy SzemerediRegularity.offDiag_pairs_le_increment_energy + Finpartition.le _ huv₂.2 hb -theorem pairContrib_lower_bound [Nonempty α] (x : { i // i ∈ P.parts.offDiag }) (hε₁ : ε ≤ 1) +variable [Nonempty α] + +lemma le_sum_distinctPairs_edgeDensity_sq (x : {i // i ∈ P.parts.offDiag}) (hε₁ : ε ≤ 1) (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) : - ((G.edgeDensity x.1.1 x.1.2 : ℝ) ^ 2 - ε ^ 5 / ↑25 + - if G.IsUniform ε x.1.1 x.1.2 then (0 : ℝ) else ε ^ 4 / 3) ≤ - pairContrib G ε hP x / ↑16 ^ P.parts.card := by - rw [pairContrib] + (G.edgeDensity x.1.1 x.1.2 : ℝ) ^ 2 + + ((if G.IsUniform ε x.1.1 x.1.2 then 0 else ε ^ 4 / 3) - ε ^ 5 / 25) ≤ + (∑ i in distinctPairs G ε hP x, G.edgeDensity i.1 i.2 ^ 2 : ℝ) / 16 ^ P.parts.card := by + rw [distinctPairs, ← add_sub_assoc, add_sub_right_comm] push_cast split_ifs with h · rw [add_zero] exact edgeDensity_chunk_uniform hPα hPε _ _ · exact edgeDensity_chunk_not_uniform hPα hPε hε₁ (mem_offDiag.1 x.2).2.2 h -#align szemeredi_regularity.pair_contrib_lower_bound SzemerediRegularity.pairContrib_lower_bound - -theorem uniform_add_nonuniform_eq_offDiag_pairs [Nonempty α] (hε₁ : ε ≤ 1) (hP₇ : 7 ≤ P.parts.card) - (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) - (hPG : ¬P.IsUniform G ε) : - (∑ x in P.parts.offDiag, (G.edgeDensity x.1 x.2 : ℝ) ^ 2 + - ↑P.parts.card ^ 2 * (ε ^ 5 / 4) : ℝ) / (P.parts.card : ℝ) ^ 2 ≤ - ∑ x in P.parts.offDiag.attach, - (pairContrib G ε hP x : ℝ) / ((increment hP G ε).parts.card : ℝ) ^ 2 := by - conv_rhs => - rw [← sum_div, card_increment hPα hPG, stepBound, ← Nat.cast_pow, mul_pow, pow_right_comm, - Nat.cast_mul, mul_comm, ← div_div, show 4 ^ 2 = 16 by norm_num, sum_div] - rw [← Nat.cast_pow, Nat.cast_pow 16] - refine' div_le_div_of_le_of_nonneg _ (Nat.cast_nonneg _) - norm_num - trans ∑ x in P.parts.offDiag.attach, ((G.edgeDensity x.1.1 x.1.2 : ℝ) ^ 2 - ε ^ 5 / ↑25 + - if G.IsUniform ε x.1.1 x.1.2 then (0 : ℝ) else ε ^ 4 / 3 : ℝ) - swap - · exact sum_le_sum fun i _ => pairContrib_lower_bound i hε₁ hPα hPε - have : - ∑ x in P.parts.offDiag.attach, ((G.edgeDensity x.1.1 x.1.2 : ℝ) ^ 2 - ε ^ 5 / ↑25 + - if G.IsUniform ε x.1.1 x.1.2 then (0 : ℝ) else ε ^ 4 / 3 : ℝ) = - ∑ x in P.parts.offDiag, ((G.edgeDensity x.1 x.2 : ℝ) ^ 2 - ε ^ 5 / ↑25 + - if G.IsUniform ε x.1 x.2 then (0 : ℝ) else ε ^ 4 / 3) := by - convert sum_attach (β := ℝ); rfl - rw [this, sum_add_distrib, sum_sub_distrib, sum_const, nsmul_eq_mul, sum_ite, sum_const_zero, - zero_add, sum_const, nsmul_eq_mul, ← Finpartition.nonUniforms] - rw [Finpartition.IsUniform, not_le] at hPG - refine' le_trans _ (add_le_add_left (mul_le_mul_of_nonneg_right hPG.le <| by positivity) _) - conv_rhs => - enter [1, 2] - rw [offDiag_card] - conv => enter [1, 1, 2]; rw [← mul_one P.parts.card] - rw [← Nat.mul_sub_left_distrib] - simp_rw [mul_assoc, sub_add_eq_add_sub, add_sub_assoc, ← mul_sub_left_distrib, mul_div_assoc' ε, - ← pow_succ, show 4 + 1 = 5 by rfl, div_eq_mul_one_div (ε ^ 5), ← mul_sub_left_distrib, - mul_left_comm _ (ε ^ 5), sq, Nat.cast_mul, mul_assoc, ← mul_assoc (ε ^ 5)] - refine' add_le_add_left (mul_le_mul_of_nonneg_left _ <| by sz_positivity) _ - rw [Nat.cast_sub (P.parts_nonempty <| univ_nonempty.ne_empty).card_pos, mul_sub_right_distrib, - Nat.cast_one, one_mul, le_sub_comm, ← mul_sub_left_distrib, ← - div_le_iff (show (0 : ℝ) < 1 / 3 - 1 / 25 - 1 / 4 by norm_num)] - exact le_trans (show _ ≤ (7 : ℝ) by norm_num) (mod_cast hP₇) -#align szemeredi_regularity.uniform_add_nonuniform_eq_off_diag_pairs SzemerediRegularity.uniform_add_nonuniform_eq_offDiag_pairs +#align szemeredi_regularity.pair_contrib_lower_bound SzemerediRegularity.le_sum_distinctPairs_edgeDensity_sq + +#noalign szemeredi_regularity.off_diag_pairs_le_increment_energy +#noalign szemeredi_regularity.uniform_add_nonuniform_eq_off_diag_pairs /-- The increment partition has energy greater than the original one by a known fixed amount. -/ -theorem energy_increment [Nonempty α] (hP : P.IsEquipartition) (hP₇ : 7 ≤ P.parts.card) - (hε : ↑100 < ↑4 ^ P.parts.card * ε ^ 5) (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) - (hPG : ¬P.IsUniform G ε) (hε₁ : ε ≤ 1) : +theorem energy_increment (hP : P.IsEquipartition) (hP₇ : 7 ≤ P.parts.card) + (hPε : 100 ≤ 4 ^ P.parts.card * ε ^ 5) (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) + (hPG : ¬P.IsUniform G ε) (hε₀ : 0 ≤ ε) (hε₁ : ε ≤ 1) : ↑(P.energy G) + ε ^ 5 / 4 ≤ (increment hP G ε).energy G := by - rw [coe_energy] - have h := uniform_add_nonuniform_eq_offDiag_pairs (hP := hP) hε₁ hP₇ hPα hε.le hPG - rw [add_div, mul_div_cancel_left] at h - exact h.trans (mod_cast offDiag_pairs_le_increment_energy) - positivity + calc + _ = (∑ x in P.parts.offDiag, (G.edgeDensity x.1 x.2 : ℝ) ^ 2 + + P.parts.card ^ 2 * (ε ^ 5 / 4) : ℝ) / P.parts.card ^ 2 := by + rw [coe_energy, add_div, mul_div_cancel_left]; positivity + _ ≤ (∑ x in P.parts.offDiag.attach, (∑ i in distinctPairs G ε hP x, + G.edgeDensity i.1 i.2 ^ 2 : ℝ) / 16 ^ P.parts.card) / P.parts.card ^ 2 := + div_le_div_of_le_of_nonneg ?_ $ by positivity + _ = (∑ x in P.parts.offDiag.attach, ∑ i in distinctPairs G ε hP x, + G.edgeDensity i.1 i.2 ^ 2 : ℝ) / (increment hP G ε).parts.card ^ 2 := by + rw [card_increment hPα hPG, coe_stepBound, mul_pow, pow_right_comm, + div_mul_eq_div_div_swap, ← sum_div]; norm_num + _ ≤ _ := by + rw [coe_energy] + gcongr + rw [← sum_biUnion pairwiseDisjoint_distinctPairs] + exact sum_le_sum_of_subset_of_nonneg distinctPairs_increment fun i _ _ ↦ sq_nonneg _ + rw [Finpartition.IsUniform, not_le, mul_tsub, mul_one, ← offDiag_card] at hPG + calc + _ ≤ ∑ x in P.parts.offDiag, (edgeDensity G x.1 x.2 : ℝ) ^ 2 + + ((nonUniforms P G ε).card * (ε ^ 4 / 3) - P.parts.offDiag.card * (ε ^ 5 / 25)) := + add_le_add_left ?_ _ + _ = ∑ x in P.parts.offDiag, ((G.edgeDensity x.1 x.2 : ℝ) ^ 2 + + ((if G.IsUniform ε x.1 x.2 then (0 : ℝ) else ε ^ 4 / 3) - ε ^ 5 / 25) : ℝ) := by + rw [sum_add_distrib, sum_sub_distrib, sum_const, nsmul_eq_mul, sum_ite, sum_const_zero, + zero_add, sum_const, nsmul_eq_mul, ← Finpartition.nonUniforms, ← add_sub_assoc, + add_sub_right_comm] + _ = _ := (sum_attach ..).symm + _ ≤ _ := sum_le_sum fun i _ ↦ le_sum_distinctPairs_edgeDensity_sq i hε₁ hPα hPε + calc + _ = (6/7 * P.parts.card ^ 2) * ε ^ 5 * (7 / 24) := by ring + _ ≤ P.parts.offDiag.card * ε ^ 5 * (22 / 75) := by + gcongr ?_ * _ * ?_ + · rw [← mul_div_right_comm, div_le_iff (by norm_num), offDiag_card] + norm_cast + rw [tsub_mul] + refine le_tsub_of_add_le_left ?_ + nlinarith + · norm_num + _ = (P.parts.offDiag.card * ε * (ε ^ 4 / 3) - P.parts.offDiag.card * (ε ^ 5 / 25)) := by ring + _ ≤ ((nonUniforms P G ε).card * (ε ^ 4 / 3) - P.parts.offDiag.card * (ε ^ 5 / 25)) := by + gcongr #align szemeredi_regularity.energy_increment SzemerediRegularity.energy_increment end SzemerediRegularity diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean index caad9b8ea7bf5..f2a4ce0a2ce0a 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean @@ -129,8 +129,8 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : -- Else, `P` must instead have energy at least `ε ^ 5 / 4 * i`. replace hP₄ := hP₄.resolve_left huniform -- We gather a few numerical facts. - have hεl' : ↑100 < ↑4 ^ P.parts.card * ε ^ 5 := - (hundred_lt_pow_initialBound_mul hε l).trans_le + have hεl' : 100 ≤ 4 ^ P.parts.card * ε ^ 5 := + (hundred_lt_pow_initialBound_mul hε l).le.trans (mul_le_mul_of_nonneg_right (pow_le_pow_right (by norm_num) hP₂) <| by positivity) have hi : (i : ℝ) ≤ 4 / ε ^ 5 := by have hi : ε ^ 5 / 4 * ↑i ≤ 1 := hP₄.trans (mod_cast P.energy_le_one G) @@ -143,7 +143,7 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : (Nat.mul_le_mul hsize (Nat.pow_le_pow_of_le_right (by norm_num) hsize)).trans hα -- We return the increment equipartition of `P`, which has energy `≥ ε ^ 5 / 4 * (i + 1)`. refine' ⟨increment hP₁ G ε, increment_isEquipartition hP₁ G ε, _, _, Or.inr <| le_trans _ <| - energy_increment hP₁ ((seven_le_initialBound ε l).trans hP₂) hεl' hPα huniform hε₁⟩ + energy_increment hP₁ ((seven_le_initialBound ε l).trans hP₂) hεl' hPα huniform hε.le hε₁⟩ · rw [card_increment hPα huniform] exact hP₂.trans (le_stepBound _) · rw [card_increment hPα huniform, iterate_succ_apply'] From a8d482d3b7314f4cc1f9444109cc61e515dcc98d Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Tue, 26 Dec 2023 20:50:31 +0000 Subject: [PATCH 208/353] docs: kmill update areas (#9289) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f999f423cac1d..70894697a7fd2 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ For a list containing more detailed information, see https://leanprover-communit * Heather Macbeth (@hrmacbeth): geometry, analysis * Patrick Massot (@patrickmassot): documentation, topology, geometry * Bhavik Mehta (@b-mehta): category theory, combinatorics -* Kyle Miller (@kmill): combinatorics, documentation +* Kyle Miller (@kmill): combinatorics, tactics, metaprogramming * Scott Morrison (@semorrison): category theory, tactics * Oliver Nash (@ocfnash): algebra, geometry, topology * Joël Riou (@joelriou): category theory, homology, algebraic geometry From 44b647d2739e3440177a880276e7a1103f7953b8 Mon Sep 17 00:00:00 2001 From: Thomas Browning Date: Tue, 26 Dec 2023 21:14:30 +0000 Subject: [PATCH 209/353] feat(FieldTheory/PolynomialGaloisGroup): The Galois group of an irreducible polynomial acts transitively on the roots (#9121) This PR adds a lemma stating that the Galois group of an irreducible polynomial acts transitively on the roots. --- Mathlib/FieldTheory/PolynomialGaloisGroup.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Mathlib/FieldTheory/PolynomialGaloisGroup.lean b/Mathlib/FieldTheory/PolynomialGaloisGroup.lean index f1af3a3f238f2..b32d789978e29 100644 --- a/Mathlib/FieldTheory/PolynomialGaloisGroup.lean +++ b/Mathlib/FieldTheory/PolynomialGaloisGroup.lean @@ -198,6 +198,14 @@ instance galAction [Fact (p.Splits (algebraMap F E))] : MulAction p.Gal (rootSet simp only [smul_def, Equiv.apply_symm_apply, Equiv.symm_apply_apply, mul_smul] #align polynomial.gal.gal_action Polynomial.Gal.galAction +lemma galAction_isPretransitive [Fact (p.Splits (algebraMap F E))] (hp : Irreducible p) : + MulAction.IsPretransitive p.Gal (p.rootSet E) := by + refine' ⟨fun x y ↦ _⟩ + have hx := minpoly.eq_of_irreducible hp (mem_rootSet.mp ((rootsEquivRoots p E).symm x).2).2 + have hy := minpoly.eq_of_irreducible hp (mem_rootSet.mp ((rootsEquivRoots p E).symm y).2).2 + obtain ⟨g, hg⟩ := (Normal.minpoly_eq_iff_mem_orbit p.SplittingField).mp (hy.symm.trans hx) + exact ⟨g, (rootsEquivRoots p E).apply_eq_iff_eq_symm_apply.mpr (Subtype.ext hg)⟩ + variable {p E} /-- `Polynomial.Gal.restrict p E` is compatible with `Polynomial.Gal.galAction p E`. -/ From 4ad935a46c5d32b21cb074328e47bafbda245688 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Tue, 26 Dec 2023 21:38:01 +0000 Subject: [PATCH 210/353] feat(LinearAlgebra, Cardinal): new cardinal lemmas to generalize some results about `Module.rank` in #9151 (#9253) + Proves that `Sup` (ciSup) commutes with cardinal addition (`ciSup_add_ciSup`) and multiplication. Generalize results in Cardinal/Basic introduced in #8842 to achieve this. + Use `ciSup_add_ciSup` to prove that the rank of a module is always at least the rank of a submodule plus the rank of the quotient by the submodule. Deduce that the rank of a product module is at least the sum of the ranks of the two factors. + Show that quotienting by a torsion submodule preserves the rank. + Golf `rank_zero_iff_forall_zero` using a recently added lemma. Co-authored-by: Andrew Yang Co-authored-by: Junyan Xu --- Mathlib/LinearAlgebra/Dimension.lean | 72 ++++++++++++++++++++----- Mathlib/SetTheory/Cardinal/Basic.lean | 19 ++++--- Mathlib/SetTheory/Cardinal/Ordinal.lean | 57 ++++++++++++++++++++ 3 files changed, 128 insertions(+), 20 deletions(-) diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean index ee60edb57308e..a1083fa04d21f 100644 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ b/Mathlib/LinearAlgebra/Dimension.lean @@ -108,6 +108,9 @@ protected irreducible_def Module.rank : Cardinal := ⨆ ι : { s : Set V // LinearIndependent K ((↑) : s → V) }, (#ι.1) #align module.rank Module.rank +lemma nonempty_linearIndependent_set : Nonempty {s : Set V // LinearIndependent K ((↑) : s → V)} := + ⟨⟨∅, linearIndependent_empty _ _⟩⟩ + end section @@ -145,6 +148,25 @@ theorem rank_le {n : ℕ} exact linearIndependent_bounded_of_finset_linearIndependent_bounded H _ li #align rank_le rank_le +theorem rank_quotient_add_rank_le [Nontrivial R] (M' : Submodule R M) : + Module.rank R (M ⧸ M') + Module.rank R M' ≤ Module.rank R M := by + simp_rw [Module.rank_def] + have := nonempty_linearIndependent_set R (M ⧸ M') + have := nonempty_linearIndependent_set R M' + rw [Cardinal.ciSup_add_ciSup _ (bddAbove_range.{v, v} _) _ (bddAbove_range.{v, v} _)] + refine ciSup_le fun ⟨s, hs⟩ ↦ ciSup_le fun ⟨t, ht⟩ ↦ ?_ + choose f hf using Quotient.mk_surjective M' + let g : s ⊕ t → M := Sum.elim (f ·) (·) + suffices : LinearIndependent R g + · refine le_trans ?_ (le_ciSup (bddAbove_range.{v, v} _) ⟨_, this.to_subtype_range⟩) + rw [mk_range_eq _ this.injective, mk_sum, lift_id, lift_id] + refine .sum_type (.of_comp M'.mkQ ?_) (ht.map' M'.subtype M'.ker_subtype) ?_ + · convert hs; ext x; exact hf x + refine disjoint_def.mpr fun x h₁ h₂ ↦ ?_ + have : x ∈ M' := span_le.mpr (Set.range_subset_iff.mpr fun i ↦ i.1.2) h₂ + obtain ⟨c, rfl⟩ := Finsupp.mem_span_range_iff_exists_finsupp.mp h₁ + simp_rw [← Quotient.mk_eq_zero, ← mkQ_apply, map_finsupp_sum, map_smul, mkQ_apply, hf] at this + rw [linearIndependent_iff.mp hs _ this, Finsupp.sum_zero_index] /-- The rank of the range of a linear map is at most the rank of the source. -/ -- The proof is: a free submodule of the range lifts to a free submodule of the @@ -241,6 +263,25 @@ theorem rank_quotient_le (p : Submodule R M) : Module.rank R (M ⧸ p) ≤ Modul variable [Nontrivial R] +variable (R M M') + +open LinearMap in +theorem lift_rank_add_lift_rank_le_rank_prod : + lift.{v'} (Module.rank R M) + lift.{v} (Module.rank R M') ≤ Module.rank R (M × M') := by + convert rank_quotient_add_rank_le (ker <| LinearMap.fst R M M') + · refine Eq.trans ?_ (lift_id'.{v, v'} _) + rw [(quotKerEquivRange _).lift_rank_eq, + rank_range_of_surjective _ fst_surjective, lift_umax.{v, v'}] + · refine Eq.trans ?_ (lift_id'.{v', v} _) + rw [ker_fst, ← (LinearEquiv.ofInjective _ <| inr_injective (M := M) (M₂ := M')).lift_rank_eq, + lift_umax.{v', v}] + +theorem rank_add_rank_le_rank_prod : + Module.rank R M + Module.rank R M₁ ≤ Module.rank R (M × M₁) := by + convert ← lift_rank_add_lift_rank_le_rank_prod R M M₁ <;> apply lift_id + +variable {R M M'} + theorem cardinal_lift_le_rank_of_linearIndependent {ι : Type w} {v : ι → M} (hv : LinearIndependent R v) : Cardinal.lift.{v} #ι ≤ Cardinal.lift.{w} (Module.rank R M) := by @@ -491,18 +532,6 @@ theorem rank_pos [Nontrivial M] : 0 < Module.rank R M := by variable [Nontrivial R] -theorem rank_zero_iff_forall_zero : Module.rank R M = 0 ↔ ∀ x : M, x = 0 := by - refine' ⟨fun h => _, fun h => _⟩ - · contrapose! h - obtain ⟨x, hx⟩ := h - letI : Nontrivial M := nontrivial_of_ne _ _ hx - exact rank_pos.ne' - · have : (⊤ : Submodule R M) = ⊥ := by - ext x - simp [h x] - rw [← rank_top, this, rank_bot] -#align rank_zero_iff_forall_zero rank_zero_iff_forall_zero - /-- See `rank_zero_iff` for a stronger version with `NoZeroSMulDivisor R M`. -/ lemma rank_eq_zero_iff {R M} [Ring R] [AddCommGroup M] [Module R M] : Module.rank R M = 0 ↔ ∀ x : M, ∃ a : R, a ≠ 0 ∧ a • x = 0 := by @@ -525,11 +554,30 @@ lemma rank_eq_zero_iff {R M} [Ring R] [AddCommGroup M] [Module R M] : apply ha simpa using FunLike.congr_fun (linearIndependent_iff.mp hs (Finsupp.single i a) (by simpa)) i +theorem rank_zero_iff_forall_zero : Module.rank R M = 0 ↔ ∀ x : M, x = 0 := by + simp_rw [rank_eq_zero_iff, smul_eq_zero, and_or_left, not_and_self_iff, false_or, + exists_and_right, and_iff_right (exists_ne (0 : R))] +#align rank_zero_iff_forall_zero rank_zero_iff_forall_zero + lemma rank_eq_zero_iff_isTorsion {R M} [CommRing R] [IsDomain R] [AddCommGroup M] [Module R M] : Module.rank R M = 0 ↔ Module.IsTorsion R M := by rw [Module.IsTorsion, rank_eq_zero_iff] simp [mem_nonZeroDivisors_iff_ne_zero] +theorem rank_quotient_eq_of_le_torsion {R M} [CommRing R] [AddCommGroup M] [Module R M] + {N : Submodule R M} (hN : N ≤ torsion R M) : Module.rank R (M ⧸ N) = Module.rank R M := + (rank_quotient_le N).antisymm <| by + nontriviality R + rw [Module.rank] + have := nonempty_linearIndependent_set R M + refine ciSup_le fun ⟨s, hs⟩ ↦ cardinal_le_rank_of_linearIndependent (v := (N.mkQ ·)) ?_ + rw [linearIndependent_iff'] at hs ⊢ + simp_rw [← map_smul, ← map_sum, mkQ_apply, Quotient.mk_eq_zero] + intro t g hg i hi + obtain ⟨r, hg⟩ := hN hg + simp_rw [Finset.smul_sum, Submonoid.smul_def, smul_smul] at hg + exact r.prop _ (mul_comm (g i) r ▸ hs t _ hg i hi) + /-- See `rank_subsingleton` for the reason that `Nontrivial R` is needed. Also see `rank_eq_zero_iff` for the version without `NoZeroSMulDivisor R M`. -/ theorem rank_zero_iff : Module.rank R M = 0 ↔ Subsingleton M := diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index b88a9421a9a2e..8b58e4038d755 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -1013,20 +1013,23 @@ protected theorem iSup_of_empty {ι} (f : ι → Cardinal) [IsEmpty ι] : iSup f #align cardinal.supr_of_empty Cardinal.iSup_of_empty lemma exists_eq_of_iSup_eq_of_not_isSuccLimit - {ι : Type u} (f : ι → Cardinal.{max u v}) (ω : Cardinal.{max u v}) + {ι : Type u} (f : ι → Cardinal.{v}) (ω : Cardinal.{v}) (hω : ¬ Order.IsSuccLimit ω) (h : ⨆ i : ι, f i = ω) : ∃ i, f i = ω := - IsLUB.exists_of_not_isSuccLimit (h ▸ isLUB_csSup' (bddAbove_range.{u, v} f)) hω + (Classical.em <| BddAbove <| range f).elim + (fun hf ↦ IsLUB.exists_of_not_isSuccLimit (h ▸ isLUB_csSup' hf) hω) fun hf ↦ by + rw [iSup, csSup_of_not_bddAbove hf, csSup_empty] at h + exact (hω <| h ▸ Order.isSuccLimit_bot).elim lemma exists_eq_of_iSup_eq_of_not_isLimit - {ι : Type u} [hι : Nonempty ι] (f : ι → Cardinal.{max u v}) (ω : Cardinal.{max u v}) - (hω : ¬ ω.IsLimit) + {ι : Type u} [hι : Nonempty ι] (f : ι → Cardinal.{v}) (hf : BddAbove (range f)) + (ω : Cardinal.{v}) (hω : ¬ ω.IsLimit) (h : ⨆ i : ι, f i = ω) : ∃ i, f i = ω := by refine (not_and_or.mp hω).elim (fun e ↦ ⟨hι.some, ?_⟩) (Cardinal.exists_eq_of_iSup_eq_of_not_isSuccLimit.{u, v} f ω · h) cases not_not.mp e rw [← le_zero_iff] at h ⊢ - exact (le_ciSup (Cardinal.bddAbove_range.{u, v} f) _).trans h + exact (le_ciSup hf _).trans h -- Portin note: simpNF is not happy with universe levels. @[simp, nolint simpNF] @@ -1475,9 +1478,9 @@ theorem IsLimit.aleph0_le {c : Cardinal} (h : IsLimit c) : ℵ₀ ≤ c := by rcases lt_aleph0.1 h' with ⟨n, rfl⟩ exact not_isLimit_natCast n h -lemma exists_eq_natCast_of_iSup_eq {ι : Type u} [Nonempty ι] (f : ι → Cardinal.{max u v}) - (n : ℕ) (h : ⨆ i, f i = n) : ∃ i, f i = n := - exists_eq_of_iSup_eq_of_not_isLimit.{u, v} f _ (not_isLimit_natCast n) h +lemma exists_eq_natCast_of_iSup_eq {ι : Type u} [Nonempty ι] (f : ι → Cardinal.{v}) + (hf : BddAbove (range f)) (n : ℕ) (h : ⨆ i, f i = n) : ∃ i, f i = n := + exists_eq_of_iSup_eq_of_not_isLimit.{u, v} f hf _ (not_isLimit_natCast n) h @[simp] theorem range_natCast : range ((↑) : ℕ → Cardinal) = Iio ℵ₀ := diff --git a/Mathlib/SetTheory/Cardinal/Ordinal.lean b/Mathlib/SetTheory/Cardinal/Ordinal.lean index ffbcf55781644..ffb4c5924fa85 100644 --- a/Mathlib/SetTheory/Cardinal/Ordinal.lean +++ b/Mathlib/SetTheory/Cardinal/Ordinal.lean @@ -849,6 +849,63 @@ protected theorem eq_of_add_eq_add_right {a b c : Cardinal} (h : a + b = c + b) exact Cardinal.eq_of_add_eq_add_left h hb #align cardinal.eq_of_add_eq_add_right Cardinal.eq_of_add_eq_add_right +section ciSup + +variable {ι : Type u} {ι' : Type w} (f : ι → Cardinal.{v}) + +section add + +variable [Nonempty ι] [Nonempty ι'] (hf : BddAbove (range f)) + +protected theorem ciSup_add (c : Cardinal.{v}) : (⨆ i, f i) + c = ⨆ i, f i + c := by + have : ∀ i, f i + c ≤ (⨆ i, f i) + c := fun i ↦ add_le_add_right (le_ciSup hf i) c + refine le_antisymm ?_ (ciSup_le' this) + have bdd : BddAbove (range (f · + c)) := ⟨_, forall_range_iff.mpr this⟩ + obtain hs | hs := lt_or_le (⨆ i, f i) ℵ₀ + · obtain ⟨i, hi⟩ := exists_eq_of_iSup_eq_of_not_isLimit + f hf _ (fun h ↦ hs.not_le h.aleph0_le) rfl + exact hi ▸ le_ciSup bdd i + rw [add_eq_max hs, max_le_iff] + exact ⟨ciSup_mono bdd fun i ↦ self_le_add_right _ c, + (self_le_add_left _ _).trans (le_ciSup bdd <| Classical.arbitrary ι)⟩ + +protected theorem add_ciSup (c : Cardinal.{v}) : c + (⨆ i, f i) = ⨆ i, c + f i := by + rw [add_comm, Cardinal.ciSup_add f hf]; simp_rw [add_comm] + +protected theorem ciSup_add_ciSup (g : ι' → Cardinal.{v}) (hg : BddAbove (range g)) : + (⨆ i, f i) + (⨆ j, g j) = ⨆ (i) (j), f i + g j := by + simp_rw [Cardinal.ciSup_add f hf, Cardinal.add_ciSup g hg] + +end add + +protected theorem ciSup_mul (c : Cardinal.{v}) : (⨆ i, f i) * c = ⨆ i, f i * c := by + cases isEmpty_or_nonempty ι; · simp + obtain rfl | h0 := eq_or_ne c 0; · simp + by_cases hf : BddAbove (range f); swap + · have hfc : ¬ BddAbove (range (f · * c)) := fun bdd ↦ hf + ⟨⨆ i, f i * c, forall_range_iff.mpr fun i ↦ (le_mul_right h0).trans (le_ciSup bdd i)⟩ + simp [iSup, csSup_of_not_bddAbove, hf, hfc] + have : ∀ i, f i * c ≤ (⨆ i, f i) * c := fun i ↦ mul_le_mul_right' (le_ciSup hf i) c + refine le_antisymm ?_ (ciSup_le' this) + have bdd : BddAbove (range (f · * c)) := ⟨_, forall_range_iff.mpr this⟩ + obtain hs | hs := lt_or_le (⨆ i, f i) ℵ₀ + · obtain ⟨i, hi⟩ := exists_eq_of_iSup_eq_of_not_isLimit + f hf _ (fun h ↦ hs.not_le h.aleph0_le) rfl + exact hi ▸ le_ciSup bdd i + rw [mul_eq_max_of_aleph0_le_left hs h0, max_le_iff] + obtain ⟨i, hi⟩ := exists_lt_of_lt_ciSup' (one_lt_aleph0.trans_le hs) + exact ⟨ciSup_mono bdd fun i ↦ le_mul_right h0, + (le_mul_left (zero_lt_one.trans hi).ne').trans (le_ciSup bdd i)⟩ + +protected theorem mul_ciSup (c : Cardinal.{v}) : c * (⨆ i, f i) = ⨆ i, c * f i := by + rw [mul_comm, Cardinal.ciSup_mul f]; simp_rw [mul_comm] + +protected theorem ciSup_mul_ciSup (g : ι' → Cardinal.{v}) : + (⨆ i, f i) * (⨆ j, g j) = ⨆ (i) (j), f i * g j := by + simp_rw [Cardinal.ciSup_mul f, Cardinal.mul_ciSup g] + +end ciSup + @[simp] theorem aleph_add_aleph (o₁ o₂ : Ordinal) : aleph o₁ + aleph o₂ = aleph (max o₁ o₂) := by rw [Cardinal.add_eq_max (aleph0_le_aleph o₁), max_aleph_eq] From 230b6ac46eb0856e837dd9cf5984224f0af8b756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Tue, 26 Dec 2023 22:33:48 +0000 Subject: [PATCH 211/353] feat(Algebra/Homology): binary biproducts of homological complexes (#8966) --- Mathlib.lean | 1 + .../Homology/HomologicalComplexBiprod.lean | 108 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 Mathlib/Algebra/Homology/HomologicalComplexBiprod.lean diff --git a/Mathlib.lean b/Mathlib.lean index 88571562b0e33..69d86369c72f9 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -237,6 +237,7 @@ import Mathlib.Algebra.Homology.ExactSequence import Mathlib.Algebra.Homology.Flip import Mathlib.Algebra.Homology.Functor import Mathlib.Algebra.Homology.HomologicalComplex +import Mathlib.Algebra.Homology.HomologicalComplexBiprod import Mathlib.Algebra.Homology.HomologicalComplexLimits import Mathlib.Algebra.Homology.Homology import Mathlib.Algebra.Homology.HomologySequence diff --git a/Mathlib/Algebra/Homology/HomologicalComplexBiprod.lean b/Mathlib/Algebra/Homology/HomologicalComplexBiprod.lean new file mode 100644 index 0000000000000..cb8b60d15b0e0 --- /dev/null +++ b/Mathlib/Algebra/Homology/HomologicalComplexBiprod.lean @@ -0,0 +1,108 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.Algebra.Homology.HomologicalComplexLimits +import Mathlib.Algebra.Homology.Additive + +/-! Binary biproducts of homological complexes + +In this file, it is shown that if two homological complex `K` and `L` in +a preadditive category are such that for all `i : ι`, the binary biproduct +`K.X i ⊞ L.X i` exists, then `K ⊞ L` exists, and there is an isomorphism +`biprodXIso K L i : (K ⊞ L).X i ≅ (K.X i) ⊞ (L.X i)`. + +-/ +open CategoryTheory Limits + +namespace HomologicalComplex + +variable {C ι : Type*} [Category C] [Preadditive C] {c : ComplexShape ι} + (K L : HomologicalComplex C c) [∀ i, HasBinaryBiproduct (K.X i) (L.X i)] + +instance (i : ι) : HasBinaryBiproduct ((eval C c i).obj K) ((eval C c i).obj L) := by + dsimp [eval] + infer_instance + +instance (i : ι) : HasLimit ((pair K L) ⋙ (eval C c i)) := by + have e : _ ≅ pair (K.X i) (L.X i) := diagramIsoPair (pair K L ⋙ eval C c i) + exact hasLimitOfIso e.symm + +instance (i : ι) : HasColimit ((pair K L) ⋙ (eval C c i)) := by + have e : _ ≅ pair (K.X i) (L.X i) := diagramIsoPair (pair K L ⋙ eval C c i) + exact hasColimitOfIso e + +instance : HasBinaryBiproduct K L := HasBinaryBiproduct.of_hasBinaryProduct _ _ + +instance (i : ι) : PreservesBinaryBiproduct K L (eval C c i) := + preservesBinaryBiproductOfPreservesBinaryProduct _ + +/-- The canonical isomorphism `(K ⊞ L).X i ≅ (K.X i) ⊞ (L.X i)`. -/ +noncomputable def biprodXIso (i : ι) : (K ⊞ L).X i ≅ (K.X i) ⊞ (L.X i) := + (eval C c i).mapBiprod K L + +@[reassoc (attr := simp)] +lemma inl_biprodXIso_inv (i : ι) : + biprod.inl ≫ (biprodXIso K L i).inv = (biprod.inl : K ⟶ K ⊞ L).f i := by + simp [biprodXIso] + +@[reassoc (attr := simp)] +lemma inr_biprodXIso_inv (i : ι) : + biprod.inr ≫ (biprodXIso K L i).inv = (biprod.inr : L ⟶ K ⊞ L).f i := by + simp [biprodXIso] + +@[reassoc (attr := simp)] +lemma biprodXIso_hom_fst (i : ι) : + (biprodXIso K L i).hom ≫ biprod.fst = (biprod.fst : K ⊞ L ⟶ K).f i := by + simp [biprodXIso] + +@[reassoc (attr := simp)] +lemma biprodXIso_hom_snd (i : ι) : + (biprodXIso K L i).hom ≫ biprod.snd = (biprod.snd : K ⊞ L ⟶ L).f i := by + simp [biprodXIso] + +@[reassoc (attr := simp)] +lemma biprod_inl_fst_f (i : ι) : + (biprod.inl : K ⟶ K ⊞ L).f i ≫ (biprod.fst : K ⊞ L ⟶ K).f i = 𝟙 _ := by + rw [← comp_f, biprod.inl_fst, id_f] + +@[reassoc (attr := simp)] +lemma biprod_inl_snd_f (i : ι) : + (biprod.inl : K ⟶ K ⊞ L).f i ≫ (biprod.snd : K ⊞ L ⟶ L).f i = 0 := by + rw [← comp_f, biprod.inl_snd, zero_f] + +@[reassoc (attr := simp)] +lemma biprod_inr_fst_f (i : ι) : + (biprod.inr : L ⟶ K ⊞ L).f i ≫ (biprod.fst : K ⊞ L ⟶ K).f i = 0 := by + rw [← comp_f, biprod.inr_fst, zero_f] + +@[reassoc (attr := simp)] +lemma biprod_inr_snd_f (i : ι) : + (biprod.inr : L ⟶ K ⊞ L).f i ≫ (biprod.snd : K ⊞ L ⟶ L).f i = 𝟙 _ := by + rw [← comp_f, biprod.inr_snd, id_f] + +variable {K L} +variable {M : HomologicalComplex C c} + +@[reassoc (attr := simp)] +lemma biprod_inl_desc_f (α : K ⟶ M) (β : L ⟶ M) (i : ι) : + (biprod.inl : K ⟶ K ⊞ L).f i ≫ (biprod.desc α β).f i = α.f i := by + rw [← comp_f, biprod.inl_desc] + +@[reassoc (attr := simp)] +lemma biprod_inr_desc_f (α : K ⟶ M) (β : L ⟶ M) (i : ι) : + (biprod.inr : L ⟶ K ⊞ L).f i ≫ (biprod.desc α β).f i = β.f i := by + rw [← comp_f, biprod.inr_desc] + +@[reassoc (attr := simp)] +lemma biprod_lift_fst_f (α : M ⟶ K) (β : M ⟶ L) (i : ι) : + (biprod.lift α β).f i ≫ (biprod.fst : K ⊞ L ⟶ K).f i = α.f i := by + rw [← comp_f, biprod.lift_fst] + +@[reassoc (attr := simp)] +lemma biprod_lift_snd_f (α : M ⟶ K) (β : M ⟶ L) (i : ι) : + (biprod.lift α β).f i ≫ (biprod.snd : K ⊞ L ⟶ L).f i = β.f i := by + rw [← comp_f, biprod.lift_snd] + +end HomologicalComplex From 2bb32b69f94b8ec667c96265116075319dff0369 Mon Sep 17 00:00:00 2001 From: Kevin Buzzard Date: Tue, 26 Dec 2023 22:33:49 +0000 Subject: [PATCH 212/353] feat(Data/ZMod/Basic): add `inv_eq_of_mul_eq_one` (#9140) Co-authored-by: Johan Commelin --- Mathlib/Data/ZMod/Basic.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mathlib/Data/ZMod/Basic.lean b/Mathlib/Data/ZMod/Basic.lean index 4569ab747172a..0f5fa03ee8070 100644 --- a/Mathlib/Data/ZMod/Basic.lean +++ b/Mathlib/Data/ZMod/Basic.lean @@ -772,6 +772,11 @@ theorem inv_mul_of_unit {n : ℕ} (a : ZMod n) (h : IsUnit a) : a⁻¹ * a = 1 : rw [mul_comm, mul_inv_of_unit a h] #align zmod.inv_mul_of_unit ZMod.inv_mul_of_unit +-- TODO: If we changed `⁻¹` so that `ZMod n` is always a `DivisionMonoid`, +-- then we could use the general lemma `inv_eq_of_mul_eq_one` +protected theorem inv_eq_of_mul_eq_one (n : ℕ) (a b : ZMod n) (h : a * b = 1) : a⁻¹ = b := + left_inv_eq_right_inv (inv_mul_of_unit a ⟨⟨a, b, h, mul_comm a b ▸ h⟩, rfl⟩) h + -- TODO: this equivalence is true for `ZMod 0 = ℤ`, but needs to use different functions. /-- Equivalence between the units of `ZMod n` and the subtype of terms `x : ZMod n` for which `x.val` is coprime to `n` -/ From 401acd59cb96b8310342f2858f8c2367169bb1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 22:33:50 +0000 Subject: [PATCH 213/353] feat: Basic finset lemmas (#9225) From LeanAPAP and LeanCamCombi --- Mathlib/Data/Finset/Basic.lean | 45 +++++++++++++++++++++++++++++++-- Mathlib/Data/Fintype/Basic.lean | 16 ++++++++++++ Mathlib/Data/Fintype/Card.lean | 6 +++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/Mathlib/Data/Finset/Basic.lean b/Mathlib/Data/Finset/Basic.lean index a2f0ee4774396..c5dbd2cdd92c5 100644 --- a/Mathlib/Data/Finset/Basic.lean +++ b/Mathlib/Data/Finset/Basic.lean @@ -477,8 +477,7 @@ theorem coe_coeEmb : ⇑(coeEmb : Finset α ↪o Set α) = ((↑) : Finset α /-- The property `s.Nonempty` expresses the fact that the finset `s` is not empty. It should be used in theorem assumptions instead of `∃ x, x ∈ s` or `s ≠ ∅` as it gives access to a nice API thanks to the dot notation. -/ -protected def Nonempty (s : Finset α) : Prop := - ∃ x : α, x ∈ s +@[pp_dot] protected def Nonempty (s : Finset α) : Prop := ∃ x : α, x ∈ s #align finset.nonempty Finset.Nonempty --Porting note: Much longer than in Lean3 @@ -738,6 +737,12 @@ theorem coe_eq_singleton {s : Finset α} {a : α} : (s : Set α) = {a} ↔ s = { rw [← coe_singleton, coe_inj] #align finset.coe_eq_singleton Finset.coe_eq_singleton +@[norm_cast] +lemma coe_subset_singleton : (s : Set α) ⊆ {a} ↔ s ⊆ {a} := by rw [← coe_subset, coe_singleton] + +@[norm_cast] +lemma singleton_subset_coe : {a} ⊆ (s : Set α) ↔ {a} ⊆ s := by rw [← coe_subset, coe_singleton] + theorem eq_singleton_iff_unique_mem {s : Finset α} {a : α} : s = {a} ↔ a ∈ s ∧ ∀ x ∈ s, x = a := by constructor <;> intro t · rw [t] @@ -1918,6 +1923,12 @@ theorem erase_empty (a : α) : erase ∅ a = ∅ := rfl #align finset.erase_empty Finset.erase_empty +@[simp] lemma erase_nonempty (ha : a ∈ s) : (s.erase a).Nonempty ↔ s.Nontrivial := by + simp only [Finset.Nonempty, mem_erase, and_comm (b := _ ∈ _)] + refine ⟨?_, fun hs ↦ hs.exists_ne a⟩ + rintro ⟨b, hb, hba⟩ + exact ⟨_, hb, _, ha, hba⟩ + @[simp] theorem erase_singleton (a : α) : ({a} : Finset α).erase a = ∅ := by ext x @@ -2075,6 +2086,19 @@ theorem erase_injOn' (a : α) : { s : Finset α | a ∈ s }.InjOn fun s => erase fun s hs t ht (h : s.erase a = _) => by rw [← insert_erase hs, ← insert_erase ht, h] #align finset.erase_inj_on' Finset.erase_injOn' +lemma Nonempty.exists_cons_eq (hs : s.Nonempty) : ∃ t a ha, cons a t ha = s := by + classical + obtain ⟨a, ha⟩ := hs + exact ⟨s.erase a, a, not_mem_erase _ _, by simp [insert_erase ha]⟩ + +lemma Nontrivial.exists_cons_eq (hs : s.Nontrivial) : + ∃ t a ha b hb hab, (cons b t hb).cons a (mem_cons.not.2 $ not_or_intro hab ha) = s := by + classical + obtain ⟨a, ha, b, hb, hab⟩ := hs + have : b ∈ s.erase a := mem_erase.2 ⟨hab.symm, hb⟩ + refine ⟨(s.erase a).erase b, a, ?_, b, ?_, ?_, ?_⟩ <;> + simp [insert_erase this, insert_erase ha, *] + end Erase /-! ### sdiff -/ @@ -2246,6 +2270,15 @@ theorem insert_sdiff_insert (s t : Finset α) (x : α) : insert x s \ insert x t insert_sdiff_of_mem _ (mem_insert_self _ _) #align finset.insert_sdiff_insert Finset.insert_sdiff_insert +lemma insert_sdiff_insert' (hab : a ≠ b) (ha : a ∉ s) : insert a s \ insert b s = {a} := by + ext; aesop + +lemma erase_sdiff_erase (hab : a ≠ b) (hb : b ∈ s) : s.erase a \ s.erase b = {b} := by + ext; aesop + +lemma cons_sdiff_cons (hab : a ≠ b) (ha hb) : s.cons a ha \ s.cons b hb = {a} := by + rw [cons_eq_insert, cons_eq_insert, insert_sdiff_insert' hab ha] + theorem sdiff_insert_of_not_mem {x : α} (h : x ∉ s) (t : Finset α) : s \ insert x t = s \ t := by refine' Subset.antisymm (sdiff_subset_sdiff (Subset.refl _) (subset_insert _ _)) fun y hy => _ simp only [mem_sdiff, mem_insert, not_or] at hy ⊢ @@ -2289,6 +2322,12 @@ theorem disjoint_erase_comm : Disjoint (s.erase a) t ↔ Disjoint s (t.erase a) simp_rw [erase_eq, disjoint_sdiff_comm] #align finset.disjoint_erase_comm Finset.disjoint_erase_comm +lemma disjoint_insert_erase (ha : a ∉ t) : Disjoint (s.erase a) (insert a t) ↔ Disjoint s t := by + rw [disjoint_erase_comm, erase_insert ha] + +lemma disjoint_erase_insert (ha : a ∉ s) : Disjoint (insert a s) (t.erase a) ↔ Disjoint s t := by + rw [← disjoint_erase_comm, erase_insert ha] + theorem disjoint_of_erase_left (ha : a ∉ t) (hst : Disjoint (s.erase a) t) : Disjoint s t := by rw [← erase_insert ha, ← disjoint_erase_comm, disjoint_insert_right] exact ⟨not_mem_erase _ _, hst⟩ @@ -2490,6 +2529,8 @@ theorem attach_nonempty_iff {s : Finset α} : s.attach.Nonempty ↔ s.Nonempty : simp [Finset.Nonempty] #align finset.attach_nonempty_iff Finset.attach_nonempty_iff +protected alias ⟨_, Nonempty.attach⟩ := attach_nonempty_iff + @[simp] theorem attach_eq_empty_iff {s : Finset α} : s.attach = ∅ ↔ s = ∅ := by simp [eq_empty_iff_forall_not_mem] diff --git a/Mathlib/Data/Fintype/Basic.lean b/Mathlib/Data/Fintype/Basic.lean index 53d4f755967f1..f70dd3c8f5aaa 100644 --- a/Mathlib/Data/Fintype/Basic.lean +++ b/Mathlib/Data/Fintype/Basic.lean @@ -178,6 +178,11 @@ theorem coe_compl (s : Finset α) : ↑sᶜ = (↑s : Set α)ᶜ := @[simp] lemma compl_subset_compl : sᶜ ⊆ tᶜ ↔ t ⊆ s := @compl_le_compl_iff_le (Finset α) _ _ _ @[simp] lemma compl_ssubset_compl : sᶜ ⊂ tᶜ ↔ t ⊂ s := @compl_lt_compl_iff_lt (Finset α) _ _ _ +lemma subset_compl_comm : s ⊆ tᶜ ↔ t ⊆ sᶜ := le_compl_iff_le_compl (α := Finset α) + +@[simp] lemma subset_compl_singleton : s ⊆ {a}ᶜ ↔ a ∉ s := by + rw [subset_compl_comm, singleton_subset_iff, mem_compl] + @[simp] theorem compl_empty : (∅ : Finset α)ᶜ = univ := compl_bot @@ -276,6 +281,11 @@ theorem image_univ_equiv [Fintype β] (f : β ≃ α) : univ.image f = univ := end BooleanAlgebra +-- @[simp] --Note this would loop with `Finset.univ_unique` +lemma singleton_eq_univ [Subsingleton α] (a : α) : ({a} : Finset α) = univ := by + ext b; simp [Subsingleton.elim a b] + + theorem map_univ_of_surjective [Fintype β] {f : β ↪ α} (hf : Surjective f) : univ.map f = univ := eq_univ_of_forall <| hf.forall.2 fun _ => mem_map_of_mem _ <| mem_univ _ #align finset.map_univ_of_surjective Finset.map_univ_of_surjective @@ -360,6 +370,9 @@ instance decidableMemRangeFintype [Fintype α] [DecidableEq β] (f : α → β) DecidablePred (· ∈ Set.range f) := fun _ => Fintype.decidableExistsFintype #align fintype.decidable_mem_range_fintype Fintype.decidableMemRangeFintype +instance decidableSubsingleton [Fintype α] [DecidableEq α] {s : Set α} [DecidablePred (· ∈ s)] : + Decidable s.Subsingleton := decidable_of_iff (∀ a ∈ s, ∀ b ∈ s, a = b) Iff.rfl + section BundledHoms instance decidableEqEquivFintype [DecidableEq β] [Fintype α] : DecidableEq (α ≃ β) := fun a b => @@ -472,6 +485,9 @@ namespace Finset variable [Fintype α] [DecidableEq α] {s t : Finset α} +@[simp] +lemma filter_univ_mem (s : Finset α) : univ.filter (· ∈ s) = s := by simp [filter_mem_eq_inter] + instance decidableCodisjoint : Decidable (Codisjoint s t) := decidable_of_iff _ codisjoint_left.symm #align finset.decidable_codisjoint Finset.decidableCodisjoint diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index cbc253aef9e2e..6fbdb60869df1 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -398,6 +398,12 @@ theorem Fintype.card_lex (α : Type*) [Fintype α] : Fintype.card (Lex α) = Fin rfl #align fintype.card_lex Fintype.card_lex +@[simp] lemma Fintype.card_multiplicative (α : Type*) [Fintype α] : + card (Multiplicative α) = card α := Finset.card_map _ + +@[simp] lemma Fintype.card_additive (α : Type*) [Fintype α] : card (Additive α) = card α := + Finset.card_map _ + /-- Given that `α ⊕ β` is a fintype, `α` is also a fintype. This is non-computable as it uses that `Sum.inl` is an injection, but there's no clear inverse if `α` is empty. -/ noncomputable def Fintype.sumLeft {α β} [Fintype (Sum α β)] : Fintype α := From 299792d941f0a59647d1864dd577af60b4b0228f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Dec 2023 22:33:51 +0000 Subject: [PATCH 214/353] =?UTF-8?q?chore:=20Generalise=20monotonicity=20of?= =?UTF-8?q?=20`=E2=80=A2`=20lemmas=20in=20modules=20(#9241)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sort the lemmas in `Algebra.Order.Module` into `Algebra.Order.Module.Defs` and `Algebra.Order.Module.Pointwise`. Generalise them. A later PR will rename the lemmas to better match the naming convention. --- Mathlib.lean | 1 - Mathlib/Algebra/Order/Module.lean | 279 ----------------- Mathlib/Algebra/Order/Module/Defs.lean | 282 +++++++++++++++--- Mathlib/Algebra/Order/Module/Pointwise.lean | 46 +++ Mathlib/Algebra/Order/Module/Synonym.lean | 4 +- Mathlib/Algebra/Order/Monovary.lean | 2 +- Mathlib/Algebra/Order/Nonneg/Module.lean | 2 +- Mathlib/Algebra/Order/Rearrangement.lean | 2 +- Mathlib/Analysis/Convex/Basic.lean | 2 +- Mathlib/Data/Real/Pointwise.lean | 2 +- .../LinearAlgebra/AffineSpace/Ordered.lean | 2 +- 11 files changed, 299 insertions(+), 325 deletions(-) delete mode 100644 Mathlib/Algebra/Order/Module.lean diff --git a/Mathlib.lean b/Mathlib.lean index 69d86369c72f9..0637c7e2ee013 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -376,7 +376,6 @@ import Mathlib.Algebra.Order.Interval import Mathlib.Algebra.Order.Invertible import Mathlib.Algebra.Order.Kleene import Mathlib.Algebra.Order.LatticeGroup -import Mathlib.Algebra.Order.Module import Mathlib.Algebra.Order.Module.Defs import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.Algebra.Order.Module.Pointwise diff --git a/Mathlib/Algebra/Order/Module.lean b/Mathlib/Algebra/Order/Module.lean deleted file mode 100644 index 320cba192aadf..0000000000000 --- a/Mathlib/Algebra/Order/Module.lean +++ /dev/null @@ -1,279 +0,0 @@ -/- -Copyright (c) 2020 Frédéric Dupuis. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Frédéric Dupuis, Yaël Dillies --/ -import Mathlib.Algebra.Order.Module.OrderedSMul - -#align_import algebra.order.module from "leanprover-community/mathlib"@"3ba15165bd6927679be7c22d6091a87337e3cd0c" - -/-! -# Ordered module - -In this file we provide lemmas about `OrderedSMul` that hold once a module structure is present. - -## TODO - -Generalise lemmas to the framework from `Mathlib.Algebra.Order.Module.Defs`. - -## References - -* https://en.wikipedia.org/wiki/Ordered_vector_space - -## Tags - -ordered module, ordered scalar, ordered smul, ordered action, ordered vector space --/ - - -open Pointwise - -variable {ι k M N : Type*} - -section Semiring - -variable [OrderedSemiring k] [OrderedAddCommGroup M] [Module k M] [OrderedSMul k M] {a b : M} - {c : k} - -/- Can be generalized from `Module k M` to `DistribMulActionWithZero k M` once it exists. -where `DistribMulActionWithZero k M`is the conjunction of `DistribMulAction k M` and -`SMulWithZero k M`.-/ -theorem smul_neg_iff_of_pos (hc : 0 < c) : c • a < 0 ↔ a < 0 := by - rw [← neg_neg a, smul_neg, neg_neg_iff_pos, neg_neg_iff_pos] - exact smul_pos_iff_of_pos_left hc -#align smul_neg_iff_of_pos smul_neg_iff_of_pos - -end Semiring - -section Ring - -variable [OrderedRing k] [OrderedAddCommGroup M] [Module k M] [OrderedSMul k M] {a b : M} {c d : k} - -theorem smul_lt_smul_of_neg (h : a < b) (hc : c < 0) : c • b < c • a := by - rw [← neg_neg c, neg_smul, neg_smul (-c), neg_lt_neg_iff] - exact smul_lt_smul_of_pos_left h (neg_pos_of_neg hc) -#align smul_lt_smul_of_neg smul_lt_smul_of_neg - -theorem smul_le_smul_of_nonpos (h : a ≤ b) (hc : c ≤ 0) : c • b ≤ c • a := by - rw [← neg_neg c, neg_smul, neg_smul (-c), neg_le_neg_iff] - exact smul_le_smul_of_nonneg_left h (neg_nonneg_of_nonpos hc) -#align smul_le_smul_of_nonpos smul_le_smul_of_nonpos - -#noalign eq_of_smul_eq_smul_of_neg_of_le - -theorem lt_of_smul_lt_smul_of_nonpos (h : c • a < c • b) (hc : c ≤ 0) : b < a := by - rw [← neg_neg c, neg_smul, neg_smul (-c), neg_lt_neg_iff] at h - exact lt_of_smul_lt_smul_of_nonneg_left h (neg_nonneg_of_nonpos hc) -#align lt_of_smul_lt_smul_of_nonpos lt_of_smul_lt_smul_of_nonpos - -theorem smul_lt_smul_iff_of_neg (hc : c < 0) : c • a < c • b ↔ b < a := by - rw [← neg_neg c, neg_smul, neg_smul (-c), neg_lt_neg_iff] - exact smul_lt_smul_iff_of_pos_left (neg_pos_of_neg hc) -#align smul_lt_smul_iff_of_neg smul_lt_smul_iff_of_neg - -theorem smul_neg_iff_of_neg (hc : c < 0) : c • a < 0 ↔ 0 < a := by - rw [← neg_neg c, neg_smul, neg_neg_iff_pos] - exact smul_pos_iff_of_pos_left (neg_pos_of_neg hc) -#align smul_neg_iff_of_neg smul_neg_iff_of_neg - -theorem smul_pos_iff_of_neg (hc : c < 0) : 0 < c • a ↔ a < 0 := by - rw [← neg_neg c, neg_smul, neg_pos] - exact smul_neg_iff_of_pos (neg_pos_of_neg hc) -#align smul_pos_iff_of_neg smul_pos_iff_of_neg - -#align smul_nonpos_of_nonpos_of_nonneg smul_nonpos_of_nonpos_of_nonneg - -theorem smul_nonneg_of_nonpos_of_nonpos (hc : c ≤ 0) (ha : a ≤ 0) : 0 ≤ c • a := - smul_nonpos_of_nonpos_of_nonneg (β := Mᵒᵈ) hc ha -#align smul_nonneg_of_nonpos_of_nonpos smul_nonneg_of_nonpos_of_nonpos - -alias ⟨_, smul_pos_of_neg_of_neg⟩ := smul_pos_iff_of_neg -#align smul_pos_of_neg_of_neg smul_pos_of_neg_of_neg - -#align smul_neg_of_pos_of_neg smul_neg_of_pos_of_neg -#align smul_neg_of_neg_of_pos smul_neg_of_neg_of_pos - -theorem antitone_smul_left (hc : c ≤ 0) : Antitone (SMul.smul c : M → M) := fun _ _ h => - smul_le_smul_of_nonpos h hc -#align antitone_smul_left antitone_smul_left - -theorem strict_anti_smul_left (hc : c < 0) : StrictAnti (SMul.smul c : M → M) := fun _ _ h => - smul_lt_smul_of_neg h hc -#align strict_anti_smul_left strict_anti_smul_left - -/-- Binary **rearrangement inequality**. -/ -theorem smul_add_smul_le_smul_add_smul [ContravariantClass M M (· + ·) (· ≤ ·)] {a b : k} {c d : M} - (hab : a ≤ b) (hcd : c ≤ d) : a • d + b • c ≤ a • c + b • d := by - obtain ⟨b, rfl⟩ := exists_add_of_le hab - obtain ⟨d, rfl⟩ := exists_add_of_le hcd - rw [smul_add, add_right_comm, smul_add, ← add_assoc, add_smul _ _ d] - rw [le_add_iff_nonneg_right] at hab hcd - exact add_le_add_left (le_add_of_nonneg_right <| smul_nonneg hab hcd) _ -#align smul_add_smul_le_smul_add_smul smul_add_smul_le_smul_add_smul - -/-- Binary **rearrangement inequality**. -/ -theorem smul_add_smul_le_smul_add_smul' [ContravariantClass M M (· + ·) (· ≤ ·)] {a b : k} {c d : M} - (hba : b ≤ a) (hdc : d ≤ c) : a • d + b • c ≤ a • c + b • d := by - rw [add_comm (a • d), add_comm (a • c)] - exact smul_add_smul_le_smul_add_smul hba hdc -#align smul_add_smul_le_smul_add_smul' smul_add_smul_le_smul_add_smul' - -/-- Binary strict **rearrangement inequality**. -/ -theorem smul_add_smul_lt_smul_add_smul [CovariantClass M M (· + ·) (· < ·)] - [ContravariantClass M M (· + ·) (· < ·)] {a b : k} {c d : M} (hab : a < b) (hcd : c < d) : - a • d + b • c < a • c + b • d := by - obtain ⟨b, rfl⟩ := exists_add_of_le hab.le - obtain ⟨d, rfl⟩ := exists_add_of_le hcd.le - rw [smul_add, add_right_comm, smul_add, ← add_assoc, add_smul _ _ d] - rw [lt_add_iff_pos_right] at hab hcd - exact add_lt_add_left (lt_add_of_pos_right _ <| smul_pos hab hcd) _ -#align smul_add_smul_lt_smul_add_smul smul_add_smul_lt_smul_add_smul - -/-- Binary strict **rearrangement inequality**. -/ -theorem smul_add_smul_lt_smul_add_smul' [CovariantClass M M (· + ·) (· < ·)] - [ContravariantClass M M (· + ·) (· < ·)] {a b : k} {c d : M} (hba : b < a) (hdc : d < c) : - a • d + b • c < a • c + b • d := by - rw [add_comm (a • d), add_comm (a • c)] - exact smul_add_smul_lt_smul_add_smul hba hdc -#align smul_add_smul_lt_smul_add_smul' smul_add_smul_lt_smul_add_smul' - -end Ring - -section Field - -variable [LinearOrderedField k] [OrderedAddCommGroup M] [Module k M] [OrderedSMul k M] {a b : M} - {c : k} - -theorem smul_le_smul_iff_of_neg (hc : c < 0) : c • a ≤ c • b ↔ b ≤ a := by - rw [← neg_neg c, neg_smul, neg_smul (-c), neg_le_neg_iff] - exact smul_le_smul_iff_of_pos_left (neg_pos_of_neg hc) -#align smul_le_smul_iff_of_neg smul_le_smul_iff_of_neg - -theorem inv_smul_le_iff_of_neg (h : c < 0) : c⁻¹ • a ≤ b ↔ c • b ≤ a := by - rw [← smul_le_smul_iff_of_neg h, smul_inv_smul₀ h.ne] -#align inv_smul_le_iff_of_neg inv_smul_le_iff_of_neg - -theorem inv_smul_lt_iff_of_neg (h : c < 0) : c⁻¹ • a < b ↔ c • b < a := by - rw [← smul_lt_smul_iff_of_neg h, smul_inv_smul₀ h.ne] -#align inv_smul_lt_iff_of_neg inv_smul_lt_iff_of_neg - -theorem smul_inv_le_iff_of_neg (h : c < 0) : a ≤ c⁻¹ • b ↔ b ≤ c • a := by - rw [← smul_le_smul_iff_of_neg h, smul_inv_smul₀ h.ne] -#align smul_inv_le_iff_of_neg smul_inv_le_iff_of_neg - -theorem smul_inv_lt_iff_of_neg (h : c < 0) : a < c⁻¹ • b ↔ b < c • a := by - rw [← smul_lt_smul_iff_of_neg h, smul_inv_smul₀ h.ne] -#align smul_inv_lt_iff_of_neg smul_inv_lt_iff_of_neg - -variable (M) - -/-- Left scalar multiplication as an order isomorphism. -/ -@[simps] -def OrderIso.smulLeftDual {c : k} (hc : c < 0) : M ≃o Mᵒᵈ where - toFun b := OrderDual.toDual (c • b) - invFun b := c⁻¹ • OrderDual.ofDual b - left_inv := inv_smul_smul₀ hc.ne - right_inv := smul_inv_smul₀ hc.ne - map_rel_iff' := (@OrderDual.toDual_le_toDual M).trans <| smul_le_smul_iff_of_neg hc -#align order_iso.smul_left_dual OrderIso.smulLeftDual - -end Field - -/-! ### Upper/lower bounds -/ - - -section OrderedRing - -variable [OrderedRing k] [OrderedAddCommGroup M] [Module k M] [OrderedSMul k M] {s : Set M} {c : k} - -theorem smul_lowerBounds_subset_upperBounds_smul (hc : c ≤ 0) : - c • lowerBounds s ⊆ upperBounds (c • s) := - (antitone_smul_left hc).image_lowerBounds_subset_upperBounds_image -#align smul_lower_bounds_subset_upper_bounds_smul smul_lowerBounds_subset_upperBounds_smul - -theorem smul_upperBounds_subset_lowerBounds_smul (hc : c ≤ 0) : - c • upperBounds s ⊆ lowerBounds (c • s) := - (antitone_smul_left hc).image_upperBounds_subset_lowerBounds_image -#align smul_upper_bounds_subset_lower_bounds_smul smul_upperBounds_subset_lowerBounds_smul - -theorem BddBelow.smul_of_nonpos (hc : c ≤ 0) (hs : BddBelow s) : BddAbove (c • s) := - (antitone_smul_left hc).map_bddBelow hs -#align bdd_below.smul_of_nonpos BddBelow.smul_of_nonpos - -theorem BddAbove.smul_of_nonpos (hc : c ≤ 0) (hs : BddAbove s) : BddBelow (c • s) := - (antitone_smul_left hc).map_bddAbove hs -#align bdd_above.smul_of_nonpos BddAbove.smul_of_nonpos - -end OrderedRing - -section LinearOrderedRing -variable [LinearOrderedRing k] [LinearOrderedAddCommGroup M] [Module k M] [OrderedSMul k M] - {f : ι → k} {g : ι → M} {s : Set ι} {a a₁ a₂ : k} {b b₁ b₂ : M} - -theorem smul_max_of_nonpos (ha : a ≤ 0) (b₁ b₂ : M) : a • max b₁ b₂ = min (a • b₁) (a • b₂) := - (antitone_smul_left ha : Antitone (_ : M → M)).map_max -#align smul_max_of_nonpos smul_max_of_nonpos - -theorem smul_min_of_nonpos (ha : a ≤ 0) (b₁ b₂ : M) : a • min b₁ b₂ = max (a • b₁) (a • b₂) := - (antitone_smul_left ha : Antitone (_ : M → M)).map_min -#align smul_min_of_nonpos smul_min_of_nonpos - -lemma nonneg_and_nonneg_or_nonpos_and_nonpos_of_smul_nonneg (hab : 0 ≤ a • b) : - 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := by - simp only [Decidable.or_iff_not_and_not, not_and, not_le] - refine fun ab nab ↦ hab.not_lt ?_ - obtain ha | rfl | ha := lt_trichotomy 0 a - exacts [smul_neg_of_pos_of_neg ha (ab ha.le), ((ab le_rfl).asymm (nab le_rfl)).elim, - smul_neg_of_neg_of_pos ha (nab ha.le)] - -lemma smul_nonneg_iff : 0 ≤ a • b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := - ⟨nonneg_and_nonneg_or_nonpos_and_nonpos_of_smul_nonneg, - fun h ↦ h.elim (and_imp.2 smul_nonneg) (and_imp.2 smul_nonneg_of_nonpos_of_nonpos)⟩ - -lemma smul_nonpos_iff : a • b ≤ 0 ↔ 0 ≤ a ∧ b ≤ 0 ∨ a ≤ 0 ∧ 0 ≤ b := by - rw [← neg_nonneg, ← smul_neg, smul_nonneg_iff, neg_nonneg, neg_nonpos] - -lemma smul_nonneg_iff_pos_imp_nonneg : 0 ≤ a • b ↔ (0 < a → 0 ≤ b) ∧ (0 < b → 0 ≤ a) := by - refine smul_nonneg_iff.trans ?_ - simp_rw [← not_le, ← or_iff_not_imp_left] - have := le_total a 0 - have := le_total b 0 - tauto - -lemma smul_nonneg_iff_neg_imp_nonpos : 0 ≤ a • b ↔ (a < 0 → b ≤ 0) ∧ (b < 0 → a ≤ 0) := by - rw [← neg_smul_neg, smul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] - -lemma smul_nonpos_iff_pos_imp_nonpos : a • b ≤ 0 ↔ (0 < a → b ≤ 0) ∧ (b < 0 → 0 ≤ a) := by - rw [← neg_nonneg, ← smul_neg, smul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] - -lemma smul_nonpos_iff_neg_imp_nonneg : a • b ≤ 0 ↔ (a < 0 → 0 ≤ b) ∧ (0 < b → a ≤ 0) := by - rw [← neg_nonneg, ← neg_smul, smul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] - -end LinearOrderedRing - -section LinearOrderedField - -variable [LinearOrderedField k] [OrderedAddCommGroup M] [Module k M] [OrderedSMul k M] {s : Set M} - {c : k} - -@[simp] -theorem lowerBounds_smul_of_neg (hc : c < 0) : lowerBounds (c • s) = c • upperBounds s := - (OrderIso.smulLeftDual M hc).upperBounds_image -#align lower_bounds_smul_of_neg lowerBounds_smul_of_neg - -@[simp] -theorem upperBounds_smul_of_neg (hc : c < 0) : upperBounds (c • s) = c • lowerBounds s := - (OrderIso.smulLeftDual M hc).lowerBounds_image -#align upper_bounds_smul_of_neg upperBounds_smul_of_neg - -@[simp] -theorem bddBelow_smul_iff_of_neg (hc : c < 0) : BddBelow (c • s) ↔ BddAbove s := - (OrderIso.smulLeftDual M hc).bddAbove_image -#align bdd_below_smul_iff_of_neg bddBelow_smul_iff_of_neg - -@[simp] -theorem bddAbove_smul_iff_of_neg (hc : c < 0) : BddAbove (c • s) ↔ BddBelow s := - (OrderIso.smulLeftDual M hc).bddBelow_image -#align bdd_above_smul_iff_of_neg bddAbove_smul_iff_of_neg - -end LinearOrderedField diff --git a/Mathlib/Algebra/Order/Module/Defs.lean b/Mathlib/Algebra/Order/Module/Defs.lean index dc071e86d3c8d..0c711f3e82847 100644 --- a/Mathlib/Algebra/Order/Module/Defs.lean +++ b/Mathlib/Algebra/Order/Module/Defs.lean @@ -453,6 +453,7 @@ lemma smul_pos [PosSMulStrictMono α β] (ha : 0 < a) (hb : 0 < b) : 0 < a • b lemma smul_neg_of_pos_of_neg [PosSMulStrictMono α β] (ha : 0 < a) (hb : b < 0) : a • b < 0 := by simpa only [smul_zero] using smul_lt_smul_of_pos_left hb ha +#align smul_neg_of_pos_of_neg smul_neg_of_pos_of_neg @[simp] lemma smul_pos_iff_of_pos_left [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : @@ -460,6 +461,11 @@ lemma smul_pos_iff_of_pos_left [PosSMulStrictMono α β] [PosSMulReflectLT α β simpa only [smul_zero] using smul_lt_smul_iff_of_pos_left ha (b₁ := 0) (b₂ := b) #align smul_pos_iff_of_pos smul_pos_iff_of_pos_left +lemma smul_neg_iff_of_pos_left [PosSMulStrictMono α β] [PosSMulReflectLT α β] (ha : 0 < a) : + a • b < 0 ↔ b < 0 := by + simpa only [smul_zero] using smul_lt_smul_iff_of_pos_left ha (b₂ := (0 : β)) +#align smul_neg_iff_of_pos smul_neg_iff_of_pos_left + lemma smul_nonneg [PosSMulMono α β] (ha : 0 ≤ a) (hb : 0 ≤ b₁) : 0 ≤ a • b₁ := by simpa only [smul_zero] using smul_le_smul_of_nonneg_left hb ha #align smul_nonneg smul_nonneg @@ -468,7 +474,10 @@ lemma smul_nonpos_of_nonneg_of_nonpos [PosSMulMono α β] (ha : 0 ≤ a) (hb : b simpa only [smul_zero] using smul_le_smul_of_nonneg_left hb ha #align smul_nonpos_of_nonneg_of_nonpos smul_nonpos_of_nonneg_of_nonpos -lemma pos_of_smul_pos_right [PosSMulReflectLT α β] (h : 0 < a • b) (ha : 0 ≤ a) : 0 < b := +lemma pos_of_smul_pos_left [PosSMulReflectLT α β] (h : 0 < a • b) (ha : 0 ≤ a) : 0 < b := + lt_of_smul_lt_smul_left (by rwa [smul_zero]) ha + +lemma neg_of_smul_neg_left [PosSMulReflectLT α β] (h : a • b < 0) (ha : 0 ≤ a) : b < 0 := lt_of_smul_lt_smul_left (by rwa [smul_zero]) ha end Preorder @@ -485,6 +494,7 @@ lemma smul_pos' [SMulPosStrictMono α β] (ha : 0 < a) (hb : 0 < b) : 0 < a • lemma smul_neg_of_neg_of_pos [SMulPosStrictMono α β] (ha : a < 0) (hb : 0 < b) : a • b < 0 := by simpa only [zero_smul] using smul_lt_smul_of_pos_right ha hb +#align smul_neg_of_neg_of_pos smul_neg_of_neg_of_pos @[simp] lemma smul_pos_iff_of_pos_right [SMulPosStrictMono α β] [SMulPosReflectLT α β] (hb : 0 < b) : @@ -496,13 +506,17 @@ lemma smul_nonneg' [SMulPosMono α β] (ha : 0 ≤ a) (hb : 0 ≤ b₁) : 0 ≤ lemma smul_nonpos_of_nonpos_of_nonneg [SMulPosMono α β] (ha : a ≤ 0) (hb : 0 ≤ b) : a • b ≤ 0 := by simpa only [zero_smul] using smul_le_smul_of_nonneg_right ha hb +#align smul_nonpos_of_nonpos_of_nonneg smul_nonpos_of_nonpos_of_nonneg -lemma pos_of_smul_pos_left [SMulPosReflectLT α β] (h : 0 < a • b) (hb : 0 ≤ b) : 0 < a := +lemma pos_of_smul_pos_right [SMulPosReflectLT α β] (h : 0 < a • b) (hb : 0 ≤ b) : 0 < a := + lt_of_smul_lt_smul_right (by rwa [zero_smul]) hb + +lemma neg_of_smul_neg_right [SMulPosReflectLT α β] (h : a • b < 0) (hb : 0 ≤ b) : a < 0 := lt_of_smul_lt_smul_right (by rwa [zero_smul]) hb lemma pos_iff_pos_of_smul_pos [PosSMulReflectLT α β] [SMulPosReflectLT α β] (hab : 0 < a • b) : 0 < a ↔ 0 < b := - ⟨pos_of_smul_pos_right hab ∘ le_of_lt, pos_of_smul_pos_left hab ∘ le_of_lt⟩ + ⟨pos_of_smul_pos_left hab ∘ le_of_lt, pos_of_smul_pos_right hab ∘ le_of_lt⟩ end Preorder @@ -620,18 +634,12 @@ lemma neg_iff_neg_of_smul_pos [PosSMulMono α β] [SMulPosMono α β] (hab : 0 < a < 0 ↔ b < 0 := ⟨neg_of_smul_pos_right hab ∘ le_of_lt, neg_of_smul_pos_left hab ∘ le_of_lt⟩ -lemma neg_of_smul_neg_left [PosSMulMono α β] (h : a • b < 0) (ha : 0 ≤ a) : b < 0 := - lt_of_not_ge fun hb ↦ (smul_nonneg ha hb).not_lt h - lemma neg_of_smul_neg_left' [SMulPosMono α β] (h : a • b < 0) (ha : 0 ≤ a) : b < 0 := lt_of_not_ge fun hb ↦ (smul_nonneg' ha hb).not_lt h -lemma neg_of_smul_neg_right [PosSMulMono α β] (h : a • b < 0) (hb : 0 ≤ b) : a < 0 := +lemma neg_of_smul_neg_right' [PosSMulMono α β] (h : a • b < 0) (hb : 0 ≤ b) : a < 0 := lt_of_not_ge fun ha ↦ (smul_nonneg ha hb).not_lt h -lemma neg_of_smul_neg_right' [SMulPosMono α β] (h : a • b < 0) (hb : 0 ≤ b) : a < 0 := - lt_of_not_ge fun ha ↦ (smul_nonneg' ha hb).not_lt h - end LinearOrder end SMulWithZero @@ -723,17 +731,6 @@ lemma SMulPosReflectLE_iff_smulPosReflectLT : SMulPosReflectLE α β ↔ SMulPos end PartialOrder end Ring -section OrderedRing -variable [OrderedRing α] [OrderedAddCommGroup β] [Module α β] - -instance PosSMulMono.toSMulPosMono [PosSMulMono α β] : SMulPosMono α β where - elim _b hb a₁ a₂ ha := by rw [← sub_nonneg, ← sub_smul]; exact smul_nonneg (sub_nonneg.2 ha) hb - -instance PosSMulStrictMono.toSMulPosStrictMono [PosSMulStrictMono α β] : SMulPosStrictMono α β where - elim _b hb a₁ a₂ ha := by rw [← sub_pos, ← sub_smul]; exact smul_pos (sub_pos.2 ha) hb - -end OrderedRing - section GroupWithZero variable [GroupWithZero α] [Preorder α] [Preorder β] [MulAction α β] @@ -764,22 +761,6 @@ def OrderIso.smulRight [PosSMulMono α β] [PosSMulReflectLE α β] {a : α} (ha end GroupWithZero -section LinearOrderedSemifield -variable [LinearOrderedSemifield α] [AddCommGroup β] [PartialOrder β] - --- See note [lower instance priority] -instance (priority := 100) PosSMulMono.toPosSMulReflectLE [MulAction α β] [PosSMulMono α β] : - PosSMulReflectLE α β where - elim _a ha b₁ b₂ h := by simpa [ha.ne'] using smul_le_smul_of_nonneg_left h $ inv_nonneg.2 ha.le - --- See note [lower instance priority] -instance (priority := 100) PosSMulStrictMono.toPosSMulReflectLT [MulActionWithZero α β] - [PosSMulStrictMono α β] : PosSMulReflectLT α β := - PosSMulReflectLT.of_pos fun a ha b₁ b₂ h ↦ by - simpa [ha.ne'] using smul_lt_smul_of_pos_left h $ inv_pos.2 ha - -end LinearOrderedSemifield - namespace OrderDual section Left @@ -822,6 +803,232 @@ instance instSMulPosReflectLE [SMulPosReflectLE α β] : SMulPosReflectLE α β end Right end OrderDual +section OrderedRing +variable [OrderedRing α] + +section OrderedAddCommGroup +variable [OrderedAddCommGroup β] [Module α β] + +#noalign eq_of_smul_eq_smul_of_neg_of_le + +section PosSMulMono +variable [PosSMulMono α β] + +lemma smul_le_smul_of_nonpos (h : b₁ ≤ b₂) (ha : a ≤ 0) : a • b₂ ≤ a • b₁ := by + rw [← neg_neg a, neg_smul, neg_smul (-a), neg_le_neg_iff] + exact smul_le_smul_of_nonneg_left h (neg_nonneg_of_nonpos ha) +#align smul_le_smul_of_nonpos smul_le_smul_of_nonpos + +lemma antitone_smul_left (ha : a ≤ 0) : Antitone (SMul.smul a : β → β) := + fun _ _ h => smul_le_smul_of_nonpos h ha +#align antitone_smul_left antitone_smul_left + +instance PosSMulMono.toSMulPosMono : SMulPosMono α β where + elim _b hb a₁ a₂ ha := by rw [← sub_nonneg, ← sub_smul]; exact smul_nonneg (sub_nonneg.2 ha) hb + +end PosSMulMono + +section PosSMulStrictMono +variable [PosSMulStrictMono α β] + +lemma smul_lt_smul_of_neg (hb : b₁ < b₂) (ha : a < 0) : a • b₂ < a • b₁ := by + rw [← neg_neg a, neg_smul, neg_smul (-a), neg_lt_neg_iff] + exact smul_lt_smul_of_pos_left hb (neg_pos_of_neg ha) +#align smul_lt_smul_of_neg smul_lt_smul_of_neg + +lemma strict_anti_smul_left (ha : a < 0) : StrictAnti (SMul.smul a : β → β) := + fun _ _ h => smul_lt_smul_of_neg h ha +#align strict_anti_smul_left strict_anti_smul_left + +instance PosSMulStrictMono.toSMulPosStrictMono : SMulPosStrictMono α β where + elim _b hb a₁ a₂ ha := by rw [← sub_pos, ← sub_smul]; exact smul_pos (sub_pos.2 ha) hb + +end PosSMulStrictMono + +lemma le_of_smul_le_smul_of_neg [PosSMulReflectLE α β] (h : a • b₁ ≤ a • b₂) (ha : a < 0) : + b₂ ≤ b₁ := by + rw [← neg_neg a, neg_smul, neg_smul (-a), neg_le_neg_iff] at h + exact le_of_smul_le_smul_of_pos_left h $ neg_pos.2 ha + +lemma lt_of_smul_lt_smul_of_nonpos [PosSMulReflectLT α β] (h : a • b₁ < a • b₂) (ha : a ≤ 0) : + b₂ < b₁ := by + rw [← neg_neg a, neg_smul, neg_smul (-a), neg_lt_neg_iff] at h + exact lt_of_smul_lt_smul_of_nonneg_left h (neg_nonneg_of_nonpos ha) +#align lt_of_smul_lt_smul_of_nonpos lt_of_smul_lt_smul_of_nonpos + +lemma smul_nonneg_of_nonpos_of_nonpos [SMulPosMono α β] (ha : a ≤ 0) (hb : b ≤ 0) : 0 ≤ a • b := + smul_nonpos_of_nonpos_of_nonneg (β := βᵒᵈ) ha hb +#align smul_nonneg_of_nonpos_of_nonpos smul_nonneg_of_nonpos_of_nonpos + +lemma smul_le_smul_iff_of_neg [PosSMulMono α β] [PosSMulReflectLE α β] (ha : a < 0) : + a • b₁ ≤ a • b₂ ↔ b₂ ≤ b₁ := by + rw [← neg_neg a, neg_smul, neg_smul (-a), neg_le_neg_iff] + exact smul_le_smul_iff_of_pos_left (neg_pos_of_neg ha) +#align smul_le_smul_iff_of_neg smul_le_smul_iff_of_neg + +section PosSMulStrictMono +variable [PosSMulStrictMono α β] [PosSMulReflectLT α β] + +lemma smul_lt_smul_iff_of_neg (ha : a < 0) : a • b₁ < a • b₂ ↔ b₂ < b₁ := by + rw [← neg_neg a, neg_smul, neg_smul (-a), neg_lt_neg_iff] + exact smul_lt_smul_iff_of_pos_left (neg_pos_of_neg ha) +#align smul_lt_smul_iff_of_neg smul_lt_smul_iff_of_neg + +lemma smul_pos_iff_of_neg (ha : a < 0) : 0 < a • b₁ ↔ b₁ < 0 := by + simpa only [smul_zero] using smul_lt_smul_iff_of_neg ha (b₁ := (0 : β)) +#align smul_pos_iff_of_neg smul_pos_iff_of_neg + +alias ⟨_, smul_pos_of_neg_of_neg⟩ := smul_pos_iff_of_neg +#align smul_pos_of_neg_of_neg smul_pos_of_neg_of_neg + +lemma smul_neg_iff_of_neg (ha : a < 0) : a • b₁ < 0 ↔ 0 < b₁ := by + simpa only [smul_zero] using smul_lt_smul_iff_of_neg ha (b₂ := (0 : β)) +#align smul_neg_iff_of_neg smul_neg_iff_of_neg + +end PosSMulStrictMono + +/-- Binary **rearrangement inequality**. -/ +lemma smul_add_smul_le_smul_add_smul [PosSMulMono α β] [ContravariantClass β β (· + ·) (· ≤ ·)] + {b₁ b₂ : α} {a d : β} (hab : b₁ ≤ b₂) (hcd : a ≤ d) : b₁ • d + b₂ • a ≤ b₁ • a + b₂ • d := by + obtain ⟨b₂, rfl⟩ := exists_add_of_le hab + obtain ⟨d, rfl⟩ := exists_add_of_le hcd + rw [smul_add, add_right_comm, smul_add, ← add_assoc, add_smul _ _ d] + rw [le_add_iff_nonneg_right] at hab hcd + exact add_le_add_left (le_add_of_nonneg_right <| smul_nonneg hab hcd) _ +#align smul_add_smul_le_smul_add_smul smul_add_smul_le_smul_add_smul + +/-- Binary **rearrangement inequality**. -/ +lemma smul_add_smul_le_smul_add_smul' [PosSMulMono α β] [ContravariantClass β β (· + ·) (· ≤ ·)] + {b₁ b₂ : α} {a d : β} (hba : b₂ ≤ b₁) (hdc : d ≤ a) : b₁ • d + b₂ • a ≤ b₁ • a + b₂ • d := by + rw [add_comm (b₁ • d), add_comm (b₁ • a)] + exact smul_add_smul_le_smul_add_smul hba hdc +#align smul_add_smul_le_smul_add_smul' smul_add_smul_le_smul_add_smul' + +/-- Binary strict **rearrangement inequality**. -/ +lemma smul_add_smul_lt_smul_add_smul [PosSMulStrictMono α β] [CovariantClass β β (· + ·) (· < ·)] + [ContravariantClass β β (· + ·) (· < ·)] {b₁ b₂ : α} {a d : β} (hab : b₁ < b₂) (hcd : a < d) : + b₁ • d + b₂ • a < b₁ • a + b₂ • d := by + obtain ⟨b₂, rfl⟩ := exists_add_of_le hab.le + obtain ⟨d, rfl⟩ := exists_add_of_le hcd.le + rw [smul_add, add_right_comm, smul_add, ← add_assoc, add_smul _ _ d] + rw [lt_add_iff_pos_right] at hab hcd + exact add_lt_add_left (lt_add_of_pos_right _ <| smul_pos hab hcd) _ +#align smul_add_smul_lt_smul_add_smul smul_add_smul_lt_smul_add_smul + +/-- Binary strict **rearrangement inequality**. -/ +lemma smul_add_smul_lt_smul_add_smul' [PosSMulStrictMono α β] [CovariantClass β β (· + ·) (· < ·)] + [ContravariantClass β β (· + ·) (· < ·)] {b₁ b₂ : α} {a d : β} (hba : b₂ < b₁) (hdc : d < a) : + b₁ • d + b₂ • a < b₁ • a + b₂ • d := by + rw [add_comm (b₁ • d), add_comm (b₁ • a)] + exact smul_add_smul_lt_smul_add_smul hba hdc +#align smul_add_smul_lt_smul_add_smul' smul_add_smul_lt_smul_add_smul' + +end OrderedAddCommGroup + +section LinearOrderedAddCommGroup +variable [LinearOrderedAddCommGroup β] [Module α β] [PosSMulMono α β] {a : α} {b b₁ b₂ : β} + +lemma smul_max_of_nonpos (ha : a ≤ 0) (b₁ b₂ : β) : a • max b₁ b₂ = min (a • b₁) (a • b₂) := + (antitone_smul_left ha : Antitone (_ : β → β)).map_max +#align smul_max_of_nonpos smul_max_of_nonpos + +lemma smul_min_of_nonpos (ha : a ≤ 0) (b₁ b₂ : β) : a • min b₁ b₂ = max (a • b₁) (a • b₂) := + (antitone_smul_left ha : Antitone (_ : β → β)).map_min +#align smul_min_of_nonpos smul_min_of_nonpos + +end LinearOrderedAddCommGroup +end OrderedRing + +section LinearOrderedRing +variable [LinearOrderedRing α] [LinearOrderedAddCommGroup β] [Module α β] [PosSMulStrictMono α β] + {a : α} {b : β} + +lemma nonneg_and_nonneg_or_nonpos_and_nonpos_of_smul_nonneg (hab : 0 ≤ a • b) : + 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := by + simp only [Decidable.or_iff_not_and_not, not_and, not_le] + refine fun ab nab ↦ hab.not_lt ?_ + obtain ha | rfl | ha := lt_trichotomy 0 a + exacts [smul_neg_of_pos_of_neg ha (ab ha.le), ((ab le_rfl).asymm (nab le_rfl)).elim, + smul_neg_of_neg_of_pos ha (nab ha.le)] + +lemma smul_nonneg_iff : 0 ≤ a • b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := + ⟨nonneg_and_nonneg_or_nonpos_and_nonpos_of_smul_nonneg, + fun h ↦ h.elim (and_imp.2 smul_nonneg) (and_imp.2 smul_nonneg_of_nonpos_of_nonpos)⟩ + +lemma smul_nonpos_iff : a • b ≤ 0 ↔ 0 ≤ a ∧ b ≤ 0 ∨ a ≤ 0 ∧ 0 ≤ b := by + rw [← neg_nonneg, ← smul_neg, smul_nonneg_iff, neg_nonneg, neg_nonpos] + +lemma smul_nonneg_iff_pos_imp_nonneg : 0 ≤ a • b ↔ (0 < a → 0 ≤ b) ∧ (0 < b → 0 ≤ a) := + smul_nonneg_iff.trans $ by + simp_rw [← not_le, ← or_iff_not_imp_left]; have := le_total a 0; have := le_total b 0; tauto + +lemma smul_nonneg_iff_neg_imp_nonpos : 0 ≤ a • b ↔ (a < 0 → b ≤ 0) ∧ (b < 0 → a ≤ 0) := by + rw [← neg_smul_neg, smul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + +lemma smul_nonpos_iff_pos_imp_nonpos : a • b ≤ 0 ↔ (0 < a → b ≤ 0) ∧ (b < 0 → 0 ≤ a) := by + rw [← neg_nonneg, ← smul_neg, smul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + +lemma smul_nonpos_iff_neg_imp_nonneg : a • b ≤ 0 ↔ (a < 0 → 0 ≤ b) ∧ (0 < b → a ≤ 0) := by + rw [← neg_nonneg, ← neg_smul, smul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + +end LinearOrderedRing + +section LinearOrderedSemifield +variable [LinearOrderedSemifield α] [AddCommGroup β] [PartialOrder β] + +-- See note [lower instance priority] +instance (priority := 100) PosSMulMono.toPosSMulReflectLE [MulAction α β] [PosSMulMono α β] : + PosSMulReflectLE α β where + elim _a ha b₁ b₂ h := by simpa [ha.ne'] using smul_le_smul_of_nonneg_left h $ inv_nonneg.2 ha.le + +-- See note [lower instance priority] +instance (priority := 100) PosSMulStrictMono.toPosSMulReflectLT [MulActionWithZero α β] + [PosSMulStrictMono α β] : PosSMulReflectLT α β := + PosSMulReflectLT.of_pos fun a ha b₁ b₂ h ↦ by + simpa [ha.ne'] using smul_lt_smul_of_pos_left h $ inv_pos.2 ha + +end LinearOrderedSemifield + +section Field +variable [LinearOrderedField α] [OrderedAddCommGroup β] [Module α β] {a : α} {b₁ b₂ : β} + +section PosSMulMono +variable [PosSMulMono α β] + +lemma inv_smul_le_iff_of_neg (h : a < 0) : a⁻¹ • b₁ ≤ b₂ ↔ a • b₂ ≤ b₁ := by + rw [← smul_le_smul_iff_of_neg h, smul_inv_smul₀ h.ne] +#align inv_smul_le_iff_of_neg inv_smul_le_iff_of_neg + +lemma smul_inv_le_iff_of_neg (h : a < 0) : b₁ ≤ a⁻¹ • b₂ ↔ b₂ ≤ a • b₁ := by + rw [← smul_le_smul_iff_of_neg h, smul_inv_smul₀ h.ne] + +variable (β) + +/-- Left scalar multiplication as an order isomorphism. -/ +@[simps] +def OrderIso.smulLeftDual (ha : a < 0) : β ≃o βᵒᵈ where + toFun b₂ := OrderDual.toDual (a • b₂) + invFun b₂ := a⁻¹ • OrderDual.ofDual b₂ + left_inv := inv_smul_smul₀ ha.ne + right_inv := smul_inv_smul₀ ha.ne + map_rel_iff' := (@OrderDual.toDual_le_toDual β).trans <| smul_le_smul_iff_of_neg ha +#align order_iso.smul_left_dual OrderIso.smulLeftDual +#align smul_inv_le_iff_of_neg smul_inv_le_iff_of_neg + +end PosSMulMono + +variable [PosSMulStrictMono α β] + +lemma inv_smul_lt_iff_of_neg (h : a < 0) : a⁻¹ • b₁ < b₂ ↔ a • b₂ < b₁ := by + rw [← smul_lt_smul_iff_of_neg h, smul_inv_smul₀ h.ne] +#align inv_smul_lt_iff_of_neg inv_smul_lt_iff_of_neg + +lemma smul_inv_lt_iff_of_neg (h : a < 0) : b₁ < a⁻¹ • b₂ ↔ b₂ < a • b₁ := by + rw [← smul_lt_smul_iff_of_neg h, smul_inv_smul₀ h.ne] +#align smul_inv_lt_iff_of_neg smul_inv_lt_iff_of_neg + +end Field + namespace Prod end Prod @@ -994,3 +1201,4 @@ Those lemmas have been deprecated on the 2023/12/23. @[deprecated] alias OrderIso.smulLeft := OrderIso.smulRight @[deprecated] alias OrderIso.smulLeft_symm_apply := OrderIso.smulRight_symm_apply @[deprecated] alias OrderIso.smulLeft_apply := OrderIso.smulRight_apply +@[deprecated] alias smul_neg_iff_of_pos := smul_neg_iff_of_pos_left diff --git a/Mathlib/Algebra/Order/Module/Pointwise.lean b/Mathlib/Algebra/Order/Module/Pointwise.lean index df2102762d8cb..c0d4e0b66d4eb 100644 --- a/Mathlib/Algebra/Order/Module/Pointwise.lean +++ b/Mathlib/Algebra/Order/Module/Pointwise.lean @@ -61,3 +61,49 @@ variable [Preorder α] [Preorder β] [GroupWithZero α] [Zero β] [MulActionWith #align bdd_above_smul_iff_of_pos bddAbove_smul_iff_of_pos end + +section OrderedRing + +variable [OrderedRing α] [OrderedAddCommGroup β] [Module α β] [PosSMulMono α β] {s : Set β} {a : α} + +lemma smul_lowerBounds_subset_upperBounds_smul (ha : a ≤ 0) : + a • lowerBounds s ⊆ upperBounds (a • s) := + (antitone_smul_left ha).image_lowerBounds_subset_upperBounds_image +#align smul_lower_bounds_subset_upper_bounds_smul smul_lowerBounds_subset_upperBounds_smul + +lemma smul_upperBounds_subset_lowerBounds_smul (ha : a ≤ 0) : + a • upperBounds s ⊆ lowerBounds (a • s) := + (antitone_smul_left ha).image_upperBounds_subset_lowerBounds_image +#align smul_upper_bounds_subset_lower_bounds_smul smul_upperBounds_subset_lowerBounds_smul + +lemma BddBelow.smul_of_nonpos (ha : a ≤ 0) (hs : BddBelow s) : BddAbove (a • s) := + (antitone_smul_left ha).map_bddBelow hs +#align bdd_below.smul_of_nonpos BddBelow.smul_of_nonpos + +lemma BddAbove.smul_of_nonpos (ha : a ≤ 0) (hs : BddAbove s) : BddBelow (a • s) := + (antitone_smul_left ha).map_bddAbove hs +#align bdd_above.smul_of_nonpos BddAbove.smul_of_nonpos + +end OrderedRing + +section LinearOrderedField +variable [LinearOrderedField α] [OrderedAddCommGroup β] [Module α β] [PosSMulMono α β] {s : Set β} + {a : α} + +@[simp] lemma lowerBounds_smul_of_neg (ha : a < 0) : lowerBounds (a • s) = a • upperBounds s := + (OrderIso.smulLeftDual β ha).upperBounds_image +#align lower_bounds_smul_of_neg lowerBounds_smul_of_neg + +@[simp] lemma upperBounds_smul_of_neg (ha : a < 0) : upperBounds (a • s) = a • lowerBounds s := + (OrderIso.smulLeftDual β ha).lowerBounds_image +#align upper_bounds_smul_of_neg upperBounds_smul_of_neg + +@[simp] lemma bddBelow_smul_iff_of_neg (ha : a < 0) : BddBelow (a • s) ↔ BddAbove s := + (OrderIso.smulLeftDual β ha).bddAbove_image +#align bdd_below_smul_iff_of_neg bddBelow_smul_iff_of_neg + +@[simp] lemma bddAbove_smul_iff_of_neg (ha : a < 0) : BddAbove (a • s) ↔ BddBelow s := + (OrderIso.smulLeftDual β ha).bddBelow_image +#align bdd_above_smul_iff_of_neg bddAbove_smul_iff_of_neg + +end LinearOrderedField diff --git a/Mathlib/Algebra/Order/Module/Synonym.lean b/Mathlib/Algebra/Order/Module/Synonym.lean index 9bba3eca08309..6cd27a45ddc60 100644 --- a/Mathlib/Algebra/Order/Module/Synonym.lean +++ b/Mathlib/Algebra/Order/Module/Synonym.lean @@ -22,11 +22,11 @@ are already defined in `Mathlib.Algebra.Group.OrderSynonym`. namespace OrderDual variable {α β γ : Type*} -instance instSMulWithZero [Zero α] [AddZeroClass β] [SMulWithZero α β] : SMulWithZero αᵒᵈ β where +instance instSMulWithZero [Zero α] [Zero β] [SMulWithZero α β] : SMulWithZero αᵒᵈ β where zero_smul := zero_smul α smul_zero := smul_zero (M := α) -instance instSMulWithZero' [Zero α] [AddZeroClass β] [SMulWithZero α β] : SMulWithZero α βᵒᵈ where +instance instSMulWithZero' [Zero α] [Zero β] [SMulWithZero α β] : SMulWithZero α βᵒᵈ where zero_smul := zero_smul _ (M := β) smul_zero := smul_zero (A := β) diff --git a/Mathlib/Algebra/Order/Monovary.lean b/Mathlib/Algebra/Order/Monovary.lean index dec508e80301d..73928ce9ff8cf 100644 --- a/Mathlib/Algebra/Order/Monovary.lean +++ b/Mathlib/Algebra/Order/Monovary.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Algebra.Order.Group.Defs -import Mathlib.Algebra.Order.Module +import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.Algebra.Order.Monoid.MinMax import Mathlib.Order.Monotone.Monovary diff --git a/Mathlib/Algebra/Order/Nonneg/Module.lean b/Mathlib/Algebra/Order/Nonneg/Module.lean index 2ed7956593457..735e574795eda 100644 --- a/Mathlib/Algebra/Order/Nonneg/Module.lean +++ b/Mathlib/Algebra/Order/Nonneg/Module.lean @@ -5,7 +5,7 @@ Authors: Apurva Nakade -/ import Mathlib.Algebra.Order.Nonneg.Ring import Mathlib.Algebra.Module.Basic -import Mathlib.Algebra.Order.Module +import Mathlib.Algebra.Order.Module.OrderedSMul /-! # Modules over nonnegative elements diff --git a/Mathlib/Algebra/Order/Rearrangement.lean b/Mathlib/Algebra/Order/Rearrangement.lean index 69e3ffa2282e8..1174e8d0c058c 100644 --- a/Mathlib/Algebra/Order/Rearrangement.lean +++ b/Mathlib/Algebra/Order/Rearrangement.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mantas Bakšys -/ import Mathlib.Algebra.BigOperators.Basic -import Mathlib.Algebra.Order.Module +import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.Data.Prod.Lex import Mathlib.GroupTheory.Perm.Support import Mathlib.Order.Monotone.Monovary diff --git a/Mathlib/Analysis/Convex/Basic.lean b/Mathlib/Analysis/Convex/Basic.lean index 198231f37e2ff..14702e7480347 100644 --- a/Mathlib/Analysis/Convex/Basic.lean +++ b/Mathlib/Analysis/Convex/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Alexander Bentkamp. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alexander Bentkamp, Yury Kudriashov, Yaël Dillies -/ -import Mathlib.Algebra.Order.Module +import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.Analysis.Convex.Star import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace diff --git a/Mathlib/Data/Real/Pointwise.lean b/Mathlib/Data/Real/Pointwise.lean index a7e358f1267e2..c5dcdbb88058e 100644 --- a/Mathlib/Data/Real/Pointwise.lean +++ b/Mathlib/Data/Real/Pointwise.lean @@ -3,7 +3,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, Eric Wieser -/ -import Mathlib.Algebra.Order.Module +import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.Algebra.Order.Module.Pointwise import Mathlib.Data.Real.Archimedean diff --git a/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean b/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean index d74b0b15cb839..fd7653f7081ba 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury G. Kudryashov -/ import Mathlib.Algebra.Order.Invertible -import Mathlib.Algebra.Order.Module +import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.LinearAlgebra.AffineSpace.MidpointZero import Mathlib.LinearAlgebra.AffineSpace.Slope import Mathlib.Tactic.FieldSimp From a76fbc3dff12eec9f09e3d9cf5088ccbbfaadd49 Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 26 Dec 2023 22:33:52 +0000 Subject: [PATCH 215/353] chore: audit remaining uses of "local homeomorphism" in comments (#9245) Almost all of them should speak about partial homeomorphisms instead. In two cases, I decided removing the "local" was clearer than adding "partial". Follow-up to #8982; complements #9238. --- Mathlib/Analysis/Calculus/ContDiff/Basic.lean | 2 +- Mathlib/Analysis/Calculus/Deriv/Inverse.lean | 4 +- Mathlib/Analysis/Calculus/FDeriv/Equiv.lean | 4 +- Mathlib/Analysis/Calculus/Implicit.lean | 8 +- .../ApproximatesLinearOn.lean | 4 +- .../Analysis/NormedSpace/HomeomorphBall.lean | 2 +- .../Analysis/SpecialFunctions/PolarCoord.lean | 6 +- Mathlib/Geometry/Manifold/ChartedSpace.lean | 74 +++++++++---------- .../Geometry/Manifold/ConformalGroupoid.lean | 2 +- .../Geometry/Manifold/ContMDiff/Atlas.lean | 2 +- .../Geometry/Manifold/Instances/Sphere.lean | 8 +- .../Manifold/LocalInvariantProperties.lean | 6 +- Mathlib/Geometry/Manifold/MFDeriv.lean | 6 +- .../Manifold/SmoothManifoldWithCorners.lean | 27 +++---- .../Geometry/Manifold/VectorBundle/Basic.lean | 2 +- Mathlib/Topology/FiberBundle/Basic.lean | 10 +-- .../Topology/FiberBundle/Trivialization.lean | 10 +-- Mathlib/Topology/VectorBundle/Basic.lean | 4 +- 18 files changed, 91 insertions(+), 90 deletions(-) diff --git a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean index 7e9f76296947d..ef8ecb9af98ed 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean @@ -1899,7 +1899,7 @@ namespace PartialHomeomorph variable (𝕜) -/-- Restrict a local homeomorphism to the subsets of the source and target +/-- Restrict a partial homeomorphism to the subsets of the source and target that consist of points `x ∈ f.source`, `y = f x ∈ f.target` such that `f` is `C^n` at `x` and `f.symm` is `C^n` at `y`. diff --git a/Mathlib/Analysis/Calculus/Deriv/Inverse.lean b/Mathlib/Analysis/Calculus/Deriv/Inverse.lean index aefe0e88c592e..64699f184d12e 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Inverse.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Inverse.lean @@ -70,7 +70,7 @@ theorem HasStrictDerivAt.of_local_left_inverse {f g : 𝕜 → 𝕜} {f' a : (hf.hasStrictFDerivAt_equiv hf').of_local_left_inverse hg hfg #align has_strict_deriv_at.of_local_left_inverse HasStrictDerivAt.of_local_left_inverse -/-- If `f` is a local homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has a +/-- If `f` is a partial homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has a nonzero derivative `f'` at `f.symm a` in the strict sense, then `f.symm` has the derivative `f'⁻¹` at `a` in the strict sense. @@ -93,7 +93,7 @@ theorem HasDerivAt.of_local_left_inverse {f g : 𝕜 → 𝕜} {f' a : 𝕜} (hg (hf.hasFDerivAt_equiv hf').of_local_left_inverse hg hfg #align has_deriv_at.of_local_left_inverse HasDerivAt.of_local_left_inverse -/-- If `f` is a local homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has a +/-- If `f` is a partial homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has a nonzero derivative `f'` at `f.symm a`, then `f.symm` has the derivative `f'⁻¹` at `a`. This is one of the easy parts of the inverse function theorem: it assumes that we already have diff --git a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean index 5bd75dc053eed..4bb25ce2831a8 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean @@ -404,7 +404,7 @@ theorem HasFDerivAt.of_local_left_inverse {f : E → F} {f' : E ≃L[𝕜] F} {g simp only [(· ∘ ·), hp, hfg.self_of_nhds] #align has_fderiv_at.of_local_left_inverse HasFDerivAt.of_local_left_inverse -/-- If `f` is a local homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has an +/-- If `f` is a partial homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has an invertible derivative `f'` in the sense of strict differentiability at `f.symm a`, then `f.symm` has the derivative `f'⁻¹` at `a`. @@ -416,7 +416,7 @@ theorem PartialHomeomorph.hasStrictFDerivAt_symm (f : PartialHomeomorph E F) {f' htff'.of_local_left_inverse (f.symm.continuousAt ha) (f.eventually_right_inverse ha) #align local_homeomorph.has_strict_fderiv_at_symm PartialHomeomorph.hasStrictFDerivAt_symm -/-- If `f` is a local homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has an +/-- If `f` is a partial homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has an invertible derivative `f'` at `f.symm a`, then `f.symm` has the derivative `f'⁻¹` at `a`. This is one of the easy parts of the inverse function theorem: it assumes that we already have diff --git a/Mathlib/Analysis/Calculus/Implicit.lean b/Mathlib/Analysis/Calculus/Implicit.lean index 42f6618ccd1a1..62f1a4e3a98af 100644 --- a/Mathlib/Analysis/Calculus/Implicit.lean +++ b/Mathlib/Analysis/Calculus/Implicit.lean @@ -68,7 +68,7 @@ Consider two functions `f : E → F` and `g : E → G` and a point `a` such that * the derivatives are surjective; * the kernels of the derivatives are complementary subspaces of `E`. -Note that the map `x ↦ (f x, g x)` has a bijective derivative, hence it is a local homeomorphism +Note that the map `x ↦ (f x, g x)` has a bijective derivative, hence it is a partial homeomorphism between `E` and `F × G`. We use this fact to define a function `φ : F → G → E` (see `ImplicitFunctionData.implicitFunction`) such that for `(y, z)` close enough to `(f a, g a)` we have `f (φ y z) = y` and `g (φ y z) = z`. @@ -141,7 +141,7 @@ protected theorem hasStrictFDerivAt : /-- Implicit function theorem. If `f : E → F` and `g : E → G` are two maps strictly differentiable at `a`, their derivatives `f'`, `g'` are surjective, and the kernels of these derivatives are -complementary subspaces of `E`, then `x ↦ (f x, g x)` defines a local homeomorphism between +complementary subspaces of `E`, then `x ↦ (f x, g x)` defines a partial homeomorphism between `E` and `F × G`. In particular, `{x | f x = f a}` is locally homeomorphic to `G`. -/ def toPartialHomeomorph : PartialHomeomorph E (F × G) := φ.hasStrictFDerivAt.toPartialHomeomorph _ @@ -260,7 +260,7 @@ def implicitFunctionDataOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : ra isCompl_ker := LinearMap.isCompl_of_proj (Classical.choose_spec hker) #align has_strict_fderiv_at.implicit_function_data_of_complemented HasStrictFDerivAt.implicitFunctionDataOfComplemented -/-- A local homeomorphism between `E` and `F × f'.ker` sending level surfaces of `f` +/-- A partial homeomorphism between `E` and `F × f'.ker` sending level surfaces of `f` to vertical subspaces. -/ def implicitToPartialHomeomorphOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) : PartialHomeomorph E (F × ker f') := @@ -392,7 +392,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] {E : [NormedSpace 𝕜 F] [FiniteDimensional 𝕜 F] (f : E → F) (f' : E →L[𝕜] F) {a : E} /-- Given a map `f : E → F` to a finite dimensional space with a surjective derivative `f'`, -returns a local homeomorphism between `E` and `F × ker f'`. -/ +returns a partial homeomorphism between `E` and `F × ker f'`. -/ def implicitToPartialHomeomorph (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : PartialHomeomorph E (F × ker f') := haveI := FiniteDimensional.complete 𝕜 F diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean index 903806a99e403..04c8765454642 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean @@ -355,7 +355,7 @@ protected theorem surjective [CompleteSpace E] (hf : ApproximatesLinearOn f (f' exact fun R h y hy => h hy #align approximates_linear_on.surjective ApproximatesLinearOn.surjective -/-- A map approximating a linear equivalence on a set defines a local equivalence on this set. +/-- A map approximating a linear equivalence on a set defines a partial equivalence on this set. Should not be used outside of this file, because it is superseded by `toPartialHomeomorph` below. This is a first step towards the inverse function. -/ @@ -403,7 +403,7 @@ section variable (f s) /-- Given a function `f` that approximates a linear equivalence on an open set `s`, -returns a local homeomorph with `toFun = f` and `source = s`. -/ +returns a partial homeomorphism with `toFun = f` and `source = s`. -/ def toPartialHomeomorph (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) (hc : Subsingleton E ∨ c < N⁻¹) (hs : IsOpen s) : PartialHomeomorph E F where toPartialEquiv := hf.toPartialEquiv hc diff --git a/Mathlib/Analysis/NormedSpace/HomeomorphBall.lean b/Mathlib/Analysis/NormedSpace/HomeomorphBall.lean index eaf3d6f95a0ab..96a84b8da3d83 100644 --- a/Mathlib/Analysis/NormedSpace/HomeomorphBall.lean +++ b/Mathlib/Analysis/NormedSpace/HomeomorphBall.lean @@ -114,7 +114,7 @@ def unitBallBall (c : P) (r : ℝ) (hr : 0 < r) : PartialHomeomorph E P := rw [image_comp, image_smul, smul_unitBall hr.ne', IsometryEquiv.image_ball] simp [abs_of_pos hr] -/-- If `r > 0`, then `PartialHomeomorph.univBall c r` is a smooth local homeomorphism +/-- If `r > 0`, then `PartialHomeomorph.univBall c r` is a smooth partial homeomorphism with `source = Set.univ` and `target = Metric.ball c r`. Otherwise, it is the translation by `c`. Thus in all cases, it sends `0` to `c`, see `PartialHomeomorph.univBall_apply_zero`. -/ diff --git a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean index 964110be02c95..803728dbdc93b 100644 --- a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean +++ b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean @@ -11,7 +11,7 @@ import Mathlib.MeasureTheory.Measure.Lebesgue.Complex /-! # Polar coordinates -We define polar coordinates, as a local homeomorphism in `ℝ^2` between `ℝ^2 - (-∞, 0]` and +We define polar coordinates, as a partial homeomorphism in `ℝ^2` between `ℝ^2 - (-∞, 0]` and `(0, +∞) × (-π, π)`. Its inverse is given by `(r, θ) ↦ (r cos θ, r sin θ)`. It satisfies the following change of variables formula (see `integral_comp_polarCoord_symm`): @@ -25,7 +25,7 @@ open Real Set MeasureTheory open scoped Real Topology -/-- The polar coordinates local homeomorphism in `ℝ^2`, mapping `(r cos θ, r sin θ)` to `(r, θ)`. +/-- The polar coordinates partial homeomorphism in `ℝ^2`, mapping `(r cos θ, r sin θ)` to `(r, θ)`. It is a homeomorphism between `ℝ^2 - (-∞, 0]` and `(0, +∞) × (-π, π)`. -/ @[simps] def polarCoord : PartialHomeomorph (ℝ × ℝ) (ℝ × ℝ) where @@ -158,7 +158,7 @@ namespace Complex open scoped Real -/-- The polar coordinates local homeomorphism in `ℂ`, mapping `r (cos θ + I * sin θ)` to `(r, θ)`. +/-- The polar coordinates partial homeomorphism in `ℂ`, mapping `r (cos θ + I * sin θ)` to `(r, θ)`. It is a homeomorphism between `ℂ - ℝ≤0` and `(0, +∞) × (-π, π)`. -/ protected noncomputable def polarCoord : PartialHomeomorph ℂ (ℝ × ℝ) := equivRealProdClm.toHomeomorph.transPartialHomeomorph polarCoord diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index 6c1db29068cd2..01cb9e37d880a 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -31,22 +31,22 @@ therefore two different ingredients in a charted space: We separate these two parts in the definition: the charted space structure is just the set of charts, and then the different smoothness requirements (smooth manifold, orientable manifold, contact manifold, and so on) are additional properties of these charts. These properties are -formalized through the notion of structure groupoid, i.e., a set of local homeomorphisms stable +formalized through the notion of structure groupoid, i.e., a set of partial homeomorphisms stable under composition and inverse, to which the change of coordinates should belong. ## Main definitions -* `StructureGroupoid H` : a subset of local homeomorphisms of `H` stable under composition, - inverse and restriction (ex: local diffeos). -* `continuousGroupoid H` : the groupoid of all local homeomorphisms of `H`. +* `StructureGroupoid H` : a subset of partial homeomorphisms of `H` stable under composition, + inverse and restriction (ex: partial diffeomorphisms). +* `continuousGroupoid H` : the groupoid of all partial homeomorphisms of `H`. * `ChartedSpace H M` : charted space structure on `M` modelled on `H`, given by an atlas of - local homeomorphisms from `M` to `H` whose sources cover `M`. This is a type class. + partial homeomorphisms from `M` to `H` whose sources cover `M`. This is a type class. * `HasGroupoid M G` : when `G` is a structure groupoid on `H` and `M` is a charted space modelled on `H`, require that all coordinate changes belong to `G`. This is a type class. * `atlas H M` : when `M` is a charted space modelled on `H`, the atlas of this charted space structure, i.e., the set of charts. * `G.maximalAtlas M` : when `M` is a charted space modelled on `H` and admitting `G` as a - structure groupoid, one can consider all the local homeomorphisms from `M` to `H` such that + structure groupoid, one can consider all the partial homeomorphisms from `M` to `H` such that changing coordinate from any chart to them belongs to `G`. This is a larger atlas, called the maximal atlas (for the groupoid `G`). * `Structomorph G M M'` : the type of diffeomorphisms between the charted spaces `M` and `M'` for @@ -59,7 +59,7 @@ This charted space structure is compatible with any groupoid. Additional useful definitions: -* `Pregroupoid H` : a subset of local maps of `H` stable under composition and +* `Pregroupoid H` : a subset of partial maps of `H` stable under composition and restriction, but not inverse (ex: smooth maps) * `Pregroupoid.groupoid` : construct a groupoid from a pregroupoid, by requiring that a map and its inverse both belong to the pregroupoid (ex: construct diffeos from smooth maps) @@ -71,9 +71,9 @@ Additional useful definitions: maximal atlas associated to the groupoid `G`, the composition of `e.symm` and `e'` belongs to the `G` if `M` admits `G` as a structure groupoid. * `ChartedSpaceCore.toChartedSpace`: consider a space without a topology, but endowed with a set - of charts (which are local equivs) for which the change of coordinates are local homeos. Then - one can construct a topology on the space for which the charts become local homeos, defining - a genuine charted space structure. + of charts (which are partial equivs) for which the change of coordinates are partial homeos. + Then one can construct a topology on the space for which the charts become partial homeos, + defining a genuine charted space structure. ## Implementation notes @@ -98,7 +98,7 @@ otherwise, there would be an instance from manifolds to topological spaces, whic instance search for topological spaces would try to find manifold structures involving a yet unknown model space, leading to problems. However, we also introduce the latter approach, through a structure `ChartedSpaceCore` making it possible to construct a topology out of a set of -local equivs with compatibility conditions (but we do not register it as an instance). +partial equivs with compatibility conditions (but we do not register it as an instance). In the definition of a charted space, the model space is written as an explicit parameter as there can be several model spaces for a given topological space. For instance, a complex manifold @@ -106,8 +106,8 @@ can be several model spaces for a given topological space. For instance, a compl ## Notations -In the locale `Manifold`, we denote the composition of local homeomorphisms with `≫ₕ`, and the -composition of local equivs with `≫`. +In the locale `Manifold`, we denote the composition of partial homeomorphisms with `≫ₕ`, and the +composition of partial equivs with `≫`. -/ set_option autoImplicit true @@ -121,7 +121,7 @@ universe u variable {H : Type u} {H' : Type*} {M : Type*} {M' : Type*} {M'' : Type*} -/- Notational shortcut for the composition of local homeomorphisms and local equivs, i.e., +/- Notational shortcut for the composition of partial homeomorphisms and partial equivs, i.e., `PartialHomeomorph.trans` and `PartialEquiv.trans`. Note that, as is usual for equivs, the composition is from left to right, hence the direction of the arrow. -/ @@ -145,13 +145,13 @@ groupoid is naturally a vector bundle) I prefer that the members of the groupoid defined on sets of the form `s × E`. There is a typeclass `ClosedUnderRestriction` for groupoids which have the restriction property. -The only nontrivial requirement is locality: if a local homeomorphism belongs to the groupoid +The only nontrivial requirement is locality: if a partial homeomorphism belongs to the groupoid around each point in its domain of definition, then it belongs to the groupoid. Without this requirement, the composition of structomorphisms does not have to be a structomorphism. Note that -this implies that a local homeomorphism with empty source belongs to any structure groupoid, as +this implies that a partial homeomorphism with empty source belongs to any structure groupoid, as it trivially satisfies this condition. -There is also a technical point, related to the fact that a local homeomorphism is by definition a +There is also a technical point, related to the fact that a partial homeomorphism is by definition a global map which is a homeomorphism when restricted to its source subset (and its values outside of the source are not relevant). Therefore, we also require that being a member of the groupoid only depends on the values on the source. @@ -161,7 +161,7 @@ We use primes in the structure names as we will reformulate them below (without -/ -/-- A structure groupoid is a set of local homeomorphisms of a topological space stable under +/-- A structure groupoid is a set of partial homeomorphisms of a topological space stable under composition and inverse. They appear in the definition of the smoothness class of a manifold. -/ structure StructureGroupoid (H : Type u) [TopologicalSpace H] where members : Set (PartialHomeomorph H H) @@ -340,8 +340,8 @@ instance instStructureGroupoidOrderBot : OrderBot (StructureGroupoid H) where instance : Inhabited (StructureGroupoid H) := ⟨idGroupoid H⟩ -/-- To construct a groupoid, one may consider classes of local homeos such that both the function -and its inverse have some property. If this property is stable under composition, +/-- To construct a groupoid, one may consider classes of partial homeomorphisms such that +both the function and its inverse have some property. If this property is stable under composition, one gets a groupoid. `Pregroupoid` bundles the properties needed for this construction, with the groupoid of smooth functions with smooth inverses as an application. -/ structure Pregroupoid (H : Type*) [TopologicalSpace H] where @@ -354,7 +354,7 @@ structure Pregroupoid (H : Type*) [TopologicalSpace H] where congr : ∀ {f g : H → H} {u}, IsOpen u → (∀ x ∈ u, g x = f x) → property f u → property g u #align pregroupoid Pregroupoid -/-- Construct a groupoid of local homeos for which the map and its inverse have some property, +/-- Construct a groupoid of partial homeos for which the map and its inverse have some property, from a pregroupoid asserting that this property is stable under composition. -/ def Pregroupoid.groupoid (PG : Pregroupoid H) : StructureGroupoid H where members := { e : PartialHomeomorph H H | PG.property e e.source ∧ PG.property e.symm e.target } @@ -414,7 +414,7 @@ theorem mem_pregroupoid_of_eq_on_source (PG : Pregroupoid H) {e e' : PartialHome exact PG.congr e.open_source he'.eqOn.symm he #align mem_pregroupoid_of_eq_on_source mem_pregroupoid_of_eq_on_source -/-- The pregroupoid of all local maps on a topological space `H`. -/ +/-- The pregroupoid of all partial maps on a topological space `H`. -/ @[reducible] def continuousPregroupoid (H : Type*) [TopologicalSpace H] : Pregroupoid H where property _ _ := True @@ -427,12 +427,12 @@ def continuousPregroupoid (H : Type*) [TopologicalSpace H] : Pregroupoid H where instance (H : Type*) [TopologicalSpace H] : Inhabited (Pregroupoid H) := ⟨continuousPregroupoid H⟩ -/-- The groupoid of all local homeomorphisms on a topological space `H`. -/ +/-- The groupoid of all partial homeomorphisms on a topological space `H`. -/ def continuousGroupoid (H : Type*) [TopologicalSpace H] : StructureGroupoid H := Pregroupoid.groupoid (continuousPregroupoid H) #align continuous_groupoid continuousGroupoid -/-- Every structure groupoid is contained in the groupoid of all local homeomorphisms. -/ +/-- Every structure groupoid is contained in the groupoid of all partial homeomorphisms. -/ instance instStructureGroupoidOrderTop : OrderTop (StructureGroupoid H) where top := continuousGroupoid H le_top _ _ _ := ⟨trivial, trivial⟩ @@ -466,8 +466,8 @@ theorem closedUnderRestriction' {G : StructureGroupoid H} [ClosedUnderRestrictio ClosedUnderRestriction.closedUnderRestriction he s hs #align closed_under_restriction' closedUnderRestriction' -/-- The trivial restriction-closed groupoid, containing only local homeomorphisms equivalent to the -restriction of the identity to the various open subsets. -/ +/-- The trivial restriction-closed groupoid, containing only partial homeomorphisms equivalent +to the restriction of the identity to the various open subsets. -/ def idRestrGroupoid : StructureGroupoid H where members := { e | ∃ (s : Set H) (h : IsOpen s), e ≈ PartialHomeomorph.ofSet s h } trans' := by @@ -537,8 +537,8 @@ theorem closedUnderRestriction_iff_id_le (G : StructureGroupoid H) : exact idRestrGroupoid_mem hs #align closed_under_restriction_iff_id_le closedUnderRestriction_iff_id_le -/-- The groupoid of all local homeomorphisms on a topological space `H` is closed under restriction. --/ +/-- The groupoid of all partial homeomorphisms on a topological space `H` +is closed under restriction. -/ instance : ClosedUnderRestriction (continuousGroupoid H) := (closedUnderRestriction_iff_id_le _).mpr le_top @@ -719,7 +719,7 @@ library_note "Manifold type tags" /-- For technical reasons we introduce two typ * `ModelPi H` is the same as `∀ i, H i`, where `H : ι → Type*` and `ι` is a finite type. In both cases the reason is the same, so we explain it only in the case of the product. A charted -space `M` with model `H` is a set of local charts from `M` to `H` covering the space. Every space is +space `M` with model `H` is a set of charts from `M` to `H` covering the space. Every space is registered as a charted space over itself, using the only chart `id`, in `chartedSpaceSelf`. You can also define a product of charted space `M` and `M'` (with model space `H × H'`) by taking the products of the charts. Now, on `H × H'`, there are two charted space structures with model space @@ -840,7 +840,7 @@ end ChartedSpace /-- Sometimes, one may want to construct a charted space structure on a space which does not yet have a topological structure, where the topology would come from the charts. For this, one needs -charts that are only local equivs, and continuity properties for their composition. +charts that are only partial equivs, and continuity properties for their composition. This is formalised in `ChartedSpaceCore`. -/ -- @[nolint has_nonempty_instance] -- Porting note: commented out structure ChartedSpaceCore (H : Type*) [TopologicalSpace H] (M : Type*) where @@ -878,8 +878,8 @@ theorem open_target (he : e ∈ c.atlas) : IsOpen e.target := by simpa [PartialEquiv.trans_source, E] using c.open_source e e he he #align charted_space_core.open_target ChartedSpaceCore.open_target -/-- An element of the atlas in a charted space without topology becomes a local homeomorphism -for the topology constructed from this atlas. The `localHomeomorph` version is given in this +/-- An element of the atlas in a charted space without topology becomes a partial homeomorphism +for the topology constructed from this atlas. The `PartialHomeomorph` version is given in this definition. -/ protected def localHomeomorph (e : PartialEquiv M H) (he : e ∈ c.atlas) : @PartialHomeomorph M H c.toTopologicalSpace _ := @@ -974,7 +974,7 @@ instance hasGroupoid_model_space (H : Type*) [TopologicalSpace H] (G : Structure simp [he, he', StructureGroupoid.id_mem] #align has_groupoid_model_space hasGroupoid_model_space -/-- Any charted space structure is compatible with the groupoid of all local homeomorphisms. -/ +/-- Any charted space structure is compatible with the groupoid of all partial homeomorphisms. -/ instance hasGroupoid_continuousGroupoid : HasGroupoid M (continuousGroupoid H) := by refine' ⟨fun _ _ ↦ _⟩ rw [continuousGroupoid, mem_groupoid_of_pregroupoid] @@ -986,7 +986,7 @@ section MaximalAtlas variable (M) (G : StructureGroupoid H) /-- Given a charted space admitting a structure groupoid, the maximal atlas associated to this -structure groupoid is the set of all local charts that are compatible with the atlas, i.e., such +structure groupoid is the set of all charts that are compatible with the atlas, i.e., such that changing coordinates with an atlas member gives an element of the groupoid. -/ def StructureGroupoid.maximalAtlas : Set (PartialHomeomorph M H) := { e | ∀ e' ∈ atlas H M, e.symm ≫ₕ e' ∈ G ∧ e'.symm ≫ₕ e ∈ G } @@ -1061,8 +1061,8 @@ namespace PartialHomeomorph variable (e : PartialHomeomorph α H) -/-- If a single local homeomorphism `e` from a space `α` into `H` has source covering the whole -space `α`, then that local homeomorphism induces an `H`-charted space structure on `α`. +/-- If a single partial homeomorphism `e` from a space `α` into `H` has source covering the whole +space `α`, then that partial homeomorphism induces an `H`-charted space structure on `α`. (This condition is equivalent to `e` being an open embedding of `α` into `H`; see `OpenEmbedding.singletonChartedSpace`.) -/ def singletonChartedSpace (h : e.source = Set.univ) : ChartedSpace H α where @@ -1088,7 +1088,7 @@ theorem singletonChartedSpace_mem_atlas_eq (h : e.source = Set.univ) (e' : Parti h' #align local_homeomorph.singleton_charted_space_mem_atlas_eq PartialHomeomorph.singletonChartedSpace_mem_atlas_eq -/-- Given a local homeomorphism `e` from a space `α` into `H`, if its source covers the whole +/-- Given a partial homeomorphism `e` from a space `α` into `H`, if its source covers the whole space `α`, then the induced charted space structure on `α` is `HasGroupoid G` for any structure groupoid `G` which is closed under restrictions. -/ theorem singleton_hasGroupoid (h : e.source = Set.univ) (G : StructureGroupoid H) diff --git a/Mathlib/Geometry/Manifold/ConformalGroupoid.lean b/Mathlib/Geometry/Manifold/ConformalGroupoid.lean index 20b2e7e834f2a..e030e9f4b603f 100644 --- a/Mathlib/Geometry/Manifold/ConformalGroupoid.lean +++ b/Mathlib/Geometry/Manifold/ConformalGroupoid.lean @@ -15,7 +15,7 @@ In this file we define the groupoid of conformal maps on normed spaces. ## Main definitions -* `conformalGroupoid`: the groupoid of conformal local homeomorphisms. +* `conformalGroupoid`: the groupoid of conformal partial homeomorphisms. ## Tags diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean index 0c8fe428e78af..bb59be42aad22 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean @@ -226,7 +226,7 @@ theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : PartialHomeomorph M M') mfld_set_tac refine' ⟨e.symm, StructureGroupoid.symm _ he, h3e, _⟩ rw [h2X]; exact e.mapsTo hex - · -- We now show the converse: a local homeomorphism `f : M → M'` which is smooth in both + · -- We now show the converse: a partial homeomorphism `f : M → M'` which is smooth in both -- directions is a local structomorphism. We do this by proposing -- `((chart_at H x).symm.trans f).trans (chart_at H (f x))` as a candidate for a structomorphism -- of `H`. diff --git a/Mathlib/Geometry/Manifold/Instances/Sphere.lean b/Mathlib/Geometry/Manifold/Instances/Sphere.lean index c838ca17e7a53..bb922383d08d1 100644 --- a/Mathlib/Geometry/Manifold/Instances/Sphere.lean +++ b/Mathlib/Geometry/Manifold/Instances/Sphere.lean @@ -23,11 +23,11 @@ it to put a smooth manifold structure on the sphere. ## Main results For a unit vector `v` in `E`, the definition `stereographic` gives the stereographic projection -centred at `v`, a local homeomorphism from the sphere to `(ℝ ∙ v)ᗮ` (the orthogonal complement of +centred at `v`, a partial homeomorphism from the sphere to `(ℝ ∙ v)ᗮ` (the orthogonal complement of `v`). For finite-dimensional `E`, we then construct a smooth manifold instance on the sphere; the charts -here are obtained by composing the local homeomorphisms `stereographic` with arbitrary isometries +here are obtained by composing the partial homeomorphisms `stereographic` with arbitrary isometries from `(ℝ ∙ v)ᗮ` to Euclidean space. We prove two lemmas about smooth maps: @@ -279,8 +279,8 @@ theorem stereo_right_inv (hv : ‖v‖ = 1) (w : (ℝ ∙ v)ᗮ) : stereoToFun v · simp #align stereo_right_inv stereo_right_inv -/-- Stereographic projection from the unit sphere in `E`, centred at a unit vector `v` in `E`; this -is the version as a local homeomorphism. -/ +/-- Stereographic projection from the unit sphere in `E`, centred at a unit vector `v` in `E`; +this is the version as a partial homeomorphism. -/ def stereographic (hv : ‖v‖ = 1) : PartialHomeomorph (sphere (0 : E) 1) (ℝ ∙ v)ᗮ where toFun := stereoToFun v ∘ (↑) invFun := stereoInvFun hv diff --git a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean index 49f80e0477536..b3e90c4818b14 100644 --- a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean +++ b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean @@ -636,7 +636,7 @@ theorem isLocalStructomorphWithinAt_localInvariantProp [ClosedUnderRestriction G · simpa only [hex, hef ⟨hx, hex⟩, mfld_simps] using hfx } #align structure_groupoid.is_local_structomorph_within_at_local_invariant_prop StructureGroupoid.isLocalStructomorphWithinAt_localInvariantProp -/-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a local homeomorph. +/-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a partial homeomorph. This gives us an `e` that is defined on a subset of `f.source`. -/ theorem _root_.PartialHomeomorph.isLocalStructomorphWithinAt_iff {G : StructureGroupoid H} [ClosedUnderRestriction G] (f : PartialHomeomorph H H) {s : Set H} {x : H} @@ -659,7 +659,7 @@ theorem _root_.PartialHomeomorph.isLocalStructomorphWithinAt_iff {G : StructureG exact ⟨e, he, hfe, hxe⟩ #align local_homeomorph.is_local_structomorph_within_at_iff PartialHomeomorph.isLocalStructomorphWithinAt_iff -/-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a local homeomorph and +/-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a partial homeomorph and the set we're considering is a superset of `f.source`. -/ theorem _root_.PartialHomeomorph.isLocalStructomorphWithinAt_iff' {G : StructureGroupoid H} [ClosedUnderRestriction G] (f : PartialHomeomorph H H) {s : Set H} {x : H} (hs : f.source ⊆ s) @@ -673,7 +673,7 @@ theorem _root_.PartialHomeomorph.isLocalStructomorphWithinAt_iff' {G : Structure rw [inter_eq_right.mpr (h2e.trans hs)] #align local_homeomorph.is_local_structomorph_within_at_iff' PartialHomeomorph.isLocalStructomorphWithinAt_iff' -/-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a local homeomorph and +/-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a partial homeomorph and the set we're considering is `f.source`. -/ theorem _root_.PartialHomeomorph.isLocalStructomorphWithinAt_source_iff {G : StructureGroupoid H} [ClosedUnderRestriction G] (f : PartialHomeomorph H H) {x : H} : diff --git a/Mathlib/Geometry/Manifold/MFDeriv.lean b/Mathlib/Geometry/Manifold/MFDeriv.lean index 79ab62287c66a..49141ae1ceac7 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv.lean @@ -242,7 +242,7 @@ def MDifferentiable (f : M → M') := ∀ x, MDifferentiableAt I I' f x #align mdifferentiable MDifferentiable -/-- Prop registering if a local homeomorphism is a local diffeomorphism on its source -/ +/-- Prop registering if a partial homeomorphism is a local diffeomorphism on its source -/ def PartialHomeomorph.MDifferentiable (f : PartialHomeomorph M M') := MDifferentiableOn I I' f f.source ∧ MDifferentiableOn I' I f.symm f.target #align local_homeomorph.mdifferentiable PartialHomeomorph.MDifferentiable @@ -1898,7 +1898,7 @@ end Charts end SpecificFunctions -/-! ### Differentiable local homeomorphisms -/ +/-! ### Differentiable partial homeomorphisms -/ namespace PartialHomeomorph.MDifferentiable @@ -1944,7 +1944,7 @@ theorem comp_symm_deriv {x : M'} (hx : x ∈ e.target) : he.symm.symm_comp_deriv hx #align local_homeomorph.mdifferentiable.comp_symm_deriv PartialHomeomorph.MDifferentiable.comp_symm_deriv -/-- The derivative of a differentiable local homeomorphism, as a continuous linear equivalence +/-- The derivative of a differentiable partial homeomorphism, as a continuous linear equivalence between the tangent spaces at `x` and `e x`. -/ protected def mfderiv {x : M} (hx : x ∈ e.source) : TangentSpace I x ≃L[𝕜] TangentSpace I' (e x) := { mfderiv I I' e x with diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index 198dab83bd691..fe6b1396c5b8f 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -37,7 +37,7 @@ but add these assumptions later as needed. (Quite a few results still do not req * `modelWithCornersSelf 𝕜 E` : trivial model with corners structure on the space `E` embedded in itself by the identity. * `contDiffGroupoid n I` : - when `I` is a model with corners on `(𝕜, E, H)`, this is the groupoid of local homeos of `H` + when `I` is a model with corners on `(𝕜, E, H)`, this is the groupoid of partial homeos of `H` which are of class `C^n` over the normed field `𝕜`, when read in `E`. * `SmoothManifoldWithCorners I M` : a type class saying that the charted space `M`, modelled on the space `H`, has `C^∞` changes of @@ -46,8 +46,9 @@ but add these assumptions later as needed. (Quite a few results still do not req * `extChartAt I x`: in a smooth manifold with corners with the model `I` on `(E, H)`, the charts take values in `H`, but often we may want to use their `E`-valued version, obtained by composing the charts with `I`. - Since the target is in general not open, we can not register them as local homeomorphisms, but - we register them as local equivs. `extChartAt I x` is the canonical such local equiv around `x`. + Since the target is in general not open, we can not register them as partial homeomorphisms, but + we register them as `PartialEquiv`s. + `extChartAt I x` is the canonical such partial equiv around `x`. As specific examples of models with corners, we define (in the file `real_instances.lean`) * `modelWithCornersSelf ℝ (EuclideanSpace (Fin n))` for the model space used to define @@ -177,7 +178,7 @@ switch to this behavior later, doing it mid-port will break a lot of proofs. -/ instance : CoeFun (ModelWithCorners 𝕜 E H) fun _ => H → E := ⟨toFun'⟩ -/-- The inverse to a model with corners, only registered as a local equiv. -/ +/-- The inverse to a model with corners, only registered as a `PartialEquiv`. -/ protected def symm : PartialEquiv E H := I.toPartialEquiv.symm #align model_with_corners.symm ModelWithCorners.symm @@ -374,7 +375,7 @@ section variable (𝕜 E) -/-- In the trivial model with corners, the associated local equiv is the identity. -/ +/-- In the trivial model with corners, the associated `PartialEquiv` is the identity. -/ @[simp, mfld_simps] theorem modelWithCornersSelf_localEquiv : 𝓘(𝕜, E).toPartialEquiv = PartialEquiv.refl E := rfl @@ -583,11 +584,11 @@ theorem contDiffGroupoid_le (h : m ≤ n) : contDiffGroupoid n I ≤ contDiffGro #align cont_diff_groupoid_le contDiffGroupoid_le /-- The groupoid of `0`-times continuously differentiable maps is just the groupoid of all -local homeomorphisms -/ +partial homeomorphisms -/ theorem contDiffGroupoid_zero_eq : contDiffGroupoid 0 I = continuousGroupoid H := by apply le_antisymm le_top intro u _ - -- we have to check that every local homeomorphism belongs to `contDiffGroupoid 0 I`, + -- we have to check that every partial homeomorphism belongs to `contDiffGroupoid 0 I`, -- by unfolding its definition change u ∈ contDiffGroupoid 0 I rw [contDiffGroupoid, mem_groupoid_of_pregroupoid] @@ -601,7 +602,7 @@ theorem contDiffGroupoid_zero_eq : contDiffGroupoid 0 I = continuousGroupoid H : variable (n) -/-- An identity local homeomorphism belongs to the `C^n` groupoid. -/ +/-- An identity partial homeomorphism belongs to the `C^n` groupoid. -/ theorem ofSet_mem_contDiffGroupoid {s : Set H} (hs : IsOpen s) : PartialHomeomorph.ofSet s hs ∈ contDiffGroupoid n I := by rw [contDiffGroupoid, mem_groupoid_of_pregroupoid] @@ -611,7 +612,7 @@ theorem ofSet_mem_contDiffGroupoid {s : Set H} (hs : IsOpen s) : exact this.congr_mono (fun x hx => I.right_inv hx.2) (subset_univ _) #align of_set_mem_cont_diff_groupoid ofSet_mem_contDiffGroupoid -/-- The composition of a local homeomorphism from `H` to `M` and its inverse belongs to +/-- The composition of a partial homeomorphism from `H` to `M` and its inverse belongs to the `C^n` groupoid. -/ theorem symm_trans_mem_contDiffGroupoid (e : PartialHomeomorph M H) : e.symm.trans e ∈ contDiffGroupoid n I := @@ -622,7 +623,7 @@ theorem symm_trans_mem_contDiffGroupoid (e : PartialHomeomorph M H) : variable {E' H' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [TopologicalSpace H'] -/-- The product of two smooth local homeomorphisms is smooth. -/ +/-- The product of two smooth partial homeomorphisms is smooth. -/ theorem contDiffGroupoid_prod {I : ModelWithCorners 𝕜 E H} {I' : ModelWithCorners 𝕜 E' H'} {e : PartialHomeomorph H H} {e' : PartialHomeomorph H' H'} (he : e ∈ contDiffGroupoid ⊤ I) (he' : e' ∈ contDiffGroupoid ⊤ I') : e.prod e' ∈ contDiffGroupoid ⊤ (I.prod I') := by @@ -744,7 +745,7 @@ def analyticGroupoid : StructureGroupoid H := rw [comp_apply, comp_apply, fg (I.symm y) hy.left.left] at hy exact hy.right } -/-- An identity local homeomorphism belongs to the analytic groupoid. -/ +/-- An identity partial homeomorphism belongs to the analytic groupoid. -/ theorem ofSet_mem_analyticGroupoid {s : Set H} (hs : IsOpen s) : PartialHomeomorph.ofSet s hs ∈ analyticGroupoid I := by rw [analyticGroupoid] @@ -770,7 +771,7 @@ theorem ofSet_mem_analyticGroupoid {s : Set H} (hs : IsOpen s) : rw [← hy.right, I.right_inv (interior_subset hy.left.right)] exact hy.left.right -/-- The composition of a local homeomorphism from `H` to `M` and its inverse belongs to +/-- The composition of a partial homeomorphism from `H` to `M` and its inverse belongs to the analytic groupoid. -/ theorem symm_trans_mem_analyticGroupoid (e : PartialHomeomorph M H) : e.symm.trans e ∈ analyticGroupoid I := @@ -788,7 +789,7 @@ instance : ClosedUnderRestriction (analyticGroupoid I) := exact ofSet_mem_analyticGroupoid I hs) /-- The analytic groupoid on a boundaryless charted space modeled on a complete vector space -consists of the local homeomorphisms which are analytic and have analytic inverse. -/ +consists of the partial homeomorphisms which are analytic and have analytic inverse. -/ theorem mem_analyticGroupoid_of_boundaryless [CompleteSpace E] [I.Boundaryless] (e : PartialHomeomorph H H) : e ∈ analyticGroupoid I ↔ AnalyticOn 𝕜 (I ∘ e ∘ I.symm) (I '' e.source) ∧ diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean index 71a68fc1d2de3..cc0a46cc89955 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean @@ -20,7 +20,7 @@ is also a charted space over `H × F`. Now, we define `SmoothVectorBundle` as the `Prop` of having smooth transition functions. Recall the structure groupoid `smoothFiberwiseLinear` on `B × F` consisting of smooth, fiberwise -linear local homeomorphisms. We show that our definition of "smooth vector bundle" implies +linear partial homeomorphisms. We show that our definition of "smooth vector bundle" implies `HasGroupoid` for this groupoid, and show (by a "composition" of `HasGroupoid` instances) that this means that a smooth vector bundle is a smooth manifold. diff --git a/Mathlib/Topology/FiberBundle/Basic.lean b/Mathlib/Topology/FiberBundle/Basic.lean index 1f322bc36579d..7a7b1ea958d91 100644 --- a/Mathlib/Topology/FiberBundle/Basic.lean +++ b/Mathlib/Topology/FiberBundle/Basic.lean @@ -39,7 +39,7 @@ an implementation of this construction: starting from an object of type fiber bundle and projection. Similarly we implement the object `FiberPrebundle` which allows to define a topological -fiber bundle from trivializations given as local equivalences with minimum additional properties. +fiber bundle from trivializations given as partial equivalences with minimum additional properties. ## Main definitions @@ -64,7 +64,7 @@ Let `Z : FiberBundleCore ι B F`. Then we define open set in `B`. * `FiberPrebundle F E` : structure registering a cover of prebundle trivializations - and requiring that the relative transition maps are local homeomorphisms. + and requiring that the relative transition maps are partial homeomorphisms. * `FiberPrebundle.totalSpaceTopology a` : natural topology of the total space, making the prebundle into a bundle. @@ -481,7 +481,7 @@ theorem mem_trivChange_source (i j : ι) (p : B × F) : between `proj ⁻¹ (baseSet i)` and `baseSet i × F`. As the fiber above `x` is `F` but read in the chart with index `index_at x`, the trivialization in the fiber above x is by definition the coordinate change from i to `index_at x`, so it depends on `x`. -The local trivialization will ultimately be a local homeomorphism. For now, we only introduce the +The local trivialization will ultimately be a partial homeomorphism. For now, we only introduce the partial equivalence version, denoted with a prime. In further developments, avoid this auxiliary version, and use `Z.local_triv` instead. -/ def localTrivAsPartialEquiv (i : ι) : PartialEquiv Z.TotalSpace (B × F) where @@ -759,8 +759,8 @@ variable (F) (E : B → Type*) [TopologicalSpace B] [TopologicalSpace F] /-- This structure permits to define a fiber bundle when trivializations are given as local equivalences but there is not yet a topology on the total space. The total space is hence given a -topology in such a way that there is a fiber bundle structure for which the local equivalences -are also local homeomorphism and hence local trivializations. -/ +topology in such a way that there is a fiber bundle structure for which the partial equivalences +are also partial homeomorphisms and hence local trivializations. -/ -- porting note: todo: was @[nolint has_nonempty_instance] structure FiberPrebundle where pretrivializationAtlas : Set (Pretrivialization F (π F E)) diff --git a/Mathlib/Topology/FiberBundle/Trivialization.lean b/Mathlib/Topology/FiberBundle/Trivialization.lean index e5ec9d3cf64f8..dc16c6787110d 100644 --- a/Mathlib/Topology/FiberBundle/Trivialization.lean +++ b/Mathlib/Topology/FiberBundle/Trivialization.lean @@ -16,10 +16,10 @@ import Mathlib.Topology.PartialHomeomorph ### Basic definitions -* `Trivialization F p` : structure extending local homeomorphisms, defining a local +* `Trivialization F p` : structure extending partial homeomorphisms, defining a local trivialization of a topological space `Z` with projection `p` and fiber `F`. -* `Pretrivialization F proj` : trivialization as a local equivalence, mainly used when the +* `Pretrivialization F proj` : trivialization as a partial equivalence, mainly used when the topology on the total space has not yet been defined. ### Operations on bundles @@ -299,9 +299,9 @@ end Pretrivialization variable [TopologicalSpace Z] [TopologicalSpace (TotalSpace F E)] -/-- A structure extending local homeomorphisms, defining a local trivialization of a projection -`proj : Z → B` with fiber `F`, as a local homeomorphism between `Z` and `B × F` defined between two -sets of the form `proj ⁻¹' baseSet` and `baseSet × F`, acting trivially on the first coordinate. +/-- A structure extending partial homeomorphisms, defining a local trivialization of a projection +`proj : Z → B` with fiber `F`, as a partial homeomorphism between `Z` and `B × F` defined between +two sets of the form `proj ⁻¹' baseSet` and `baseSet × F`, acting trivially on the first coordinate. -/ -- porting note: todo: was @[nolint has_nonempty_instance] structure Trivialization (proj : Z → B) extends PartialHomeomorph Z (B × F) where diff --git a/Mathlib/Topology/VectorBundle/Basic.lean b/Mathlib/Topology/VectorBundle/Basic.lean index 625d8332aaf98..e06149db52d56 100644 --- a/Mathlib/Topology/VectorBundle/Basic.lean +++ b/Mathlib/Topology/VectorBundle/Basic.lean @@ -848,8 +848,8 @@ open VectorBundle /-- This structure permits to define a vector bundle when trivializations are given as local equivalences but there is not yet a topology on the total space or the fibers. The total space is hence given a topology in such a way that there is a fiber bundle structure for -which the local equivalences are also local homeomorphisms and hence vector bundle trivializations. -The topology on the fibers is induced from the one on the total space. +which the partial equivalences are also partial homeomorphisms and hence vector bundle +trivializations. The topology on the fibers is induced from the one on the total space. The field `exists_coordChange` is stated as an existential statement (instead of 3 separate fields), since it depends on propositional information (namely `e e' ∈ pretrivializationAtlas`). From c228bcf4828ba56ebc951d2465053bbd8443abfe Mon Sep 17 00:00:00 2001 From: Arend Mellendijk Date: Tue, 26 Dec 2023 22:33:53 +0000 Subject: [PATCH 216/353] chore: Remove superfluous lemma that uses `n.factors.toFinset` (#9248) I added `prod_factors_toFinset_of_squarefree` before `primeFactors` existed. I suspect it was missed during the refactor. --- Mathlib/Data/Nat/Squarefree.lean | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index 4ed58411296da..10fe9df266569 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -399,10 +399,8 @@ lemma coprime_div_gcd_of_squarefree (hm : Squarefree m) (hn : n ≠ 0) : Coprime (coprime_div_gcd_div_gcd (m := m) (gcd_ne_zero_right hn).bot_lt).mul_right this lemma prod_primeFactors_of_squarefree (hn : Squarefree n) : ∏ p in n.primeFactors, p = n := by - convert factorization_prod_pow_eq_self hn.ne_zero - refine prod_congr rfl fun p hp ↦ ?_ - simp only [support_factorization, toFinset_factors, mem_primeFactors_of_ne_zero hn.ne_zero] at hp - simp_rw [factorization_eq_one_of_squarefree hn hp.1 hp.2, pow_one] + rw [← toFinset_factors, List.prod_toFinset _ hn.nodup_factors, List.map_id', + Nat.prod_factors hn.ne_zero] lemma primeFactors_prod (hs : ∀ p ∈ s, p.Prime) : primeFactors (∏ p in s, p) = s := by have hn : ∏ p in s, p ≠ 0 := prod_ne_zero_iff.2 fun p hp ↦ (hs _ hp).ne_zero @@ -430,10 +428,6 @@ lemma prod_primeFactors_invOn_squarefree : {s | ∀ p ∈ s, p.Prime} {n | Squarefree n} := ⟨fun _s ↦ primeFactors_prod, fun _n ↦ prod_primeFactors_of_squarefree⟩ -theorem prod_factors_toFinset_of_squarefree {n : ℕ} (hn : Squarefree n) : - ∏ p in n.factors.toFinset, p = n := by - rw [List.prod_toFinset _ hn.nodup_factors, List.map_id', Nat.prod_factors hn.ne_zero] - end Nat -- Porting note: comment out NormNum tactic, to be moved to another file. From 04c6d77cb8c94fbdac2ac19ac5dec94434becf41 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Tue, 26 Dec 2023 22:33:54 +0000 Subject: [PATCH 217/353] chore: use elab_as_elim directly, now that lean4#1900 is fixed (#9288) Adds the attribute `elab_as_elim` directly to the declarations of `strongSubRecursion` and `pincerRecursion`, rather than in separate commands. This change was made possible by https://github.com/leanprover/lean4/commit/8a573b5d87a42bd19307522ee747aaed44d9d71c, which fixed https://github.com/leanprover/lean4/issues/1900. --- Mathlib/Data/Nat/Basic.lean | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Mathlib/Data/Nat/Basic.lean b/Mathlib/Data/Nat/Basic.lean index 1cd9067d80f1b..6770f954b07a0 100644 --- a/Mathlib/Data/Nat/Basic.lean +++ b/Mathlib/Data/Nat/Basic.lean @@ -560,21 +560,18 @@ theorem decreasingInduction_succ_left {P : ℕ → Sort*} (h : ∀ n, P (n + 1) strictly below `(a,b)` to `P a b`, then we have `P n m` for all `n m : ℕ`. Note that for non-`Prop` output it is preferable to use the equation compiler directly if possible, since this produces equation lemmas. -/ +@[elab_as_elim] def strongSubRecursion {P : ℕ → ℕ → Sort*} (H : ∀ a b, (∀ x y, x < a → y < b → P x y) → P a b) : ∀ n m : ℕ, P n m | n, m => H n m fun x y _ _ => strongSubRecursion H x y #align nat.strong_sub_recursion Nat.strongSubRecursion --- Porting note: --- we can't put this on the definition itself because of --- https://github.com/leanprover/lean4/issues/1900 -attribute [elab_as_elim] strongSubRecursion - /-- Given `P : ℕ → ℕ → Sort*`, if we have `P i 0` and `P 0 i` for all `i : ℕ`, and for any `x y : ℕ` we can extend `P` from `(x,y+1)` and `(x+1,y)` to `(x+1,y+1)` then we have `P n m` for all `n m : ℕ`. Note that for non-`Prop` output it is preferable to use the equation compiler directly if possible, since this produces equation lemmas. -/ +@[elab_as_elim] def pincerRecursion {P : ℕ → ℕ → Sort*} (Ha0 : ∀ a : ℕ, P a 0) (H0b : ∀ b : ℕ, P 0 b) (H : ∀ x y : ℕ, P x y.succ → P x.succ y → P x.succ y.succ) : ∀ n m : ℕ, P n m | a, 0 => Ha0 a @@ -583,11 +580,6 @@ def pincerRecursion {P : ℕ → ℕ → Sort*} (Ha0 : ∀ a : ℕ, P a 0) (H0b termination_by pincerRecursion Ha0 Hab H n m => n + m #align nat.pincer_recursion Nat.pincerRecursion --- Porting note: --- we can't put this on the definition itself because of --- https://github.com/leanprover/lean4/issues/1900 -attribute [elab_as_elim] pincerRecursion - /-- Recursion starting at a non-zero number: given a map `C k → C (k+1)` for each `k ≥ n`, there is a map from `C n` to each `C m`, `n ≤ m`. -/ @[elab_as_elim] From 9757df4e07dcd5870b7118b17e70c6d3945251c7 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Tue, 26 Dec 2023 22:33:55 +0000 Subject: [PATCH 218/353] chore: remove workarounds for lean4#1891 (#9290) We no longer need to explicitly specify the `Monotone` and `StrictMono` arguments, after https://github.com/leanprover/lean4/commit/069873d8e5e0e7bed18f71edb63d18da50748ec9 fixed https://github.com/leanprover/lean4/issues/1891. Compare to the mathlib3 declarations: https://github.com/leanprover-community/mathlib/blob/65a1391a0106c9204fe45bc73a039f056558cb83/src/data/prod/lex.lean#L93-L107 --- Mathlib/Data/Prod/Lex.lean | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Mathlib/Data/Prod/Lex.lean b/Mathlib/Data/Prod/Lex.lean index 71c003d9f7ba4..419770c6e9a95 100644 --- a/Mathlib/Data/Prod/Lex.lean +++ b/Mathlib/Data/Prod/Lex.lean @@ -108,22 +108,14 @@ section Preorder variable [PartialOrder α] [Preorder β] --- porting note: type class search sees right through the type synonrm for `α ×ₗ β` and uses the --- `Preorder` structure for `α × β` instead --- This is hopefully the same problems as in https://github.com/leanprover/lean4/issues/1891 --- and will be fixed in nightly-2022-11-30 -theorem toLex_mono : @Monotone _ _ _ (Prod.Lex.preorder α β) (toLex : α × β → α ×ₗ β) := by +theorem toLex_mono : Monotone (toLex : α × β → α ×ₗ β) := by rintro ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ ⟨ha, hb⟩ obtain rfl | ha : a₁ = a₂ ∨ _ := ha.eq_or_lt · exact right _ hb · exact left _ _ ha #align prod.lex.to_lex_mono Prod.Lex.toLex_mono --- porting note: type class search sees right through the type synonrm for `α ×ₗ β` and uses the --- `Preorder` structure for `α × β` instead --- This is hopefully the same problems as in https://github.com/leanprover/lean4/issues/1891 --- and will be fixed in nightly-2022-11-30 -theorem toLex_strictMono : @StrictMono _ _ _ (Prod.Lex.preorder α β) (toLex : α × β → α ×ₗ β) := by +theorem toLex_strictMono : StrictMono (toLex : α × β → α ×ₗ β) := by rintro ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ h obtain rfl | ha : a₁ = a₂ ∨ _ := h.le.1.eq_or_lt · exact right _ (Prod.mk_lt_mk_iff_right.1 h) From c8b9760e5831e2a867e07c6fd4819a042369ba52 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Dec 2023 23:40:24 +0000 Subject: [PATCH 219/353] chore: deprecate `prod_zero_iff_exists_zero` (#9281) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Make `Multiset.prod_eq_zero_iff` a `simp` lemma. - Golf and deprecate `prod_zero_iff_exists_zero`; it was a bad API version of `Multiset.prod_eq_zero_iff`. - Make `Ideal.mul_eq_bot` a `simp` lemma`. - Add `Ideal.multiset_prod_eq_bot` (a `simp` lemma), deprecate `Ideal.prod_eq_bot`. The deprecated lemmas `prod_zero_iff_exists_zero` and `Ideal.prod_eq_bot` use `∃ x ∈ s, x = 0` instead of a simpler `0 ∈ s` in the RHS. --- Mathlib/Algebra/BigOperators/Multiset/Basic.lean | 1 + .../Algebra/GroupWithZero/NonZeroDivisors.lean | 16 ++-------------- Mathlib/NumberTheory/ArithmeticFunction.lean | 10 +++------- Mathlib/RingTheory/Ideal/Operations.lean | 9 ++++++++- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/Mathlib/Algebra/BigOperators/Multiset/Basic.lean b/Mathlib/Algebra/BigOperators/Multiset/Basic.lean index 7ad7b4546aed5..ac6ac8f1b3d49 100644 --- a/Mathlib/Algebra/BigOperators/Multiset/Basic.lean +++ b/Mathlib/Algebra/BigOperators/Multiset/Basic.lean @@ -285,6 +285,7 @@ theorem prod_eq_zero {s : Multiset α} (h : (0 : α) ∈ s) : s.prod = 0 := by variable [NoZeroDivisors α] [Nontrivial α] {s : Multiset α} +@[simp] theorem prod_eq_zero_iff : s.prod = 0 ↔ (0 : α) ∈ s := Quotient.inductionOn s fun l => by rw [quot_mk_to_coe, coe_prod] diff --git a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean index 478a46491eca2..6298c0bc106f4 100644 --- a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean +++ b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean @@ -234,22 +234,10 @@ theorem nonZeroDivisors_le_comap_nonZeroDivisors_of_injective [NoZeroDivisors M' Submonoid.le_comap_of_map_le _ (map_le_nonZeroDivisors_of_injective _ hf le_rfl) #align non_zero_divisors_le_comap_non_zero_divisors_of_injective nonZeroDivisors_le_comap_nonZeroDivisors_of_injective +@[deprecated Multiset.prod_eq_zero_iff] -- since 26 Dec 2023 theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} : s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by - constructor; swap - · rintro ⟨r, hrs, rfl⟩ - exact Multiset.prod_eq_zero hrs - induction' s using Multiset.induction_on with a s ih - · intro habs - simp at habs - · rw [Multiset.prod_cons] - intro hprod - replace hprod := eq_zero_or_eq_zero_of_mul_eq_zero hprod - cases' hprod with ha hb - · exact ⟨a, Multiset.mem_cons_self a s, ha⟩ - · apply (ih hb).imp _ - rintro b ⟨hb₁, hb₂⟩ - exact ⟨Multiset.mem_cons_of_mem hb₁, hb₂⟩ + simp [Multiset.prod_eq_zero_iff] #align prod_zero_iff_exists_zero prod_zero_iff_exists_zero end nonZeroDivisors diff --git a/Mathlib/NumberTheory/ArithmeticFunction.lean b/Mathlib/NumberTheory/ArithmeticFunction.lean index 3babea1f1e034..06a39f065e3eb 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction.lean @@ -919,13 +919,9 @@ theorem cardFactors_mul {m n : ℕ} (m0 : m ≠ 0) (n0 : n ≠ 0) : Ω (m * n) = theorem cardFactors_multiset_prod {s : Multiset ℕ} (h0 : s.prod ≠ 0) : Ω s.prod = (Multiset.map Ω s).sum := by - revert h0 - -- porting note: was `apply s.induction_on` - refine s.induction_on ?_ ?_ - · simp - intro a t h h0 - rw [Multiset.prod_cons, mul_ne_zero_iff] at h0 - simp [h0, cardFactors_mul, h] + induction s using Multiset.induction_on with + | empty => simp + | cons ih => simp_all [cardFactors_mul, not_or] #align nat.arithmetic_function.card_factors_multiset_prod Nat.ArithmeticFunction.cardFactors_multiset_prod @[simp] diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 43e909af119f5..2c5516daf12f1 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -809,6 +809,7 @@ theorem pow_right_mono {I J : Ideal R} (e : I ≤ J) (n : ℕ) : I ^ n ≤ J ^ n exact Ideal.mul_mono e hn #align ideal.pow_right_mono Ideal.pow_right_mono +@[simp] theorem mul_eq_bot {R : Type*} [CommSemiring R] [NoZeroDivisors R] {I J : Ideal R} : I * J = ⊥ ↔ I = ⊥ ∨ J = ⊥ := ⟨fun hij => @@ -823,9 +824,15 @@ instance {R : Type*} [CommSemiring R] [NoZeroDivisors R] : NoZeroDivisors (Ideal eq_zero_or_eq_zero_of_mul_eq_zero := mul_eq_bot.1 /-- A product of ideals in an integral domain is zero if and only if one of the terms is zero. -/ +@[simp] +lemma multiset_prod_eq_bot {R : Type*} [CommRing R] [IsDomain R] {s : Multiset (Ideal R)} : + s.prod = ⊥ ↔ ⊥ ∈ s := + Multiset.prod_eq_zero_iff + +/-- A product of ideals in an integral domain is zero if and only if one of the terms is zero. -/ +@[deprecated multiset_prod_eq_bot] -- since 26 Dec 2023 theorem prod_eq_bot {R : Type*} [CommRing R] [IsDomain R] {s : Multiset (Ideal R)} : s.prod = ⊥ ↔ ∃ I ∈ s, I = ⊥ := by - rw [bot_eq_zero, prod_zero_iff_exists_zero] simp #align ideal.prod_eq_bot Ideal.prod_eq_bot From b4b3958576f5dd3234621675b1c3953ce5936945 Mon Sep 17 00:00:00 2001 From: Alex J Best Date: Wed, 27 Dec 2023 00:57:40 +0000 Subject: [PATCH 220/353] chore: delete omega syntax stub (#9294) as omega is now in std --- Mathlib/Mathport/Syntax.lean | 3 --- 1 file changed, 3 deletions(-) diff --git a/Mathlib/Mathport/Syntax.lean b/Mathlib/Mathport/Syntax.lean index afc5049d8f5ac..5350b7be4816f 100644 --- a/Mathlib/Mathport/Syntax.lean +++ b/Mathlib/Mathport/Syntax.lean @@ -213,9 +213,6 @@ syntax termList := " [" term,* "]" /- E -/ syntax (name := noncommRing) "noncomm_ring" : tactic - -/- S -/ syntax (name := omega) "omega" (&" manual")? (&" nat" <|> &" int")? : tactic - /- B -/ syntax (name := acMono) "ac_mono" ("*" <|> ("^" num))? (config)? ((" : " term) <|> (" := " term))? : tactic From fb6ba072b0a93cf43e39a87367072a958d7be9cf Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Wed, 27 Dec 2023 04:42:56 +0000 Subject: [PATCH 221/353] chore(LinearAlgebra): rename to enable `LinearIndependent` dot notation (#9144) + Rename `cardinal_lift_le_rank_of_linearIndependent`, `cardinal_le_rank_of_linearIndependent(')`, `cardinal_mk/fintype_card/finset_card_le_finrank_of_linearIndependent`, `fintype_card_le_finrank_of_linearIndependent`, `finset_card_le_finrank_of_linearIndependent` by removing trailing `_of_linearIndependent` in favor of namespace `LinearIndependent.` + Remove `cardinal_lift_le_rank_of_linearIndependent'`, exact duplicate of the version without the prime + Rename `FiniteDimensional/Module.Finite.lt_aleph0_of_linearIndependent` to `LinearIndependent.lt_aleph0_of_finiteDimensional/finite` + Add one lemma `LinearIndependent.aleph0_le_rank` in LinearAlgebra/Dimension and two lemmas `LinearIndependent.finrank_eq_zero_of_infinite` and `finrank_eq_nat_card_basis` in LinearAlgebra/Finrank + Remove `StrongRankCondition` from `finrank_eq_zero_of_basis_imp_not_finite` and four subsequent lemmas Co-authored-by: Junyan Xu Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib/FieldTheory/Fixed.lean | 7 +-- Mathlib/LinearAlgebra/Dimension.lean | 60 ++++++++++--------- Mathlib/LinearAlgebra/FiniteDimensional.lean | 10 ++-- Mathlib/LinearAlgebra/Finrank.lean | 17 +++++- .../LinearAlgebra/FreeModule/Finite/Rank.lean | 54 ++++++++++------- 5 files changed, 90 insertions(+), 58 deletions(-) diff --git a/Mathlib/FieldTheory/Fixed.lean b/Mathlib/FieldTheory/Fixed.lean index 47d6b253bd880..7665979fd3d83 100644 --- a/Mathlib/FieldTheory/Fixed.lean +++ b/Mathlib/FieldTheory/Fixed.lean @@ -268,8 +268,7 @@ theorem rank_le_card : Module.rank (FixedPoints.subfield G F) F ≤ Fintype.card rank_le fun s hs => by simpa only [rank_fun', Cardinal.mk_coe_finset, Finset.coe_sort_coe, Cardinal.lift_natCast, Cardinal.natCast_le] using - cardinal_lift_le_rank_of_linearIndependent' - (linearIndependent_smul_of_linearIndependent G F hs) + (linearIndependent_smul_of_linearIndependent G F hs).cardinal_lift_le_rank #align fixed_points.rank_le_card FixedPoints.rank_le_card end Fintype @@ -323,7 +322,7 @@ theorem linearIndependent_toLinearMap (R : Type u) (A : Type v) (B : Type w) [Co theorem cardinal_mk_algHom (K : Type u) (V : Type v) (W : Type w) [Field K] [Field V] [Algebra K V] [FiniteDimensional K V] [Field W] [Algebra K W] [FiniteDimensional K W] : Cardinal.mk (V →ₐ[K] W) ≤ finrank W (V →ₗ[K] W) := - cardinal_mk_le_finrank_of_linearIndependent <| linearIndependent_toLinearMap K V W + (linearIndependent_toLinearMap K V W).cardinal_mk_le_finrank #align cardinal_mk_alg_hom cardinal_mk_algHom noncomputable instance AlgEquiv.fintype (K : Type u) (V : Type v) [Field K] [Field V] [Algebra K V] @@ -333,7 +332,7 @@ noncomputable instance AlgEquiv.fintype (K : Type u) (V : Type v) [Field K] [Fie theorem finrank_algHom (K : Type u) (V : Type v) [Field K] [Field V] [Algebra K V] [FiniteDimensional K V] : Fintype.card (V →ₐ[K] V) ≤ finrank V (V →ₗ[K] V) := - fintype_card_le_finrank_of_linearIndependent <| linearIndependent_toLinearMap K V V + (linearIndependent_toLinearMap K V V).fintype_card_le_finrank #align finrank_alg_hom finrank_algHom namespace FixedPoints diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean index a1083fa04d21f..32d63f47e5d47 100644 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ b/Mathlib/LinearAlgebra/Dimension.lean @@ -282,32 +282,39 @@ theorem rank_add_rank_le_rank_prod : variable {R M M'} -theorem cardinal_lift_le_rank_of_linearIndependent {ι : Type w} {v : ι → M} +namespace LinearIndependent + +theorem cardinal_lift_le_rank {ι : Type w} {v : ι → M} (hv : LinearIndependent R v) : Cardinal.lift.{v} #ι ≤ Cardinal.lift.{w} (Module.rank R M) := by - apply le_trans - · exact Cardinal.lift_mk_le'.mpr ⟨(Equiv.ofInjective _ hv.injective).toEmbedding⟩ - · simp only [Cardinal.lift_le, Module.rank_def] - apply le_trans - swap - · exact le_ciSup (Cardinal.bddAbove_range.{v, v} _) ⟨range v, hv.coe_range⟩ - · exact le_rfl -#align cardinal_lift_le_rank_of_linear_independent cardinal_lift_le_rank_of_linearIndependent + rw [Module.rank] + refine le_trans ?_ (lift_le.mpr <| le_ciSup (bddAbove_range.{v, v} _) ⟨_, hv.coe_range⟩) + exact lift_mk_le'.mpr ⟨(Equiv.ofInjective _ hv.injective).toEmbedding⟩ +#align cardinal_lift_le_rank_of_linear_independent LinearIndependent.cardinal_lift_le_rank +#align cardinal_lift_le_rank_of_linear_independent' LinearIndependent.cardinal_lift_le_rank -theorem cardinal_lift_le_rank_of_linearIndependent' {ι : Type w} {v : ι → M} - (hv : LinearIndependent R v) : Cardinal.lift.{v} #ι ≤ Cardinal.lift.{w} (Module.rank R M) := - cardinal_lift_le_rank_of_linearIndependent hv -#align cardinal_lift_le_rank_of_linear_independent' cardinal_lift_le_rank_of_linearIndependent' +lemma aleph0_le_rank {ι : Type w} [Infinite ι] {v : ι → M} + (hv : LinearIndependent R v) : ℵ₀ ≤ Module.rank R M := + aleph0_le_lift.mp <| (aleph0_le_lift.mpr <| aleph0_le_mk ι).trans hv.cardinal_lift_le_rank -theorem cardinal_le_rank_of_linearIndependent {ι : Type v} {v : ι → M} +theorem cardinal_le_rank {ι : Type v} {v : ι → M} (hv : LinearIndependent R v) : #ι ≤ Module.rank R M := by - simpa using cardinal_lift_le_rank_of_linearIndependent hv -#align cardinal_le_rank_of_linear_independent cardinal_le_rank_of_linearIndependent + simpa using hv.cardinal_lift_le_rank +#align cardinal_le_rank_of_linear_independent LinearIndependent.cardinal_le_rank -theorem cardinal_le_rank_of_linearIndependent' {s : Set M} +theorem cardinal_le_rank' {s : Set M} (hs : LinearIndependent R (fun x => x : s → M)) : #s ≤ Module.rank R M := - cardinal_le_rank_of_linearIndependent hs -#align cardinal_le_rank_of_linear_independent' cardinal_le_rank_of_linearIndependent' + hs.cardinal_le_rank +#align cardinal_le_rank_of_linear_independent' LinearIndependent.cardinal_le_rank' + +end LinearIndependent + +@[deprecated] +alias cardinal_lift_le_rank_of_linearIndependent := LinearIndependent.cardinal_lift_le_rank +@[deprecated] +alias cardinal_lift_le_rank_of_linearIndependent' := LinearIndependent.cardinal_lift_le_rank +@[deprecated] alias cardinal_le_rank_of_linearIndependent := LinearIndependent.cardinal_le_rank +@[deprecated] alias cardinal_le_rank_of_linearIndependent' := LinearIndependent.cardinal_le_rank' variable (R M) @@ -491,7 +498,7 @@ theorem CompleteLattice.Independent.subtype_ne_bot_le_rank [NoZeroSMulDivisors R exact i.prop choose v hvV hv using hI have : LinearIndependent R v := (hV.comp Subtype.coe_injective).linearIndependent _ hvV hv - exact cardinal_lift_le_rank_of_linearIndependent' this + exact this.cardinal_lift_le_rank #align complete_lattice.independent.subtype_ne_bot_le_rank CompleteLattice.Independent.subtype_ne_bot_le_rank end @@ -526,7 +533,7 @@ theorem rank_pos [Nontrivial M] : 0 < Module.rank R M := by suffices 1 ≤ Module.rank R M by exact zero_lt_one.trans_le this letI := Module.nontrivial R M suffices LinearIndependent R fun y : ({x} : Set M) => (y : M) by - simpa using cardinal_le_rank_of_linearIndependent this + simpa using this.cardinal_le_rank exact linearIndependent_singleton hx #align rank_pos rank_pos @@ -543,7 +550,7 @@ lemma rank_eq_zero_iff {R M} [Ring R] [AddCommGroup M] [Module R M] : have : LinearIndependent R (fun _ : Unit ↦ x) · exact linearIndependent_iff.mpr (fun l hl ↦ Finsupp.unique_ext <| not_not.mp fun H ↦ hx _ H ((Finsupp.total_unique _ _ _).symm.trans hl)) - simpa using cardinal_lift_le_rank_of_linearIndependent this + simpa using this.cardinal_lift_le_rank · intro h rw [← le_zero_iff, Module.rank_def] apply ciSup_le' @@ -570,7 +577,7 @@ theorem rank_quotient_eq_of_le_torsion {R M} [CommRing R] [AddCommGroup M] [Modu nontriviality R rw [Module.rank] have := nonempty_linearIndependent_set R M - refine ciSup_le fun ⟨s, hs⟩ ↦ cardinal_le_rank_of_linearIndependent (v := (N.mkQ ·)) ?_ + refine ciSup_le fun ⟨s, hs⟩ ↦ LinearIndependent.cardinal_le_rank (v := (N.mkQ ·)) ?_ rw [linearIndependent_iff'] at hs ⊢ simp_rw [← map_smul, ← map_sum, mkQ_apply, Quotient.mk_eq_zero] intro t g hg i hi @@ -1022,8 +1029,7 @@ theorem Basis.card_le_card_of_linearIndependent {ι : Type*} [Fintype ι] (b : B {ι' : Type*} [Fintype ι'] {v : ι' → M} (hv : LinearIndependent R v) : Fintype.card ι' ≤ Fintype.card ι := by letI := nontrivial_of_invariantBasisNumber R - simpa [rank_eq_card_basis b, Cardinal.mk_fintype] using - cardinal_lift_le_rank_of_linearIndependent' hv + simpa [rank_eq_card_basis b, Cardinal.mk_fintype] using hv.cardinal_lift_le_rank #align basis.card_le_card_of_linear_independent Basis.card_le_card_of_linearIndependent theorem Basis.card_le_card_of_submodule (N : Submodule R M) [Fintype ι] (b : Basis ι R M) @@ -1463,7 +1469,7 @@ theorem le_rank_iff_exists_linearIndependent {c : Cardinal} : rcases h with ⟨s, hst, hsc⟩ exact ⟨s, hsc, (ofVectorSpaceIndex.linearIndependent K V).mono hst⟩ · rintro ⟨s, rfl, si⟩ - exact cardinal_le_rank_of_linearIndependent si + exact si.cardinal_le_rank #align le_rank_iff_exists_linear_independent le_rank_iff_exists_linearIndependent theorem le_rank_iff_exists_linearIndependent_finset {n : ℕ} : ↑n ≤ Module.rank K V ↔ @@ -1674,7 +1680,7 @@ theorem le_rank_iff_exists_linearIndependent {c : Cardinal} {f : V →ₗ[K] V'} · rintro ⟨s, hsc, si⟩ have : LinearIndependent K fun x : s => f.rangeRestrict x := LinearIndependent.of_comp f.range.subtype (by convert si) - convert cardinal_le_rank_of_linearIndependent this.image + convert this.image.cardinal_le_rank rw [← Cardinal.lift_inj, ← hsc, Cardinal.mk_image_eq_of_injOn_lift] exact injOn_iff_injective.2 this.injective #align linear_map.le_rank_iff_exists_linear_independent LinearMap.le_rank_iff_exists_linearIndependent diff --git a/Mathlib/LinearAlgebra/FiniteDimensional.lean b/Mathlib/LinearAlgebra/FiniteDimensional.lean index 098d690e09217..c7e7c1b0ce4ee 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean @@ -216,10 +216,12 @@ theorem finrank_eq_card_basis' [FiniteDimensional K V] {ι : Type w} (h : Basis Module.mk_finrank_eq_card_basis h #align finite_dimensional.finrank_eq_card_basis' FiniteDimensional.finrank_eq_card_basis' -theorem lt_aleph0_of_linearIndependent {ι : Type w} [FiniteDimensional K V] {v : ι → V} - (h : LinearIndependent K v) : #ι < ℵ₀ := - Module.Finite.lt_aleph0_of_linearIndependent h -#align finite_dimensional.lt_aleph_0_of_linear_independent FiniteDimensional.lt_aleph0_of_linearIndependent +theorem _root_.LinearIndependent.lt_aleph0_of_finiteDimensional {ι : Type w} [FiniteDimensional K V] + {v : ι → V} (h : LinearIndependent K v) : #ι < ℵ₀ := + h.lt_aleph0_of_finite +#align finite_dimensional.lt_aleph_0_of_linear_independent LinearIndependent.lt_aleph0_of_finiteDimensional +@[deprecated] alias +lt_aleph0_of_linearIndependent := LinearIndependent.lt_aleph0_of_finiteDimensional /-- If a submodule has maximal dimension in a finite dimensional space, then it is equal to the whole space. -/ diff --git a/Mathlib/LinearAlgebra/Finrank.lean b/Mathlib/LinearAlgebra/Finrank.lean index 66a3dd77e3ad5..324138a45592c 100644 --- a/Mathlib/LinearAlgebra/Finrank.lean +++ b/Mathlib/LinearAlgebra/Finrank.lean @@ -184,14 +184,27 @@ end FiniteDimensional section ZeroRank -variable [Ring K] [StrongRankCondition K] [AddCommGroup V] [Module K V] [Module.Free K V] +variable [Ring K] [AddCommGroup V] [Module K V] open FiniteDimensional +lemma LinearIndependent.finrank_eq_zero_of_infinite {ι} [Nontrivial K] [Infinite ι] {v : ι → V} + (hv : LinearIndependent K v) : finrank K V = 0 := toNat_eq_zero.mpr <| .inr hv.aleph0_le_rank + +theorem finrank_eq_nat_card_basis {ι} [StrongRankCondition K] + (h : Basis ι K V) : finrank K V = Nat.card ι := by + rw [Nat.card, ← toNat_lift.{v}, h.mk_eq_rank, toNat_lift, finrank] + +variable [Module.Free K V] + theorem finrank_eq_zero_of_basis_imp_not_finite (h : ∀ s : Set V, Basis.{v} (s : Set V) K V → ¬s.Finite) : finrank K V = 0 := by + cases subsingleton_or_nontrivial K + · have := Module.subsingleton K V + exact (h ∅ ⟨LinearEquiv.ofSubsingleton _ _⟩ Set.finite_empty).elim obtain ⟨_, ⟨b⟩⟩ := (Module.free_iff_set K V).mp ‹_› - exact dif_neg fun rank_lt => h _ b (b.finite_index_of_rank_lt_aleph0 rank_lt) + have := Set.Infinite.to_subtype (h _ b) + exact b.linearIndependent.finrank_eq_zero_of_infinite #align finrank_eq_zero_of_basis_imp_not_finite finrank_eq_zero_of_basis_imp_not_finite theorem finrank_eq_zero_of_basis_imp_false (h : ∀ s : Finset V, Basis.{v} (s : Set V) K V → False) : diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean index d58aa46fcdc0b..6cab2f64a5f63 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean @@ -327,45 +327,57 @@ theorem basisUnique_repr_eq_zero_iff {ι : Type*} [Unique ι] fun hv => by rw [hv, LinearEquiv.map_zero, Finsupp.zero_apply]⟩ #align finite_dimensional.basis_unique.repr_eq_zero_iff FiniteDimensional.basisUnique_repr_eq_zero_iff -theorem cardinal_mk_le_finrank_of_linearIndependent [Module.Finite R V] +end FiniteDimensional + +namespace LinearIndependent + +theorem cardinal_mk_le_finrank [Module.Finite R V] {ι : Type w} {b : ι → V} (h : LinearIndependent R b) : #ι ≤ finrank R V := by rw [← lift_le.{max v w}] - simpa only [← finrank_eq_rank, lift_natCast, lift_le_nat_iff] using - cardinal_lift_le_rank_of_linearIndependent h -#align finite_dimensional.cardinal_mk_le_finrank_of_linear_independent FiniteDimensional.cardinal_mk_le_finrank_of_linearIndependent + simpa only [← finrank_eq_rank, lift_natCast, lift_le_nat_iff] using h.cardinal_lift_le_rank +#align finite_dimensional.cardinal_mk_le_finrank_of_linear_independent LinearIndependent.cardinal_mk_le_finrank -theorem fintype_card_le_finrank_of_linearIndependent [Module.Finite R V] +theorem fintype_card_le_finrank [Module.Finite R V] {ι : Type*} [Fintype ι] {b : ι → V} (h : LinearIndependent R b) : Fintype.card ι ≤ finrank R V := by - simpa using cardinal_mk_le_finrank_of_linearIndependent h -#align finite_dimensional.fintype_card_le_finrank_of_linear_independent FiniteDimensional.fintype_card_le_finrank_of_linearIndependent + simpa using h.cardinal_mk_le_finrank +#align finite_dimensional.fintype_card_le_finrank_of_linear_independent LinearIndependent.fintype_card_le_finrank -theorem finset_card_le_finrank_of_linearIndependent [Module.Finite R V] +theorem finset_card_le_finrank [Module.Finite R V] {b : Finset V} (h : LinearIndependent R (fun x => x : b → V)) : b.card ≤ finrank R V := by rw [← Fintype.card_coe] - exact fintype_card_le_finrank_of_linearIndependent h -#align finite_dimensional.finset_card_le_finrank_of_linear_independent FiniteDimensional.finset_card_le_finrank_of_linearIndependent + exact h.fintype_card_le_finrank +#align finite_dimensional.finset_card_le_finrank_of_linear_independent LinearIndependent.finset_card_le_finrank -end FiniteDimensional - -theorem Module.Finite.lt_aleph0_of_linearIndependent {ι : Type w} +theorem lt_aleph0_of_finite {ι : Type w} [Module.Finite R V] {v : ι → V} (h : LinearIndependent R v) : #ι < ℵ₀ := by apply Cardinal.lift_lt.1 apply lt_of_le_of_lt - apply cardinal_lift_le_rank_of_linearIndependent h + apply h.cardinal_lift_le_rank rw [← finrank_eq_rank, Cardinal.lift_aleph0, Cardinal.lift_natCast] apply Cardinal.nat_lt_aleph0 -theorem LinearIndependent.finite [Module.Finite R V] {ι : Type*} {f : ι → V} +theorem finite [Module.Finite R V] {ι : Type*} {f : ι → V} (h : LinearIndependent R f) : Finite ι := - Cardinal.lt_aleph0_iff_finite.1 <| Module.Finite.lt_aleph0_of_linearIndependent h + Cardinal.lt_aleph0_iff_finite.1 <| h.lt_aleph0_of_finite -theorem LinearIndependent.setFinite [Module.Finite R V] {b : Set V} +theorem setFinite [Module.Finite R V] {b : Set V} (h : LinearIndependent R fun x : b => (x : V)) : b.Finite := - Cardinal.lt_aleph0_iff_set_finite.mp (Module.Finite.lt_aleph0_of_linearIndependent h) + Cardinal.lt_aleph0_iff_set_finite.mp h.lt_aleph0_of_finite #align linear_independent.finite LinearIndependent.setFinite +end LinearIndependent + +@[deprecated] +alias cardinal_mk_le_finrank_of_linearIndependent := LinearIndependent.cardinal_mk_le_finrank +@[deprecated] +alias fintype_card_le_finrank_of_linearIndependent := LinearIndependent.fintype_card_le_finrank +@[deprecated] +alias finset_card_le_finrank_of_linearIndependent := LinearIndependent.finset_card_le_finrank +@[deprecated] +alias Module.Finite.lt_aleph0_of_linearIndependent := LinearIndependent.lt_aleph0_of_finite + theorem Module.Finite.not_linearIndependent_of_infinite {ι : Type*} [Infinite ι] [Module.Finite R V] (v : ι → V) : ¬LinearIndependent R v := mt LinearIndependent.finite <| @not_finite _ _ #align finite_dimensional.not_linear_independent_of_infinite Module.Finite.not_linearIndependent_of_infinite @@ -487,7 +499,7 @@ theorem Module.exists_nontrivial_relation_of_finrank_lt_card [Module.Finite R V] {t : Finset V} (h : finrank R V < t.card) : ∃ f : V → R, ∑ e in t, f e • e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by obtain ⟨g, sum, z, nonzero⟩ := Fintype.not_linearIndependent_iff.mp - (mt FiniteDimensional.finset_card_le_finrank_of_linearIndependent h.not_le) + (mt LinearIndependent.finset_card_le_finrank h.not_le) refine ⟨Subtype.val.extend g 0, ?_, z, z.2, by rwa [Subtype.val_injective.extend_apply]⟩ rw [← Finset.sum_finset_coe]; convert sum; apply Subtype.val_injective.extend_apply #align finite_dimensional.exists_nontrivial_relation_of_rank_lt_card Module.exists_nontrivial_relation_of_finrank_lt_card @@ -541,8 +553,8 @@ theorem Module.finite_of_rank_eq_nat [Module.Free R V] {n : ℕ} (h : Module.ran Module.Finite R V := by nontriviality R obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := R) (M := V) - have := mk_lt_aleph0_iff.mp <| cardinal_le_rank_of_linearIndependent - b.linearIndependent |>.trans_eq h |>.trans_lt <| nat_lt_aleph0 n + have := mk_lt_aleph0_iff.mp <| + b.linearIndependent.cardinal_le_rank |>.trans_eq h |>.trans_lt <| nat_lt_aleph0 n exact Module.Finite.of_basis b theorem Module.finite_of_rank_eq_zero [NoZeroSMulDivisors R V] From c7483a355afd192a212dbcf68f1f18fbc21e7469 Mon Sep 17 00:00:00 2001 From: Jujian Zhang Date: Wed, 27 Dec 2023 05:26:37 +0000 Subject: [PATCH 222/353] feat: In a ring, sets act on submodules (#7140) If $M$ is an $R$-module, $N$ a submodule and $S$ a subset of $R$. Then we can define $S \cdot N$ to be the smallest submodule containing all $s \cdot n$ where $s \in S$ and $n \in N$ Co-authored-by: Johan Commelin Co-authored-by: Mario Carneiro --- .../Algebra/Module/Submodule/Pointwise.lean | 302 +++++++++++++++++- Mathlib/RingTheory/Ideal/Operations.lean | 11 + 2 files changed, 311 insertions(+), 2 deletions(-) diff --git a/Mathlib/Algebra/Module/Submodule/Pointwise.lean b/Mathlib/Algebra/Module/Submodule/Pointwise.lean index 68e9e0876b03d..712607fa38d87 100644 --- a/Mathlib/Algebra/Module/Submodule/Pointwise.lean +++ b/Mathlib/Algebra/Module/Submodule/Pointwise.lean @@ -1,10 +1,13 @@ /- Copyright (c) 2021 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Eric Wieser +Authors: Eric Wieser, Jujian Zhang -/ import Mathlib.GroupTheory.Subgroup.Pointwise import Mathlib.LinearAlgebra.Span +import Mathlib.LinearAlgebra.Finsupp +import Mathlib.RingTheory.Ideal.Basic +import Mathlib.Algebra.Module.BigOperators #align_import algebra.module.submodule.pointwise from "leanprover-community/mathlib"@"48085f140e684306f9e7da907cd5932056d1aded" @@ -21,12 +24,21 @@ and the actions which matches the action of `Set.mulActionSet`. +This file also provides: +* `Submodule.pointwiseSetSMulSubmodule`: for `R`-module `M`, a `s : Set R` can act on + `N : Submodule R M` by defining `s • N` to be the smallest submodule containing all `a • n` + where `a ∈ s` and `n ∈ N`. + These actions are available in the `Pointwise` locale. ## Implementation notes -Most of the lemmas in this file are direct copies of lemmas from +For an `R`-module `M`, The action of a subset of `R` acting on a submodule of `M` introduced in +section `set_acting_on_submodules` does not have a counterpart in `GroupTheory/Submonoid/Pointwise.lean`. + +Other than section `set_acting_on_submodules`, most of the lemmas in this file are direct copies of +lemmas from `GroupTheory/Submonoid/Pointwise.lean`. -/ @@ -277,4 +289,290 @@ scoped[Pointwise] attribute [instance] Submodule.pointwiseMulActionWithZero end +/-! +### Sets acting on Submodules + +Let `R` be a (semi)ring and `M` an `R`-module. Let `S` be a monoid which acts on `M` distributively, +then subsets of `S` can act on submodules of `M`. +For subset `s ⊆ S` and submodule `N ≤ M`, we define `s • N` to be the smallest submodule containing +all `r • n` where `r ∈ s` and `n ∈ N`. + +#### Results +For arbitrary monoids `S` acting distributively on `M`, there is an induction principle for `s • N`: +To prove `P` holds for all `s • N`, it is enough +to prove: +- for all `r ∈ s` and `n ∈ N`, `P (r • n)`; +- for all `r` and `m ∈ s • N`, `P (r • n)`; +- for all `m₁, m₂`, `P m₁` and `P m₂` implies `P (m₁ + m₂)`; +- `P 0`. + +To invoke this induction principal, use `induction x, hx using Submodule.set_smul_inductionOn` where +`x : M` and `hx : x ∈ s • N` + +When we consider subset of `R` acting on `M` +- `Submodule.pointwiseSetDistribMulAction` : the action described above is distributive. +- `Submodule.mem_set_smul` : `x ∈ s • N` iff `x` can be written as `r₀ n₀ + ... + rₖ nₖ` where + `rᵢ ∈ s` and `nᵢ ∈ N`. +- `Submodule.coe_span_smul`: `s • N` is the same as `⟨s⟩ • N` where `⟨s⟩` is the ideal spanned + by `s`. + + +#### Notes +- If we assume the addition on subsets of `R` is the `⊔` and subtraction `⊓` i.e. use `SetSemiring`, +then this action actually gives a module structure on submodules of `M` over subsets of `R`. +- If we generalize so that `r • N` makes sense for all `r : S`, then `Submodule.singleton_set_smul` + and `Submodule.singleton_set_smul` can be generalized as well. +-/ + +section set_acting_on_submodules + +variable {S : Type*} [Monoid S] + +variable [AddCommMonoid M] [Module R M] [DistribMulAction S M] + +/-- +Let `s ⊆ R` be a set and `N ≤ M` be a submodule, then `s • N` is the smallest submodule containing +all `r • n` where `r ∈ s` and `n ∈ N`. +-/ +protected def pointwiseSetSMul : SMul (Set S) (Submodule R M) where + smul s N := sInf { p | ∀ ⦃r : S⦄ ⦃n : M⦄, r ∈ s → n ∈ N → r • n ∈ p } + +scoped[Pointwise] attribute [instance] Submodule.pointwiseSetSMul + +variable (sR : Set R) (s : Set S) (N : Submodule R M) + +lemma mem_set_smul_def (x : M) : + x ∈ s • N ↔ + x ∈ sInf { p : Submodule R M | ∀ ⦃r : S⦄ {n : M}, r ∈ s → n ∈ N → r • n ∈ p } := Iff.rfl + +variable {s N} in +@[aesop safe] +lemma mem_set_smul_of_mem_mem {r : S} {m : M} (mem1 : r ∈ s) (mem2 : m ∈ N) : + r • m ∈ s • N := by + rw [mem_set_smul_def, mem_sInf] + exact fun _ h => h mem1 mem2 + +lemma set_smul_le (p : Submodule R M) + (closed_under_smul : ∀ ⦃r : S⦄ ⦃n : M⦄, r ∈ s → n ∈ N → r • n ∈ p) : + s • N ≤ p := + sInf_le closed_under_smul + +lemma set_smul_le_iff (p : Submodule R M) : + s • N ≤ p ↔ + ∀ ⦃r : S⦄ ⦃n : M⦄, r ∈ s → n ∈ N → r • n ∈ p := by + fconstructor + · intro h r n hr hn + exact h <| mem_set_smul_of_mem_mem hr hn + · apply set_smul_le + +lemma set_smul_eq_of_le (p : Submodule R M) + (closed_under_smul : ∀ ⦃r : S⦄ ⦃n : M⦄, r ∈ s → n ∈ N → r • n ∈ p) + (le : p ≤ s • N) : + s • N = p := + le_antisymm (set_smul_le s N p closed_under_smul) le + +lemma set_smul_mono_right {p q : Submodule R M} (le : p ≤ q) : + s • p ≤ s • q := + set_smul_le _ _ _ fun _ _ hr hm => mem_set_smul_of_mem_mem (mem1 := hr) + (mem2 := le hm) + +lemma set_smul_mono_left {s t : Set S} (le : s ≤ t) : + s • N ≤ t • N := + set_smul_le _ _ _ fun _ _ hr hm => mem_set_smul_of_mem_mem (mem1 := le hr) + (mem2 := hm) + +lemma set_smul_le_of_le_le {s t : Set S} {p q : Submodule R M} + (le_set : s ≤ t) (le_submodule : p ≤ q) : s • p ≤ t • q := + le_trans (set_smul_mono_left _ le_set) <| set_smul_mono_right _ le_submodule + +variable {s N} in +/-- +Induction principal for set acting on submodules. To prove `P` holds for all `s • N`, it is enough +to prove: +- for all `r ∈ s` and `n ∈ N`, `P (r • n)`; +- for all `r` and `m ∈ s • N`, `P (r • n)`; +- for all `m₁, m₂`, `P m₁` and `P m₂` implies `P (m₁ + m₂)`; +- `P 0`. + +To invoke this induction principal, use `induction x, hx using Submodule.set_smul_inductionOn` where +`x : M` and `hx : x ∈ s • N` +-/ +@[elab_as_elim] +lemma set_smul_inductionOn {motive : (x : M) → (_ : x ∈ s • N) → Prop} + (x : M) + (hx : x ∈ s • N) + (smul₀ : ∀ ⦃r : S⦄ ⦃n : M⦄ (mem₁ : r ∈ s) (mem₂ : n ∈ N), + motive (r • n) (mem_set_smul_of_mem_mem mem₁ mem₂)) + (smul₁ : ∀ (r : R) ⦃m : M⦄ (mem : m ∈ s • N) , + motive m mem → motive (r • m) (Submodule.smul_mem _ r mem)) -- + (add : ∀ ⦃m₁ m₂ : M⦄ (mem₁: m₁ ∈ s • N) (mem₂ : m₂ ∈ s • N), + motive m₁ mem₁ → motive m₂ mem₂ → motive (m₁ + m₂) (Submodule.add_mem _ mem₁ mem₂)) + (zero : motive 0 (Submodule.zero_mem _)) : + motive x hx := + let ⟨_, h⟩ := set_smul_le s N + { carrier := { m | ∃ (mem : m ∈ s • N), motive m mem }, + zero_mem' := ⟨Submodule.zero_mem _, zero⟩ + add_mem' := fun ⟨mem, h⟩ ⟨mem', h'⟩ ↦ ⟨_, add mem mem' h h'⟩ + smul_mem' := fun r _ ⟨mem, h⟩ ↦ ⟨_, smul₁ r mem h⟩ } + (fun _ _ mem mem' ↦ ⟨mem_set_smul_of_mem_mem mem mem', smul₀ mem mem'⟩) hx + h + +-- Implementation note: if `N` is both an `R`-submodule and `S`-submodule and `SMulCommClass R S M`, +-- this lemma is also true for any `s : Set S`. +lemma set_smul_eq_map [SMulCommClass R R N] : + sR • N = + Submodule.map + (N.subtype.comp (Finsupp.lsum R <| DistribMulAction.toLinearMap _ _)) + (Finsupp.supported N R sR) := by + classical + apply set_smul_eq_of_le + · intro r n hr hn + exact ⟨Finsupp.single r ⟨n, hn⟩, Finsupp.single_mem_supported _ _ hr, by simp⟩ + + · intro x hx + obtain ⟨c, hc, rfl⟩ := hx + simp only [LinearMap.coe_comp, coeSubtype, Finsupp.coe_lsum, Finsupp.sum, LinearMap.coe_mk, + AddHom.coe_mk, Function.comp_apply, AddSubmonoid.coe_finset_sum, coe_toAddSubmonoid, + SetLike.val_smul] + refine Submodule.sum_mem (p := sR • N) (t := c.support) ?_ _ ⟨sR • N, ?_⟩ + · rintro r hr + rw [mem_set_smul_def, Submodule.mem_sInf] + rintro p hp + exact hp (hc hr) (c r).2 + · ext x : 1 + simp only [Set.mem_iInter, SetLike.mem_coe] + fconstructor + · refine fun h ↦ h fun r n hr hn ↦ ?_ + rw [mem_set_smul_def, mem_sInf] + exact fun p hp ↦ hp hr hn + · aesop + +lemma mem_set_smul(x : M) [SMulCommClass R R N] : + x ∈ sR • N ↔ ∃ (c : R →₀ N), (c.support : Set R) ⊆ sR ∧ x = c.sum fun r m ↦ r • m := by + fconstructor + · intros h + rw [set_smul_eq_map] at h + obtain ⟨c, hc, rfl⟩ := h + exact ⟨c, hc, rfl⟩ + + · rw [mem_set_smul_def, Submodule.mem_sInf] + rintro ⟨c, hc1, rfl⟩ p hp + simp only [Finsupp.sum, AddSubmonoid.coe_finset_sum, coe_toAddSubmonoid, SetLike.val_smul] + exact Submodule.sum_mem _ fun r hr ↦ hp (hc1 hr) (c _).2 + +@[simp] lemma empty_set_smul : (∅ : Set S) • N = ⊥ := by + ext + fconstructor + · intro hx + rw [mem_set_smul_def, Submodule.mem_sInf] at hx + exact hx ⊥ (fun r _ hr ↦ hr.elim) + · rintro rfl; exact Submodule.zero_mem _ + +@[simp] lemma set_smul_bot : s • (⊥ : Submodule R M) = ⊥ := + eq_bot_iff.mpr fun x hx ↦ by induction x, hx using set_smul_inductionOn <;> aesop + +-- TODO: `r • N` should be generalized to allow `r` to be an element of `S`. +lemma singleton_set_smul [SMulCommClass R R M] (r : R) : + ({r} : Set R) • N = r • N := by + apply set_smul_eq_of_le + · rintro r m rfl hm; exact ⟨m, hm, rfl⟩ + · rintro _ ⟨m, hm, rfl⟩ + rw [mem_set_smul_def, Submodule.mem_sInf] + intro p hp; exact hp rfl hm + +lemma mem_singleton_set_smul [SMulCommClass R S M] (r : S) (x : M) : + x ∈ ({r} : Set S) • N ↔ ∃ (m : M), m ∈ N ∧ x = r • m := by + fconstructor + · intro hx + induction' x, hx using Submodule.set_smul_inductionOn with + t n memₜ memₙ t n mem h m₁ m₂ mem₁ mem₂ h₁ h₂ + · aesop + · rcases h with ⟨n, hn, rfl⟩ + exact ⟨t • n, by aesop, smul_comm _ _ _⟩ + · rcases h₁ with ⟨m₁, h₁, rfl⟩ + rcases h₂ with ⟨m₂, h₂, rfl⟩ + exact ⟨m₁ + m₂, Submodule.add_mem _ h₁ h₂, by aesop⟩ + · exact ⟨0, Submodule.zero_mem _, by aesop⟩ + · rintro ⟨m, hm, rfl⟩ + aesop + +-- Note that this can't be generalized to `Set S`, because even though `SMulCommClass R R M` implies +-- `SMulComm R R N` for all `R`-submodules `N`, `SMulCommClass R S N` for all `R`-submodules `N` +-- does not make sense. If we just focus on `R`-submodules that are also `S`-submodule, then this +-- should be true. +/-- A subset of a ring `R` has a multiplicative action on submodules of a module over `R`. -/ +protected def pointwiseSetMulAction [SMulCommClass R R M] : + MulAction (Set R) (Submodule R M) where + one_smul x := show {(1 : R)} • x = x from SetLike.ext fun m => + (mem_singleton_set_smul _ _ _).trans ⟨by rintro ⟨_, h, rfl⟩; rwa [one_smul], + fun h => ⟨m, h, (one_smul _ _).symm⟩⟩ + mul_smul s t x := le_antisymm + (set_smul_le _ _ _ <| by rintro _ _ ⟨_, _, _, _, rfl⟩ _; rw [mul_smul]; aesop) + (set_smul_le _ _ _ <| by + rintro r m hr hm + have : SMulCommClass R R x := ⟨fun r s m => Subtype.ext <| smul_comm _ _ _⟩ + obtain ⟨c, hc1, rfl⟩ := mem_set_smul _ _ _ |>.mp hm + simp only [Finsupp.sum, AddSubmonoid.coe_finset_sum, coe_toAddSubmonoid, SetLike.val_smul, + Finset.smul_sum] + exact Submodule.sum_mem _ fun r' hr' ↦ mul_smul r r' (c r' : M) ▸ + mem_set_smul_of_mem_mem (mem1 := ⟨r, r', hr, hc1 hr', rfl⟩) (mem2 := (c _).2)) + +scoped[Pointwise] attribute [instance] Submodule.pointwiseSetMulAction + +-- TODO: `r • N` should be generalized to allow `r` to be an element of `S`. +lemma set_smul_eq_iSup [SMulCommClass R R M] : + sR • N = ⨆ (r ∈ sR), r • N := + set_smul_eq_of_le _ _ _ + (fun r m hr hm => (show r • N ≤ _ by + rw [iSup_subtype', ← sSup_range] + exact le_sSup ⟨⟨r, hr⟩, rfl⟩) ⟨_, hm, rfl⟩) <| by + rw [iSup_subtype', ← sSup_range, sSup_le_iff] + rintro _ ⟨⟨x, hx⟩, rfl⟩ _ ⟨y, hy, rfl⟩ + exact mem_set_smul_of_mem_mem (mem1 := hx) (mem2 := hy) + +-- This cannot be generalized to `Set S` because `MulAction` can't be generalized already. +/-- In a ring, sets acts on submodules. -/ +protected def pointwiseSetDistribMulAction [SMulCommClass R R M] : + DistribMulAction (Set R) (Submodule R M) where + smul_zero s := set_smul_bot s + smul_add s x y := le_antisymm + (set_smul_le _ _ _ <| by + rintro r m hr hm + rw [add_eq_sup, Submodule.mem_sup] at hm + obtain ⟨a, ha, b, hb, rfl⟩ := hm + rw [smul_add, add_eq_sup, Submodule.mem_sup] + exact ⟨r • a, mem_set_smul_of_mem_mem (mem1 := hr) (mem2 := ha), + r • b, mem_set_smul_of_mem_mem (mem1 := hr) (mem2 := hb), rfl⟩) + (sup_le_iff.mpr ⟨set_smul_mono_right _ le_sup_left, + set_smul_mono_right _ le_sup_right⟩) + +scoped[Pointwise] attribute [instance] Submodule.pointwiseSetDistribMulAction + +lemma sup_set_smul (s t : Set S) : + (s ⊔ t) • N = s • N ⊔ t • N := + set_smul_eq_of_le _ _ _ + (by rintro _ _ (hr|hr) hn + · exact Submodule.mem_sup_left (mem_set_smul_of_mem_mem hr hn) + · exact Submodule.mem_sup_right (mem_set_smul_of_mem_mem hr hn)) + (sup_le (set_smul_mono_left _ le_sup_left) (set_smul_mono_left _ le_sup_right)) + +lemma coe_span_smul {R' M' : Type*} [CommSemiring R'] [AddCommMonoid M'] [Module R' M'] + (s : Set R') (N : Submodule R' M') : + (Ideal.span s : Set R') • N = s • N := + set_smul_eq_of_le _ _ _ + (by rintro r n hr hn + induction' hr using Submodule.span_induction' with r h _ _ _ _ ihr ihs r r' hr hr' + · exact mem_set_smul_of_mem_mem h hn + · rw [zero_smul]; exact Submodule.zero_mem _ + · rw [add_smul]; exact Submodule.add_mem _ ihr ihs + · rw [mem_span_set] at hr + obtain ⟨c, hc, rfl⟩ := hr + rw [Finsupp.sum, Finset.smul_sum, Finset.sum_smul] + refine Submodule.sum_mem _ fun i hi => ?_ + rw [← mul_smul, smul_eq_mul, mul_comm, mul_smul] + exact mem_set_smul_of_mem_mem (hc hi) <| Submodule.smul_mem _ _ hn) <| + set_smul_mono_left _ Submodule.subset_span + +end set_acting_on_submodules + end Submodule diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 2c5516daf12f1..ca89ba46b2aa5 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -110,6 +110,12 @@ theorem smul_le {P : Submodule R M} : I • N ≤ P ↔ ∀ r ∈ I, ∀ n ∈ N map₂_le #align submodule.smul_le Submodule.smul_le +@[simp, norm_cast] +lemma coe_set_smul : (I : Set R) • N = I • N := + Submodule.set_smul_eq_of_le _ _ _ + (fun _ _ hr hx => smul_mem_smul hr hx) + (smul_le.mpr fun _ hr _ hx => mem_set_smul_of_mem_mem hr hx) + @[elab_as_elim] theorem smul_induction_on {p : M → Prop} {x} (H : x ∈ I • N) (Hb : ∀ r ∈ I, ∀ n ∈ N, p (r • n)) (H1 : ∀ x y, p x → p y → p (x + y)) : p x := by @@ -2289,6 +2295,11 @@ instance moduleSubmodule : Module (Ideal R) (Submodule R M) where smul_zero := smul_bot #align submodule.module_submodule Submodule.moduleSubmodule +lemma span_smul_eq + (s : Set R) (N : Submodule R M) : + Ideal.span s • N = s • N := by + rw [← coe_set_smul, coe_span_smul] + end Submodule namespace RingHom From f9e2c2ca39707c94f2893124ca247b78ebb001ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 05:26:38 +0000 Subject: [PATCH 223/353] refactor(AlgebraicTopology): using the cofan API for SplitSimplicialObject (#8531) This PR changes the definition of a splitting of simplicial objects. The new definition makes a better use of the cofan API. As a result, it is no longer necessary to assume that the category has finite coproducts. --- .../DoldKan/FunctorGamma.lean | 72 +++++---- .../AlgebraicTopology/DoldKan/GammaCompN.lean | 4 +- .../AlgebraicTopology/DoldKan/NCompGamma.lean | 10 +- .../DoldKan/SplitSimplicialObject.lean | 98 ++++++------ .../SplitSimplicialObject.lean | 140 +++++++----------- 5 files changed, 136 insertions(+), 188 deletions(-) diff --git a/Mathlib/AlgebraicTopology/DoldKan/FunctorGamma.lean b/Mathlib/AlgebraicTopology/DoldKan/FunctorGamma.lean index cb2af4b91d7e5..362a3da24f2e0 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/FunctorGamma.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/FunctorGamma.lean @@ -231,65 +231,56 @@ def obj (K : ChainComplex C ℕ) : SimplicialObject C where rfl) #align algebraic_topology.dold_kan.Γ₀.obj AlgebraicTopology.DoldKan.Γ₀.obj - -theorem splitting_map_eq_id (Δ : SimplexCategoryᵒᵖ) : - SimplicialObject.Splitting.map (Γ₀.obj K) - (fun n : ℕ => Sigma.ι (Γ₀.Obj.summand K (op [n])) (Splitting.IndexSet.id (op [n]))) Δ = - 𝟙 _ := colimit.hom_ext (fun ⟨A⟩ => by - induction' Δ using Opposite.rec' with Δ - induction' Δ using SimplexCategory.rec with n - dsimp [Splitting.map] - simp only [colimit.ι_desc, Cofan.mk_ι_app, Γ₀.obj_map] - erw [Γ₀.Obj.map_on_summand₀ K (SimplicialObject.Splitting.IndexSet.id A.1) - (show A.e ≫ 𝟙 _ = A.e.op.unop ≫ 𝟙 _ by rfl), - Γ₀.Obj.Termwise.mapMono_id, A.ext', id_comp, comp_id] - rfl) -#align algebraic_topology.dold_kan.Γ₀.splitting_map_eq_id AlgebraicTopology.DoldKan.Γ₀.splitting_map_eq_id - /-- By construction, the simplicial `Γ₀.obj K` is equipped with a splitting. -/ def splitting (K : ChainComplex C ℕ) : SimplicialObject.Splitting (Γ₀.obj K) where N n := K.X n ι n := Sigma.ι (Γ₀.Obj.summand K (op [n])) (Splitting.IndexSet.id (op [n])) - map_isIso Δ := by - rw [Γ₀.splitting_map_eq_id] - apply IsIso.id + isColimit' Δ := IsColimit.ofIsoColimit (colimit.isColimit _) (Cofan.ext (Iso.refl _) (by + intro A + dsimp [Splitting.cofan'] + rw [comp_id, Γ₀.Obj.map_on_summand₀ K (SimplicialObject.Splitting.IndexSet.id A.1) + (show A.e ≫ 𝟙 _ = A.e.op.unop ≫ 𝟙 _ by rfl), Γ₀.Obj.Termwise.mapMono_id] + dsimp + rw [id_comp] + rfl)) #align algebraic_topology.dold_kan.Γ₀.splitting AlgebraicTopology.DoldKan.Γ₀.splitting -@[simp 1100] -theorem splitting_iso_hom_eq_id (Δ : SimplexCategoryᵒᵖ) : ((splitting K).iso Δ).hom = 𝟙 _ := - splitting_map_eq_id K Δ -#align algebraic_topology.dold_kan.Γ₀.splitting_iso_hom_eq_id AlgebraicTopology.DoldKan.Γ₀.splitting_iso_hom_eq_id - @[reassoc] theorem Obj.map_on_summand {Δ Δ' : SimplexCategoryᵒᵖ} (A : Splitting.IndexSet Δ) (θ : Δ ⟶ Δ') {Δ'' : SimplexCategory} {e : Δ'.unop ⟶ Δ''} {i : Δ'' ⟶ A.1.unop} [Epi e] [Mono i] (fac : e ≫ i = θ.unop ≫ A.e) : - (Γ₀.splitting K).ιSummand A ≫ (Γ₀.obj K).map θ = - Γ₀.Obj.Termwise.mapMono K i ≫ (Γ₀.splitting K).ιSummand (Splitting.IndexSet.mk e) := by - dsimp only [SimplicialObject.Splitting.ιSummand, SimplicialObject.Splitting.ιCoprod] - simp only [assoc, Γ₀.splitting_iso_hom_eq_id, id_comp, comp_id] - exact Γ₀.Obj.map_on_summand₀ K A fac + ((Γ₀.splitting K).cofan Δ).inj A ≫ (Γ₀.obj K).map θ = + Γ₀.Obj.Termwise.mapMono K i ≫ ((Γ₀.splitting K).cofan Δ').inj (Splitting.IndexSet.mk e) := by + dsimp [Splitting.cofan] + change (_ ≫ (Γ₀.obj K).map A.e.op) ≫ (Γ₀.obj K).map θ = _ + rw [assoc, ← Functor.map_comp] + dsimp [splitting] + erw [Γ₀.Obj.map_on_summand₀ K (Splitting.IndexSet.id A.1) + (show e ≫ i = ((Splitting.IndexSet.e A).op ≫ θ).unop ≫ 𝟙 _ by rw [comp_id, fac]; rfl), + Γ₀.Obj.map_on_summand₀ K (Splitting.IndexSet.id (op Δ'')) + (show e ≫ 𝟙 Δ'' = e.op.unop ≫ 𝟙 _ by simp), Termwise.mapMono_id, id_comp] #align algebraic_topology.dold_kan.Γ₀.obj.map_on_summand AlgebraicTopology.DoldKan.Γ₀.Obj.map_on_summand @[reassoc] theorem Obj.map_on_summand' {Δ Δ' : SimplexCategoryᵒᵖ} (A : Splitting.IndexSet Δ) (θ : Δ ⟶ Δ') : - (splitting K).ιSummand A ≫ (obj K).map θ = - Obj.Termwise.mapMono K (image.ι (θ.unop ≫ A.e)) ≫ (splitting K).ιSummand (A.pull θ) := by + ((splitting K).cofan Δ).inj A ≫ (obj K).map θ = + Obj.Termwise.mapMono K (image.ι (θ.unop ≫ A.e)) ≫ + ((splitting K).cofan Δ').inj (A.pull θ) := by apply Obj.map_on_summand apply image.fac #align algebraic_topology.dold_kan.Γ₀.obj.map_on_summand' AlgebraicTopology.DoldKan.Γ₀.Obj.map_on_summand' @[reassoc] theorem Obj.mapMono_on_summand_id {Δ Δ' : SimplexCategory} (i : Δ' ⟶ Δ) [Mono i] : - (splitting K).ιSummand (Splitting.IndexSet.id (op Δ)) ≫ (obj K).map i.op = - Obj.Termwise.mapMono K i ≫ (splitting K).ιSummand (Splitting.IndexSet.id (op Δ')) := + ((splitting K).cofan _).inj (Splitting.IndexSet.id (op Δ)) ≫ (obj K).map i.op = + Obj.Termwise.mapMono K i ≫ ((splitting K).cofan _).inj (Splitting.IndexSet.id (op Δ')) := Obj.map_on_summand K (Splitting.IndexSet.id (op Δ)) i.op (rfl : 𝟙 _ ≫ i = i ≫ 𝟙 _) #align algebraic_topology.dold_kan.Γ₀.obj.map_mono_on_summand_id AlgebraicTopology.DoldKan.Γ₀.Obj.mapMono_on_summand_id @[reassoc] theorem Obj.map_epi_on_summand_id {Δ Δ' : SimplexCategory} (e : Δ' ⟶ Δ) [Epi e] : - (Γ₀.splitting K).ιSummand (Splitting.IndexSet.id (op Δ)) ≫ (Γ₀.obj K).map e.op = - (Γ₀.splitting K).ιSummand (Splitting.IndexSet.mk e) := by + ((Γ₀.splitting K).cofan _).inj (Splitting.IndexSet.id (op Δ)) ≫ (Γ₀.obj K).map e.op = + ((Γ₀.splitting K).cofan _).inj (Splitting.IndexSet.mk e) := by simpa only [Γ₀.Obj.map_on_summand K (Splitting.IndexSet.id (op Δ)) e.op (rfl : e ≫ 𝟙 Δ = e ≫ 𝟙 Δ), Γ₀.Obj.Termwise.mapMono_id] using id_comp _ @@ -298,7 +289,8 @@ theorem Obj.map_epi_on_summand_id {Δ Δ' : SimplexCategory} (e : Δ' ⟶ Δ) [E /-- The functor `Γ₀ : ChainComplex C ℕ ⥤ SimplicialObject C`, on morphisms. -/ @[simps] def map {K K' : ChainComplex C ℕ} (f : K ⟶ K') : obj K ⟶ obj K' where - app Δ := (Γ₀.splitting K).desc Δ fun A => f.f A.1.unop.len ≫ (Γ₀.splitting K').ιSummand A + app Δ := (Γ₀.splitting K).desc Δ fun A => f.f A.1.unop.len ≫ + ((Γ₀.splitting K').cofan _).inj A naturality {Δ' Δ} θ := by apply (Γ₀.splitting K).hom_ext' intro A @@ -323,7 +315,7 @@ def Γ₀' : ChainComplex C ℕ ⥤ SimplicialObject.Split C where f := f.f comm := fun n => by dsimp - simp only [← Splitting.ιSummand_id, (Γ₀.splitting K).ι_desc] + simp only [← Splitting.cofan_inj_id, (Γ₀.splitting K).ι_desc] rfl } #align algebraic_topology.dold_kan.Γ₀' AlgebraicTopology.DoldKan.Γ₀' @@ -344,7 +336,8 @@ def Γ₂ : Karoubi (ChainComplex C ℕ) ⥤ Karoubi (SimplicialObject C) := #align algebraic_topology.dold_kan.Γ₂ AlgebraicTopology.DoldKan.Γ₂ theorem HigherFacesVanish.on_Γ₀_summand_id (K : ChainComplex C ℕ) (n : ℕ) : - HigherFacesVanish (n + 1) ((Γ₀.splitting K).ιSummand (Splitting.IndexSet.id (op [n + 1]))) := by + @HigherFacesVanish C _ _ (Γ₀.obj K) _ n (n + 1) + (((Γ₀.splitting K).cofan _).inj (Splitting.IndexSet.id (op [n + 1]))) := by intro j _ have eq := Γ₀.Obj.mapMono_on_summand_id K (SimplexCategory.δ j.succ) rw [Γ₀.Obj.Termwise.mapMono_eq_zero K, zero_comp] at eq; rotate_left @@ -356,8 +349,9 @@ theorem HigherFacesVanish.on_Γ₀_summand_id (K : ChainComplex C ℕ) (n : ℕ) @[reassoc (attr := simp)] theorem PInfty_on_Γ₀_splitting_summand_eq_self (K : ChainComplex C ℕ) {n : ℕ} : - (Γ₀.splitting K).ιSummand (Splitting.IndexSet.id (op [n])) ≫ (PInfty : K[Γ₀.obj K] ⟶ _).f n = - (Γ₀.splitting K).ιSummand (Splitting.IndexSet.id (op [n])) := by + ((Γ₀.splitting K).cofan _).inj (Splitting.IndexSet.id (op [n])) ≫ + (PInfty : K[Γ₀.obj K] ⟶ _).f n = + ((Γ₀.splitting K).cofan _).inj (Splitting.IndexSet.id (op [n])) := by rw [PInfty_f] rcases n with _|n · simpa only [P_f_0_eq] using comp_id _ diff --git a/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean b/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean index 1634c0e310058..0f9927406eb58 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean @@ -42,7 +42,7 @@ def Γ₀NondegComplexIso (K : ChainComplex C ℕ) : (Γ₀.splitting K).nondegC rw [Fintype.sum_eq_single (0 : Fin (n + 2))] · simp only [Fin.val_zero, pow_zero, one_zsmul] erw [Γ₀.Obj.mapMono_on_summand_id_assoc, Γ₀.Obj.Termwise.mapMono_δ₀, - Splitting.ι_πSummand_eq_id, comp_id] + Splitting.cofan_inj_πSummand_eq_id, comp_id] · intro i hi dsimp simp only [Preadditive.zsmul_comp, Preadditive.comp_zsmul, assoc] @@ -172,7 +172,7 @@ set_option linter.uppercaseLean3 false in @[simp] theorem N₂Γ₂_inv_app_f_f (X : Karoubi (ChainComplex C ℕ)) (n : ℕ) : (N₂Γ₂.inv.app X).f.f n = - X.p.f n ≫ (Γ₀.splitting X.X).ιSummand (Splitting.IndexSet.id (op [n])) := by + X.p.f n ≫ ((Γ₀.splitting X.X).cofan _).inj (Splitting.IndexSet.id (op [n])) := by dsimp [N₂Γ₂] simp only [whiskeringLeft_obj_preimage_app, NatTrans.comp_app, Functor.comp_map, Karoubi.comp_f, N₂Γ₂ToKaroubiIso_inv_app, HomologicalComplex.comp_f, diff --git a/Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean b/Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean index 3181a978372d3..978864ca05978 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/NCompGamma.lean @@ -12,7 +12,7 @@ import Mathlib.AlgebraicTopology.DoldKan.NReflectsIso In order to construct the unit isomorphism of the Dold-Kan equivalence, we first construct natural transformations -`Γ₂N₁.natTrans : N₁ ⋙ Γ₂ ⟶ toKaroubi (simplicial_object C)` and +`Γ₂N₁.natTrans : N₁ ⋙ Γ₂ ⟶ toKaroubi (SimplicialObject C)` and `Γ₂N₂.natTrans : N₂ ⋙ Γ₂ ⟶ 𝟭 (SimplicialObject C)`. It is then shown that `Γ₂N₂.natTrans` is an isomorphism by using that it becomes an isomorphism after the application of the functor @@ -151,14 +151,14 @@ def natTrans : (N₁ : SimplicialObject C ⥤ _) ⋙ Γ₂ ⟶ toKaroubi _ where apply (Γ₀.splitting K[X]).hom_ext intro n dsimp [N₁] - simp only [← Splitting.ιSummand_id, Splitting.ι_desc, comp_id, Splitting.ι_desc_assoc, + simp only [← Splitting.cofan_inj_id, Splitting.ι_desc, comp_id, Splitting.ι_desc_assoc, assoc, PInfty_f_idem_assoc] } naturality {X Y} f := by ext1 apply (Γ₀.splitting K[X]).hom_ext intro n dsimp [N₁, toKaroubi] - simp only [← Splitting.ιSummand_id, Splitting.ι_desc, Splitting.ι_desc_assoc, assoc, + simp only [← Splitting.cofan_inj_id, Splitting.ι_desc, Splitting.ι_desc_assoc, assoc, PInfty_f_idem_assoc, Karoubi.comp_f, NatTrans.comp_app, Γ₂_map_f_app, HomologicalComplex.comp_f, AlternatingFaceMapComplex.map_f, PInfty_f_naturality_assoc, NatTrans.naturality, Splitting.IndexSet.id_fst, unop_op, len_mk] @@ -230,9 +230,9 @@ theorem identity_N₂_objectwise (P : Karoubi (SimplicialObject C)) : N₂.map (Γ₂N₂.natTrans.app P) = 𝟙 (N₂.obj P) := by ext n have eq₁ : (N₂Γ₂.inv.app (N₂.obj P)).f.f n = PInfty.f n ≫ P.p.app (op [n]) ≫ - (Γ₀.splitting (N₂.obj P).X).ιSummand (Splitting.IndexSet.id (op [n])) := by + ((Γ₀.splitting (N₂.obj P).X).cofan _).inj (Splitting.IndexSet.id (op [n])) := by simp only [N₂Γ₂_inv_app_f_f, N₂_obj_p_f, assoc] - have eq₂ : (Γ₀.splitting (N₂.obj P).X).ιSummand (Splitting.IndexSet.id (op [n])) ≫ + have eq₂ : ((Γ₀.splitting (N₂.obj P).X).cofan _).inj (Splitting.IndexSet.id (op [n])) ≫ (N₂.map (Γ₂N₂.natTrans.app P)).f.f n = PInfty.f n ≫ P.p.app (op [n]) := by dsimp rw [PInfty_on_Γ₀_splitting_summand_eq_self_assoc, Γ₂N₂.natTrans_app_f_app] diff --git a/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean b/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean index f835fe6d7a082..b4d443a48ca2f 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean @@ -30,48 +30,43 @@ namespace SimplicialObject namespace Splitting -variable {C : Type*} [Category C] [HasFiniteCoproducts C] {X : SimplicialObject C} +variable {C : Type*} [Category C] {X : SimplicialObject C} (s : Splitting X) /-- The projection on a summand of the coproduct decomposition given by a splitting of a simplicial object. -/ noncomputable def πSummand [HasZeroMorphisms C] {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : - X.obj Δ ⟶ s.N A.1.unop.len := by - refine' (s.iso Δ).inv ≫ Sigma.desc fun B => _ - by_cases h : B = A - · exact eqToHom (by subst h; rfl) - · exact 0 + X.obj Δ ⟶ s.N A.1.unop.len := + s.desc Δ (fun B => by + by_cases h : B = A + · exact eqToHom (by subst h; rfl) + · exact 0) #align simplicial_object.splitting.π_summand SimplicialObject.Splitting.πSummand @[reassoc (attr := simp)] -theorem ι_πSummand_eq_id [HasZeroMorphisms C] {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : - s.ιSummand A ≫ s.πSummand A = 𝟙 _ := by - dsimp only [ιSummand, iso_hom, πSummand, iso_inv, summand] - simp only [summand, assoc, IsIso.hom_inv_id_assoc] - erw [colimit.ι_desc, Cofan.mk_ι_app] - dsimp - simp only [dite_eq_ite, ite_true] -#align simplicial_object.splitting.ι_π_summand_eq_id SimplicialObject.Splitting.ι_πSummand_eq_id +theorem cofan_inj_πSummand_eq_id [HasZeroMorphisms C] {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : + (s.cofan Δ).inj A ≫ s.πSummand A = 𝟙 _ := by + simp [πSummand] +#align simplicial_object.splitting.ι_π_summand_eq_id SimplicialObject.Splitting.cofan_inj_πSummand_eq_id @[reassoc (attr := simp)] -theorem ι_πSummand_eq_zero [HasZeroMorphisms C] {Δ : SimplexCategoryᵒᵖ} (A B : IndexSet Δ) - (h : B ≠ A) : s.ιSummand A ≫ s.πSummand B = 0 := by - dsimp only [ιSummand, iso_hom, πSummand, iso_inv, summand] - simp only [summand, assoc, IsIso.hom_inv_id_assoc] - erw [colimit.ι_desc, Cofan.mk_ι_app] - exact dif_neg h.symm -#align simplicial_object.splitting.ι_π_summand_eq_zero SimplicialObject.Splitting.ι_πSummand_eq_zero +theorem cofan_inj_πSummand_eq_zero [HasZeroMorphisms C] {Δ : SimplexCategoryᵒᵖ} (A B : IndexSet Δ) + (h : B ≠ A) : (s.cofan Δ).inj A ≫ s.πSummand B = 0 := by + dsimp [πSummand] + rw [ι_desc, dif_neg h.symm] +#align simplicial_object.splitting.ι_π_summand_eq_zero SimplicialObject.Splitting.cofan_inj_πSummand_eq_zero variable [Preadditive C] theorem decomposition_id (Δ : SimplexCategoryᵒᵖ) : - 𝟙 (X.obj Δ) = ∑ A : IndexSet Δ, s.πSummand A ≫ s.ιSummand A := by + 𝟙 (X.obj Δ) = ∑ A : IndexSet Δ, s.πSummand A ≫ (s.cofan Δ).inj A := by apply s.hom_ext' intro A - rw [comp_id, comp_sum, Finset.sum_eq_single A, ι_πSummand_eq_id_assoc] + dsimp + erw [comp_id, comp_sum, Finset.sum_eq_single A, cofan_inj_πSummand_eq_id_assoc] · intro B _ h₂ - rw [s.ι_πSummand_eq_zero_assoc _ _ h₂, zero_comp] - · simp only [Finset.mem_univ, not_true, IsEmpty.forall_iff] + rw [s.cofan_inj_πSummand_eq_zero_assoc _ _ h₂, zero_comp] + · simp #align simplicial_object.splitting.decomposition_id SimplicialObject.Splitting.decomposition_id @[reassoc (attr := simp)] @@ -80,7 +75,8 @@ theorem σ_comp_πSummand_id_eq_zero {n : ℕ} (i : Fin (n + 1)) : apply s.hom_ext' intro A dsimp only [SimplicialObject.σ] - rw [comp_zero, s.ιSummand_epi_naturality_assoc A (SimplexCategory.σ i).op, ι_πSummand_eq_zero] + rw [comp_zero, s.cofan_inj_epi_naturality_assoc A (SimplexCategory.σ i).op, + cofan_inj_πSummand_eq_zero] rw [ne_comm] change ¬(A.epiComp (SimplexCategory.σ i).op).EqId rw [IndexSet.eqId_iff_len_eq] @@ -92,13 +88,13 @@ theorem σ_comp_πSummand_id_eq_zero {n : ℕ} (i : Fin (n + 1)) : /-- If a simplicial object `X` in an additive category is split, then `PInfty` vanishes on all the summands of `X _[n]` which do not correspond to the identity of `[n]`. -/ -theorem ιSummand_comp_PInfty_eq_zero {X : SimplicialObject C} (s : SimplicialObject.Splitting X) +theorem cofan_inj_comp_PInfty_eq_zero {X : SimplicialObject C} (s : SimplicialObject.Splitting X) {n : ℕ} (A : SimplicialObject.Splitting.IndexSet (op [n])) (hA : ¬A.EqId) : - s.ιSummand A ≫ PInfty.f n = 0 := by + (s.cofan _).inj A ≫ PInfty.f n = 0 := by rw [SimplicialObject.Splitting.IndexSet.eqId_iff_mono] at hA - rw [SimplicialObject.Splitting.ιSummand_eq, assoc, degeneracy_comp_PInfty X n A.e hA, comp_zero] + rw [SimplicialObject.Splitting.cofan_inj_eq, assoc, degeneracy_comp_PInfty X n A.e hA, comp_zero] set_option linter.uppercaseLean3 false in -#align simplicial_object.splitting.ι_summand_comp_P_infty_eq_zero SimplicialObject.Splitting.ιSummand_comp_PInfty_eq_zero +#align simplicial_object.splitting.ι_summand_comp_P_infty_eq_zero SimplicialObject.Splitting.cofan_inj_comp_PInfty_eq_zero theorem comp_PInfty_eq_zero_iff {Z : C} {n : ℕ} (f : Z ⟶ X _[n]) : f ≫ PInfty.f n = 0 ↔ f ≫ s.πSummand (IndexSet.id (op [n])) = 0 := by @@ -123,7 +119,7 @@ theorem comp_PInfty_eq_zero_iff {Z : C} {n : ℕ} (f : Z ⟶ X _[n]) : · dsimp at hA subst hA rw [assoc, reassoc_of% h, zero_comp] - · simp only [assoc, s.ιSummand_comp_PInfty_eq_zero A hA, comp_zero] + · simp only [assoc, s.cofan_inj_comp_PInfty_eq_zero A hA, comp_zero] set_option linter.uppercaseLean3 false in #align simplicial_object.splitting.comp_P_infty_eq_zero_iff SimplicialObject.Splitting.comp_PInfty_eq_zero_iff @@ -138,28 +134,28 @@ set_option linter.uppercaseLean3 false in #align simplicial_object.splitting.P_infty_comp_π_summand_id SimplicialObject.Splitting.PInfty_comp_πSummand_id @[reassoc (attr := simp)] -theorem πSummand_comp_ιSummand_comp_PInfty_eq_PInfty (n : ℕ) : - s.πSummand (IndexSet.id (op [n])) ≫ s.ιSummand (IndexSet.id (op [n])) ≫ PInfty.f n = +theorem πSummand_comp_cofan_inj_id_comp_PInfty_eq_PInfty (n : ℕ) : + s.πSummand (IndexSet.id (op [n])) ≫ (s.cofan _).inj (IndexSet.id (op [n])) ≫ PInfty.f n = PInfty.f n := by conv_rhs => rw [← id_comp (PInfty.f n)] erw [s.decomposition_id, Preadditive.sum_comp] rw [Fintype.sum_eq_single (IndexSet.id (op [n])), assoc] rintro A (hA : ¬A.EqId) - rw [assoc, s.ιSummand_comp_PInfty_eq_zero A hA, comp_zero] + rw [assoc, s.cofan_inj_comp_PInfty_eq_zero A hA, comp_zero] set_option linter.uppercaseLean3 false in -#align simplicial_object.splitting.π_summand_comp_ι_summand_comp_P_infty_eq_P_infty SimplicialObject.Splitting.πSummand_comp_ιSummand_comp_PInfty_eq_PInfty +#align simplicial_object.splitting.π_summand_comp_ι_summand_comp_P_infty_eq_P_infty SimplicialObject.Splitting.πSummand_comp_cofan_inj_id_comp_PInfty_eq_PInfty /-- The differentials `s.d i j : s.N i ⟶ s.N j` on nondegenerate simplices of a split simplicial object are induced by the differentials on the alternating face map complex. -/ @[simp] noncomputable def d (i j : ℕ) : s.N i ⟶ s.N j := - s.ιSummand (IndexSet.id (op [i])) ≫ K[X].d i j ≫ s.πSummand (IndexSet.id (op [j])) + (s.cofan _).inj (IndexSet.id (op [i])) ≫ K[X].d i j ≫ s.πSummand (IndexSet.id (op [j])) #align simplicial_object.splitting.d SimplicialObject.Splitting.d theorem ιSummand_comp_d_comp_πSummand_eq_zero (j k : ℕ) (A : IndexSet (op [j])) (hA : ¬A.EqId) : - s.ιSummand A ≫ K[X].d j k ≫ s.πSummand (IndexSet.id (op [k])) = 0 := by + (s.cofan _).inj A ≫ K[X].d j k ≫ s.πSummand (IndexSet.id (op [k])) = 0 := by rw [A.eqId_iff_mono] at hA - rw [← assoc, ← s.comp_PInfty_eq_zero_iff, assoc, ← PInfty.comm j k, s.ιSummand_eq, assoc, + rw [← assoc, ← s.comp_PInfty_eq_zero_iff, assoc, ← PInfty.comm j k, s.cofan_inj_eq, assoc, degeneracy_comp_PInfty_assoc X j A.e hA, zero_comp, comp_zero] #align simplicial_object.splitting.ι_summand_comp_d_comp_π_summand_eq_zero SimplicialObject.Splitting.ιSummand_comp_d_comp_πSummand_eq_zero @@ -195,10 +191,10 @@ noncomputable def toKaroubiNondegComplexIsoN₁ : (toKaroubi _).obj s.nondegComplex ≅ N₁.obj X where hom := { f := - { f := fun n => s.ιSummand (IndexSet.id (op [n])) ≫ PInfty.f n + { f := fun n => (s.cofan _).inj (IndexSet.id (op [n])) ≫ PInfty.f n comm' := fun i j _ => by dsimp - rw [assoc, assoc, assoc, πSummand_comp_ιSummand_comp_PInfty_eq_PInfty, + rw [assoc, assoc, assoc, πSummand_comp_cofan_inj_id_comp_PInfty_eq_PInfty, HomologicalComplex.Hom.comm] } comm := by ext n @@ -222,11 +218,11 @@ noncomputable def toKaroubiNondegComplexIsoN₁ : hom_inv_id := by ext n simp only [assoc, PInfty_comp_πSummand_id, Karoubi.comp_f, HomologicalComplex.comp_f, - ι_πSummand_eq_id] + cofan_inj_πSummand_eq_id] rfl inv_hom_id := by ext n - simp only [πSummand_comp_ιSummand_comp_PInfty_eq_PInfty, Karoubi.comp_f, + simp only [πSummand_comp_cofan_inj_id_comp_PInfty_eq_PInfty, Karoubi.comp_f, HomologicalComplex.comp_f, N₁_obj_p, Karoubi.id_eq] set_option linter.uppercaseLean3 false in #align simplicial_object.splitting.to_karoubi_nondeg_complex_iso_N₁ SimplicialObject.Splitting.toKaroubiNondegComplexIsoN₁ @@ -246,24 +242,22 @@ noncomputable def nondegComplexFunctor : Split C ⥤ ChainComplex C ℕ where { f := Φ.f comm' := fun i j _ => by dsimp - erw [← ιSummand_naturality_symm_assoc Φ (Splitting.IndexSet.id (op [i])), + erw [← cofan_inj_naturality_symm_assoc Φ (Splitting.IndexSet.id (op [i])), ((alternatingFaceMapComplex C).map Φ.F).comm_assoc i j] simp only [assoc] congr 2 apply S₁.s.hom_ext' intro A dsimp [alternatingFaceMapComplex] - erw [ιSummand_naturality_symm_assoc Φ A] + erw [cofan_inj_naturality_symm_assoc Φ A] by_cases h : A.EqId · dsimp at h subst h - simp only [Splitting.ι_πSummand_eq_id, comp_id, Splitting.ι_πSummand_eq_id_assoc] - rfl - · have h' : Splitting.IndexSet.id (op [j]) ≠ A := by - rw [ne_comm] - exact h - rw [S₁.s.ι_πSummand_eq_zero_assoc _ _ h', S₂.s.ι_πSummand_eq_zero _ _ h', zero_comp, - comp_zero] } + rw [Splitting.cofan_inj_πSummand_eq_id] + dsimp + rw [comp_id, Splitting.cofan_inj_πSummand_eq_id_assoc] + · rw [S₁.s.cofan_inj_πSummand_eq_zero_assoc _ _ (Ne.symm h), + S₂.s.cofan_inj_πSummand_eq_zero _ _ (Ne.symm h), zero_comp, comp_zero] } #align simplicial_object.split.nondeg_complex_functor SimplicialObject.Split.nondegComplexFunctor /-- The natural isomorphism (in `Karoubi (ChainComplex C ℕ)`) between the chain complex @@ -278,7 +272,7 @@ noncomputable def toKaroubiNondegComplexFunctorIsoN₁ : simp only [Karoubi.comp_f, toKaroubi_map_f, HomologicalComplex.comp_f, nondegComplexFunctor_map_f, Splitting.toKaroubiNondegComplexIsoN₁_hom_f_f, N₁_map_f, AlternatingFaceMapComplex.map_f, assoc, PInfty_f_idem_assoc] - erw [← Split.ιSummand_naturality_symm_assoc Φ (Splitting.IndexSet.id (op [n]))] + erw [← Split.cofan_inj_naturality_symm_assoc Φ (Splitting.IndexSet.id (op [n]))] rw [PInfty_f_naturality] set_option linter.uppercaseLean3 false in #align simplicial_object.split.to_karoubi_nondeg_complex_functor_iso_N₁ SimplicialObject.Split.toKaroubiNondegComplexFunctorIsoN₁ diff --git a/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean b/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean index 52939154bd404..69bafbf60a98b 100644 --- a/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean @@ -208,84 +208,47 @@ def summand (A : IndexSet Δ) : C := N A.1.unop.len #align simplicial_object.splitting.summand SimplicialObject.Splitting.summand -variable [HasFiniteCoproducts C] - -/-- The coproduct of the family `summand N Δ` -/ -abbrev coprod := ∐ summand N Δ -#align simplicial_object.splitting.coprod SimplicialObject.Splitting.coprod - -variable {Δ} - -/-- The inclusion of a summand in the coproduct. -/ -@[simp] -def ιCoprod (A : IndexSet Δ) : N A.1.unop.len ⟶ coprod N Δ := - Sigma.ι (summand N Δ) A -#align simplicial_object.splitting.ι_coprod SimplicialObject.Splitting.ιCoprod - -variable {N} - -/-- The canonical morphism `coprod N Δ ⟶ X.obj Δ` attached to a sequence -of objects `N` and a sequence of morphisms `N n ⟶ X _[n]`. -/ -@[simp] -def map (Δ : SimplexCategoryᵒᵖ) : coprod N Δ ⟶ X.obj Δ := - Sigma.desc fun A => φ A.1.unop.len ≫ X.map A.e.op -#align simplicial_object.splitting.map SimplicialObject.Splitting.map +/-- The cofan for `summand N Δ` induced by morphisms `N n ⟶ X_ [n]` for all `n : ℕ`. -/ +def cofan' (Δ : SimplexCategoryᵒᵖ) : Cofan (summand N Δ) := + Cofan.mk (X.obj Δ) (fun A => φ A.1.unop.len ≫ X.map A.e.op) end Splitting -variable [HasFiniteCoproducts C] - --porting note: removed @[nolint has_nonempty_instance] /-- A splitting of a simplicial object `X` consists of the datum of a sequence of objects `N`, a sequence of morphisms `ι : N n ⟶ X _[n]` such that for all `Δ : SimplexCategoryᵒᵖ`, the canonical map `Splitting.map X ι Δ` is an isomorphism. -/ structure Splitting (X : SimplicialObject C) where + /-- The "nondegenerate simplices" `N n` for all `n : ℕ`. -/ N : ℕ → C + /-- The "inclusion" `N n ⟶ X _[n]` for all `n : ℕ`. -/ ι : ∀ n, N n ⟶ X _[n] - map_isIso : ∀ Δ : SimplexCategoryᵒᵖ, IsIso (Splitting.map X ι Δ) + /-- For each `Δ`, `X.obj Δ` identifies to the coproduct of the objects `N A.1.unop.len` + for all `A : IndexSet Δ`. -/ + isColimit' : ∀ Δ : SimplexCategoryᵒᵖ, IsColimit (Splitting.cofan' N X ι Δ) #align simplicial_object.splitting SimplicialObject.Splitting namespace Splitting variable {X Y : SimplicialObject C} (s : Splitting X) -attribute [instance] Splitting.map_isIso -#align simplicial_object.splitting.map_is_iso SimplicialObject.Splitting.map_isIso +/-- The cofan for `summand s.N Δ` induced by a splitting of a simplicial object. -/ +def cofan (Δ : SimplexCategoryᵒᵖ) : Cofan (summand s.N Δ) := + Cofan.mk (X.obj Δ) (fun A => s.ι A.1.unop.len ≫ X.map A.e.op) --- Porting note: --- This used to be `@[simps]`, but now `Splitting.map` is unfolded in the generated lemmas. Why? --- Instead we write these lemmas by hand. -/-- The isomorphism on simplices given by the axiom `Splitting.map_isIso` -/ -def iso (Δ : SimplexCategoryᵒᵖ) : coprod s.N Δ ≅ X.obj Δ := - asIso (Splitting.map X s.ι Δ) -#align simplicial_object.splitting.iso SimplicialObject.Splitting.iso - -@[simp] -theorem iso_hom (Δ : SimplexCategoryᵒᵖ) : (iso s Δ).hom = Splitting.map X s.ι Δ := - rfl - -@[simp] -theorem iso_inv (Δ : SimplexCategoryᵒᵖ) : (iso s Δ).inv = inv (Splitting.map X s.ι Δ) := - rfl - -/-- Via the isomorphism `s.iso Δ`, this is the inclusion of a summand -in the direct sum decomposition given by the splitting `s : Splitting X`. -/ -def ιSummand {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : s.N A.1.unop.len ⟶ X.obj Δ := - Splitting.ιCoprod s.N A ≫ (s.iso Δ).hom -#align simplicial_object.splitting.ι_summand SimplicialObject.Splitting.ιSummand +/-- The cofan `s.cofan Δ` is colimit. -/ +def isColimit (Δ : SimplexCategoryᵒᵖ) : IsColimit (s.cofan Δ) := s.isColimit' Δ @[reassoc] -theorem ιSummand_eq {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : - s.ιSummand A = s.ι A.1.unop.len ≫ X.map A.e.op := by - dsimp only [ιSummand, Iso.hom] - erw [colimit.ι_desc, Cofan.mk_ι_app] -#align simplicial_object.splitting.ι_summand_eq SimplicialObject.Splitting.ιSummand_eq - -theorem ιSummand_id (n : ℕ) : s.ιSummand (IndexSet.id (op [n])) = s.ι n := by - erw [ιSummand_eq, X.map_id, comp_id] +theorem cofan_inj_eq {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : + (s.cofan Δ).inj A = s.ι A.1.unop.len ≫ X.map A.e.op := rfl +#align simplicial_object.splitting.ι_summand_eq SimplicialObject.Splitting.cofan_inj_eq + +theorem cofan_inj_id (n : ℕ) : (s.cofan _).inj (IndexSet.id (op [n])) = s.ι n := by + erw [cofan_inj_eq, X.map_id, comp_id] rfl -#align simplicial_object.splitting.ι_summand_id SimplicialObject.Splitting.ιSummand_id +#align simplicial_object.splitting.ι_summand_id SimplicialObject.Splitting.cofan_inj_id /-- As it is stated in `Splitting.hom_ext`, a morphism `f : X ⟶ Y` from a split simplicial object to any simplicial object is determined by its restrictions @@ -296,17 +259,15 @@ def φ (f : X ⟶ Y) (n : ℕ) : s.N n ⟶ Y _[n] := #align simplicial_object.splitting.φ SimplicialObject.Splitting.φ @[reassoc (attr := simp)] -theorem ιSummand_comp_app (f : X ⟶ Y) {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : - s.ιSummand A ≫ f.app Δ = s.φ f A.1.unop.len ≫ Y.map A.e.op := by - simp only [ιSummand_eq_assoc, φ, assoc] +theorem cofan_inj_comp_app (f : X ⟶ Y) {Δ : SimplexCategoryᵒᵖ} (A : IndexSet Δ) : + (s.cofan Δ).inj A ≫ f.app Δ = s.φ f A.1.unop.len ≫ Y.map A.e.op := by + simp only [cofan_inj_eq_assoc, φ, assoc] erw [NatTrans.naturality] -#align simplicial_object.splitting.ι_summand_comp_app SimplicialObject.Splitting.ιSummand_comp_app +#align simplicial_object.splitting.ι_summand_comp_app SimplicialObject.Splitting.cofan_inj_comp_app theorem hom_ext' {Z : C} {Δ : SimplexCategoryᵒᵖ} (f g : X.obj Δ ⟶ Z) - (h : ∀ A : IndexSet Δ, s.ιSummand A ≫ f = s.ιSummand A ≫ g) : f = g := by - rw [← cancel_epi (s.iso Δ).hom] - ext A - simpa only [ιSummand_eq, iso_hom, map, colimit.ι_desc_assoc, Cofan.mk_ι_app] using h A + (h : ∀ A : IndexSet Δ, (s.cofan Δ).inj A ≫ f = (s.cofan Δ).inj A ≫ g) : f = g := + Cofan.IsColimit.hom_ext (s.isColimit Δ) _ _ h #align simplicial_object.splitting.hom_ext' SimplicialObject.Splitting.hom_ext' theorem hom_ext (f g : X ⟶ Y) (h : ∀ n : ℕ, s.φ f n = s.φ g n) : f = g := by @@ -316,22 +277,20 @@ theorem hom_ext (f g : X ⟶ Y) (h : ∀ n : ℕ, s.φ f n = s.φ g n) : f = g : induction' Δ using Opposite.rec with Δ induction' Δ using SimplexCategory.rec with n dsimp - simp only [s.ιSummand_comp_app, h] + simp only [s.cofan_inj_comp_app, h] #align simplicial_object.splitting.hom_ext SimplicialObject.Splitting.hom_ext /-- The map `X.obj Δ ⟶ Z` obtained by providing a family of morphisms on all the terms of decomposition given by a splitting `s : Splitting X` -/ def desc {Z : C} (Δ : SimplexCategoryᵒᵖ) (F : ∀ A : IndexSet Δ, s.N A.1.unop.len ⟶ Z) : X.obj Δ ⟶ Z := - (s.iso Δ).inv ≫ Sigma.desc F + Cofan.IsColimit.desc (s.isColimit Δ) F #align simplicial_object.splitting.desc SimplicialObject.Splitting.desc @[reassoc (attr := simp)] theorem ι_desc {Z : C} (Δ : SimplexCategoryᵒᵖ) (F : ∀ A : IndexSet Δ, s.N A.1.unop.len ⟶ Z) - (A : IndexSet Δ) : s.ιSummand A ≫ s.desc Δ F = F A := by - dsimp only [ιSummand, desc] - simp only [assoc, Iso.hom_inv_id_assoc, ιCoprod] - erw [colimit.ι_desc, Cofan.mk_ι_app] + (A : IndexSet Δ) : (s.cofan Δ).inj A ≫ s.desc Δ F = F A := by + apply Cofan.IsColimit.fac #align simplicial_object.splitting.ι_desc SimplicialObject.Splitting.ι_desc /-- A simplicial object that is isomorphic to a split simplicial object is split. -/ @@ -339,20 +298,17 @@ theorem ι_desc {Z : C} (Δ : SimplexCategoryᵒᵖ) (F : ∀ A : IndexSet Δ, s def ofIso (e : X ≅ Y) : Splitting Y where N := s.N ι n := s.ι n ≫ e.hom.app (op [n]) - map_isIso Δ := by - convert (inferInstance : IsIso ((s.iso Δ).hom ≫ e.hom.app Δ)) - ext - simp [map] + isColimit' Δ := IsColimit.ofIsoColimit (s.isColimit Δ ) (Cofan.ext (e.app Δ) + (fun A => by simp [cofan, cofan'])) #align simplicial_object.splitting.of_iso SimplicialObject.Splitting.ofIso @[reassoc] -theorem ιSummand_epi_naturality {Δ₁ Δ₂ : SimplexCategoryᵒᵖ} (A : IndexSet Δ₁) (p : Δ₁ ⟶ Δ₂) - [Epi p.unop] : s.ιSummand A ≫ X.map p = s.ιSummand (A.epiComp p) := by - dsimp [ιSummand] - erw [colimit.ι_desc, colimit.ι_desc, Cofan.mk_ι_app, Cofan.mk_ι_app] - dsimp only [IndexSet.epiComp, IndexSet.e] - rw [op_comp, X.map_comp, assoc, Quiver.Hom.op_unop] -#align simplicial_object.splitting.ι_summand_epi_naturality SimplicialObject.Splitting.ιSummand_epi_naturality +theorem cofan_inj_epi_naturality {Δ₁ Δ₂ : SimplexCategoryᵒᵖ} (A : IndexSet Δ₁) (p : Δ₁ ⟶ Δ₂) + [Epi p.unop] : (s.cofan Δ₁).inj A ≫ X.map p = (s.cofan Δ₂).inj (A.epiComp p) := by + dsimp [cofan] + rw [assoc, ← X.map_comp] + rfl +#align simplicial_object.splitting.ι_summand_epi_naturality SimplicialObject.Splitting.cofan_inj_epi_naturality end Splitting @@ -364,7 +320,9 @@ in `C` equipped with a splitting, and morphisms are morphisms of simplicial obje which are compatible with the splittings. -/ @[ext] structure Split where + /-- the underlying simplicial object -/ X : SimplicialObject C + /-- a splitting of the simplicial object -/ s : Splitting X #align simplicial_object.split SimplicialObject.Split @@ -383,7 +341,9 @@ def mk' {X : SimplicialObject C} (s : Splitting X) : Split C := /-- Morphisms in `SimplicialObject.Split C` are morphisms of simplicial objects that are compatible with the splittings. -/ structure Hom (S₁ S₂ : Split C) where + /-- the morphism between the underlying simplical objects -/ F : S₁.X ⟶ S₂.X + /-- the morphism between the "nondegenerate" `n`-simplices for all `n : ℕ` -/ f : ∀ n : ℕ, S₁.s.N n ⟶ S₂.s.N n comm : ∀ n : ℕ, S₁.s.ι n ≫ F.app (op [n]) = f n ≫ S₂.s.ι n := by aesop_cat #align simplicial_object.split.hom SimplicialObject.Split.Hom @@ -461,11 +421,11 @@ theorem comp_f {S₁ S₂ S₃ : Split C} (Φ₁₂ : S₁ ⟶ S₂) (Φ₂₃ : #align simplicial_object.split.comp_f SimplicialObject.Split.comp_f @[reassoc (attr := simp 1100)] -theorem ιSummand_naturality_symm {S₁ S₂ : Split C} (Φ : S₁ ⟶ S₂) {Δ : SimplexCategoryᵒᵖ} +theorem cofan_inj_naturality_symm {S₁ S₂ : Split C} (Φ : S₁ ⟶ S₂) {Δ : SimplexCategoryᵒᵖ} (A : Splitting.IndexSet Δ) : - S₁.s.ιSummand A ≫ Φ.F.app Δ = Φ.f A.1.unop.len ≫ S₂.s.ιSummand A := by - erw [S₁.s.ιSummand_eq, S₂.s.ιSummand_eq, assoc, Φ.F.naturality, ← Φ.comm_assoc ] -#align simplicial_object.split.ι_summand_naturality_symm SimplicialObject.Split.ιSummand_naturality_symm + (S₁.s.cofan Δ).inj A ≫ Φ.F.app Δ = Φ.f A.1.unop.len ≫ (S₂.s.cofan Δ).inj A := by + erw [S₁.s.cofan_inj_eq, S₂.s.cofan_inj_eq, assoc, Φ.F.naturality, ← Φ.comm_assoc] +#align simplicial_object.split.ι_summand_naturality_symm SimplicialObject.Split.cofan_inj_naturality_symm variable (C) @@ -490,11 +450,11 @@ set_option linter.uppercaseLean3 false in in split simplicial objects is a natural transformation of functors `SimplicialObject.Split C ⥤ C` -/ @[simps] -def natTransιSummand {Δ : SimplexCategoryᵒᵖ} (A : Splitting.IndexSet Δ) : +def natTransCofanInj {Δ : SimplexCategoryᵒᵖ} (A : Splitting.IndexSet Δ) : evalN C A.1.unop.len ⟶ forget C ⋙ (evaluation SimplexCategoryᵒᵖ C).obj Δ where - app S := S.s.ιSummand A - naturality _ _ Φ := (ιSummand_naturality_symm Φ A).symm -#align simplicial_object.split.nat_trans_ι_summand SimplicialObject.Split.natTransιSummand + app S := (S.s.cofan Δ).inj A + naturality _ _ Φ := (cofan_inj_naturality_symm Φ A).symm +#align simplicial_object.split.nat_trans_ι_summand SimplicialObject.Split.natTransCofanInj end Split From c9e4122d0673e89cb8c676b5ba23224e7ac279f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 05:26:39 +0000 Subject: [PATCH 224/353] feat(CategoryTheory/Sites): objects which cover the terminal object (#8632) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR, given a site `(C, J)`, we introduce the notion of a family of objects `Y : I → C` which "cover the final object". This notion is used in order to formulate results about global sections of sheaves. It shall also be useful in future PRs in order to formulate descent properties of sheaves. --- Mathlib.lean | 1 + Mathlib/CategoryTheory/Sites/CoversTop.lean | 163 ++++++++++++++++++ .../Sites/EqualizerSheafCondition.lean | 4 +- Mathlib/CategoryTheory/Sites/Sieves.lean | 54 ++++++ 4 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 Mathlib/CategoryTheory/Sites/CoversTop.lean diff --git a/Mathlib.lean b/Mathlib.lean index 0637c7e2ee013..bfffbaf6cbc12 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1256,6 +1256,7 @@ import Mathlib.CategoryTheory.Sites.ConstantSheaf import Mathlib.CategoryTheory.Sites.CoverLifting import Mathlib.CategoryTheory.Sites.CoverPreserving import Mathlib.CategoryTheory.Sites.Coverage +import Mathlib.CategoryTheory.Sites.CoversTop import Mathlib.CategoryTheory.Sites.DenseSubsite import Mathlib.CategoryTheory.Sites.EffectiveEpimorphic import Mathlib.CategoryTheory.Sites.EqualizerSheafCondition diff --git a/Mathlib/CategoryTheory/Sites/CoversTop.lean b/Mathlib/CategoryTheory/Sites/CoversTop.lean new file mode 100644 index 0000000000000..13850c722e9b9 --- /dev/null +++ b/Mathlib/CategoryTheory/Sites/CoversTop.lean @@ -0,0 +1,163 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.CategoryTheory.Sites.Sheaf + +/-! Objects which cover the terminal object + +In this file, given a site `(C, J)`, we introduce the notion of a family +of objects `Y : I → C` which "cover the final object": this means +that for all `X : C`, the sieve `Sieve.ofObjects Y X` is covering for `J`. +When there is a terminal object `X : C`, then `J.CoversTop Y` +holds iff `Sieve.ofObjects Y X` is covering for `J`. + +We introduce a notion of compatible family of elements on objects `Y` +and obtain `Presheaf.FamilyOfElementsOnObjects.IsCompatible.exists_unique_section` +which asserts that if a presheaf of types is a sheaf, then any compatible +family of elements on objects `Y` which cover the final object extends as +a section of this presheaf. + +-/ + +universe w v' v u' u + +namespace CategoryTheory + +open Limits + +variable {C : Type u} [Category.{v} C] (J : GrothendieckTopology C) + {A : Type u'} [Category.{v'} A] + +namespace GrothendieckTopology + +/-- A family of objects `Y : I → C` "covers the final object" +if for all `X : C`, the sieve `ofObjects Y X` is a covering sieve. -/ +def CoversTop {I : Type*} (Y : I → C) : Prop := + ∀ (X : C), Sieve.ofObjects Y X ∈ J X + +lemma coversTop_iff_of_isTerminal (X : C) (hX : IsTerminal X) + {I : Type*} (Y : I → C) : + J.CoversTop Y ↔ Sieve.ofObjects Y X ∈ J X := by + constructor + · tauto + · intro h W + apply J.superset_covering _ (J.pullback_stable (hX.from W) h) + rintro T a ⟨i, ⟨b⟩⟩ + exact ⟨i, ⟨b⟩⟩ + +namespace CoversTop + +variable {J} +variable {I : Type*} {Y : I → C} (hY : J.CoversTop Y) + +/-- The cover of any object `W : C` attached to a family of objects `Y` that satisfy +`J.CoversTop Y` -/ +abbrev cover (W : C) : Cover J W := ⟨Sieve.ofObjects Y W, hY W⟩ + +lemma ext (F : Sheaf J A) {c : Cone F.1} (hc : IsLimit c) {X : A} {f g : X ⟶ c.pt} + (h : ∀ (i : I), f ≫ c.π.app (Opposite.op (Y i)) = + g ≫ c.π.app (Opposite.op (Y i))) : + f = g := by + refine' hc.hom_ext (fun Z => F.2.hom_ext (hY.cover Z.unop) _ _ _) + rintro ⟨W, a, ⟨i, ⟨b⟩⟩⟩ + simpa using h i =≫ F.1.map b.op + +lemma sections_ext (F : Sheaf J (Type _)) {x y : F.1.sections} + (h : ∀ (i : I), x.1 (Opposite.op (Y i)) = y.1 (Opposite.op (Y i))) : + x = y := by + ext W + apply (Presieve.isSeparated_of_isSheaf J F.1 + ((isSheaf_iff_isSheaf_of_type _ _).1 F.2) _ (hY W.unop)).ext + rintro T a ⟨i, ⟨b⟩⟩ + simpa using congr_arg (F.1.map b.op) (h i) + +end CoversTop + +end GrothendieckTopology + +namespace Presheaf + +variable (F : Cᵒᵖ ⥤ Type w) {I : Type*} (Y : I → C) + +/-- A family of elements of a presheaf of types `F` indexed by a family of objects +`Y : I → C` consists of the data of an element in `F.obj (Opposite.op (Y i))` for all `i`. -/ +def FamilyOfElementsOnObjects := ∀ (i : I), F.obj (Opposite.op (Y i)) + +namespace FamilyOfElementsOnObjects + +variable {F Y} (x : FamilyOfElementsOnObjects F Y) + +/-- `x : FamilyOfElementsOnObjects F Y` is compatible if for any object `Z` such that +there exists a morphism `f : Z → Y i`, then the pullback of `x i` by `f` is independent +of `f` and `i`. -/ +def IsCompatible (x : FamilyOfElementsOnObjects F Y) : Prop := + ∀ (Z : C) (i j : I) (f : Z ⟶ Y i) (g : Z ⟶ Y j), + F.map f.op (x i) = F.map g.op (x j) + +/-- A family of elements indexed by `Sieve.ofObjects Y X` that is induced by +`x : FamilyOfElementsOnObjects F Y`. See the equational lemma +`IsCompatible.familyOfElements_apply` which holds under the assumption `x.IsCompatible`. -/ +noncomputable def familyOfElements (X : C) : + Presieve.FamilyOfElements F (Sieve.ofObjects Y X).arrows := + fun _ _ hf => F.map hf.choose_spec.some.op (x _) + +namespace IsCompatible + +variable {x} (hx : x.IsCompatible) + +lemma familyOfElements_apply {X Z : C} (f : Z ⟶ X) (i : I) (φ : Z ⟶ Y i) : + familyOfElements x X f ⟨i, ⟨φ⟩⟩ = F.map φ.op (x i) := by + apply hx + +lemma familyOfElements_isCompatible (X : C) : + (familyOfElements x X).Compatible := by + intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ ⟨i₁, ⟨φ₁⟩⟩ ⟨i₂, ⟨φ₂⟩⟩ _ + simpa [hx.familyOfElements_apply f₁ i₁ φ₁, + hx.familyOfElements_apply f₂ i₂ φ₂] using hx Z i₁ i₂ (g₁ ≫ φ₁) (g₂ ≫ φ₂) + +variable {J} +variable (hY : J.CoversTop Y) (hF : IsSheaf J F) + +lemma exists_unique_section : + ∃! (s : F.sections), ∀ (i : I), s.1 (Opposite.op (Y i)) = x i := by + have H := (isSheaf_iff_isSheaf_of_type _ _).1 hF + apply exists_unique_of_exists_of_unique + · let s := fun (X : C) => (H _ (hY X)).amalgamate _ + (hx.familyOfElements_isCompatible X) + have hs : ∀ {X : C} (i : I) (f : X ⟶ Y i), s X = F.map f.op (x i) := fun {X} i f => by + have h := Presieve.IsSheafFor.valid_glue (H _ (hY X)) + (hx.familyOfElements_isCompatible _) (𝟙 _) ⟨i, ⟨f⟩⟩ + simp only [op_id, F.map_id, types_id_apply] at h + exact h.trans (hx.familyOfElements_apply _ _ _) + have hs' : ∀ {W X : C} (a : W ⟶ X) (i : I) (_ : W ⟶ Y i), F.map a.op (s X) = s W := by + intro W X a i b + rw [hs i b] + exact (Presieve.IsSheafFor.valid_glue (H _ (hY X)) + (hx.familyOfElements_isCompatible _) a ⟨i, ⟨b⟩⟩).trans (familyOfElements_apply hx _ _ _) + refine' ⟨⟨fun X => s X.unop, _⟩, fun i => (hs i (𝟙 (Y i))).trans (by simp)⟩ + rintro ⟨Y₁⟩ ⟨Y₂⟩ ⟨f : Y₂ ⟶ Y₁⟩ + change F.map f.op (s Y₁) = s Y₂ + apply (Presieve.isSeparated_of_isSheaf J F H _ (hY Y₂)).ext + rintro Z φ ⟨i, ⟨g⟩⟩ + rw [hs' φ i g, ← hs' (φ ≫ f) i g, op_comp, F.map_comp] + rfl + · intro y₁ y₂ hy₁ hy₂ + exact hY.sections_ext ⟨F, hF⟩ (fun i => by rw [hy₁, hy₂]) + +/-- The section of a sheaf of types which lifts a compatible family of elements indexed +by objects which cover the terminal object. -/ +noncomputable def section_ : F.sections := (hx.exists_unique_section hY hF).choose + +@[simp] +lemma section_apply (i : I) : (hx.section_ hY hF).1 (Opposite.op (Y i)) = x i := + (hx.exists_unique_section hY hF).choose_spec.1 i + +end IsCompatible + +end FamilyOfElementsOnObjects + +end Presheaf + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean b/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean index 2578320b8eb51..aa2899c7a0e9a 100644 --- a/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean +++ b/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean @@ -266,7 +266,7 @@ namespace Arrows open Presieve variable {B : C} {I : Type} (X : I → C) (π : (i : I) → X i ⟶ B) [UnivLE.{w, max v u}] - [(ofArrows X π).hasPullbacks] + [(Presieve.ofArrows X π).hasPullbacks] -- TODO: allow `I : Type w`  /-- @@ -339,7 +339,7 @@ theorem compatible_iff (x : FirstObj P X) : (Arrows.Compatible P π ((Types.prod `P` is a sheaf for `Presieve.ofArrows X π`, iff the fork given by `w` is an equalizer. See . -/ -theorem sheaf_condition : (ofArrows X π).IsSheafFor P ↔ +theorem sheaf_condition : (Presieve.ofArrows X π).IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι (forkMap P X π) (w P X π))) := by rw [Types.type_equalizer_iff_unique, isSheafFor_arrows_iff] erw [← Equiv.forall_congr_left (Types.productIso _).toEquiv.symm] diff --git a/Mathlib/CategoryTheory/Sites/Sieves.lean b/Mathlib/CategoryTheory/Sites/Sieves.lean index 6bd8768eae9a6..fe1429611c273 100644 --- a/Mathlib/CategoryTheory/Sites/Sieves.lean +++ b/Mathlib/CategoryTheory/Sites/Sieves.lean @@ -465,6 +465,52 @@ theorem generate_top : generate (⊤ : Presieve X) = ⊤ := generate_of_contains_isSplitEpi (𝟙 _) ⟨⟩ #align category_theory.sieve.generate_top CategoryTheory.Sieve.generate_top +/-- The sieve of `X` generated by family of morphisms `Y i ⟶ X`. -/ +abbrev ofArrows {I : Type*} {X : C} (Y : I → C) (f : ∀ i, Y i ⟶ X) : + Sieve X := + generate (Presieve.ofArrows Y f) + +lemma ofArrows_mk {I : Type*} {X : C} (Y : I → C) (f : ∀ i, Y i ⟶ X) (i : I) : + ofArrows Y f (f i) := + ⟨_, 𝟙 _, _, ⟨i⟩, by simp⟩ + +lemma mem_ofArrows_iff {I : Type*} {X : C} (Y : I → C) (f : ∀ i, Y i ⟶ X) + {W : C} (g : W ⟶ X) : + ofArrows Y f g ↔ ∃ (i : I) (a : W ⟶ Y i), g = a ≫ f i := by + constructor + · rintro ⟨T, a, b, ⟨i⟩, rfl⟩ + exact ⟨i, a, rfl⟩ + · rintro ⟨i, a, rfl⟩ + apply downward_closed _ (ofArrows_mk Y f i) + + +/-- The sieve of `X : C` that is generated by a family of objects `Y : I → C`: +it consists of morphisms to `X` which factor through at least one of the `Y i`. -/ +def ofObjects {I : Type*} (Y : I → C) (X : C) : Sieve X where + arrows Z _ := ∃ (i : I), Nonempty (Z ⟶ Y i) + downward_closed := by + rintro Z₁ Z₂ p ⟨i, ⟨f⟩⟩ g + exact ⟨i, ⟨g ≫ f⟩⟩ + +lemma mem_ofObjects_iff {I : Type*} (Y : I → C) {Z X : C} (g : Z ⟶ X) : + ofObjects Y X g ↔ ∃ (i : I), Nonempty (Z ⟶ Y i) := by rfl + +lemma ofArrows_le_ofObjects + {I : Type*} (Y : I → C) {X : C} (f : ∀ i, Y i ⟶ X) : + Sieve.ofArrows Y f ≤ Sieve.ofObjects Y X := by + intro W g hg + rw [mem_ofArrows_iff] at hg + obtain ⟨i, a, rfl⟩ := hg + exact ⟨i, ⟨a⟩⟩ + +lemma ofArrows_eq_ofObjects {X : C} (hX : IsTerminal X) + {I : Type*} (Y : I → C) (f : ∀ i, Y i ⟶ X) : + ofArrows Y f = ofObjects Y X := by + refine' le_antisymm (ofArrows_le_ofObjects Y f) (fun W g => _) + rw [mem_ofArrows_iff, mem_ofObjects_iff] + rintro ⟨i, ⟨h⟩⟩ + exact ⟨i, h, hX.hom_ext _ _⟩ + /-- Given a morphism `h : Y ⟶ X`, send a sieve S on X to a sieve on Y as the inverse image of S with `_ ≫ h`. That is, `Sieve.pullback S h := (≫ h) '⁻¹ S`. -/ @@ -501,6 +547,14 @@ theorem pullback_eq_top_of_mem (S : Sieve X) {f : Y ⟶ X} : S f → S.pullback (pullback_eq_top_iff_mem f).1 #align category_theory.sieve.pullback_eq_top_of_mem CategoryTheory.Sieve.pullback_eq_top_of_mem +lemma pullback_ofObjects_eq_top + {I : Type*} (Y : I → C) {X : C} {i : I} (g : X ⟶ Y i) : + ofObjects Y X = ⊤ := by + ext Z h + simp only [top_apply, iff_true] + rw [mem_ofObjects_iff ] + exact ⟨i, ⟨h ≫ g⟩⟩ + /-- Push a sieve `R` on `Y` forward along an arrow `f : Y ⟶ X`: `gf : Z ⟶ X` is in the sieve if `gf` factors through some `g : Z ⟶ Y` which is in `R`. -/ From 9ed6b90fffda5c72b70d53370fe210a9e45b71cc Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Wed, 27 Dec 2023 05:26:40 +0000 Subject: [PATCH 225/353] refactor: remove `Sym2`'s global `Prod` setoid instance, use `s(x, y)` notation for unordered pairs (#8729) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `Sym2` type used a global setoid instance on `α × α` so that `⟦(x, y)⟧` could stand for an unordered pair using standard `Quotient` syntax. This commit refactors `Sym2` to not use `Quotient` and instead use its own `s(x, y)` notation. One benefit to this is that this notation produces a term with type `Sym2` rather than `Quotient`. The `Fintype` instance for `Sym2` is in `Mathlib.Data.Finset.Sym`. We switch from using the one for `Quotient` because it does not require `DecidableEq`. --- .../Combinatorics/SimpleGraph/Acyclic.lean | 2 +- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 52 +-- .../SimpleGraph/Connectivity.lean | 46 +-- .../Combinatorics/SimpleGraph/DegreeSum.lean | 1 + .../Combinatorics/SimpleGraph/IncMatrix.lean | 3 +- .../Combinatorics/SimpleGraph/Matching.lean | 4 +- .../Combinatorics/SimpleGraph/Subgraph.lean | 16 +- .../SimpleGraph/Triangle/Basic.lean | 1 + Mathlib/Data/Finset/Sym.lean | 13 +- Mathlib/Data/List/Sym.lean | 12 +- Mathlib/Data/Multiset/Sym.lean | 2 +- Mathlib/Data/Sym/Card.lean | 33 +- Mathlib/Data/Sym/Sym2.lean | 296 +++++++++--------- Mathlib/Order/GameAdd.lean | 26 +- 14 files changed, 256 insertions(+), 251 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean index 9e517f29d9830..1c02bf8f62db3 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean @@ -66,7 +66,7 @@ variable {G} @[simp] lemma isAcyclic_bot : IsAcyclic (⊥ : SimpleGraph V) := λ _a _w hw ↦ hw.ne_bot rfl theorem isAcyclic_iff_forall_adj_isBridge : - G.IsAcyclic ↔ ∀ ⦃v w : V⦄, G.Adj v w → G.IsBridge ⟦(v, w)⟧ := by + G.IsAcyclic ↔ ∀ ⦃v w : V⦄, G.Adj v w → G.IsBridge s(v, w) := by simp_rw [isBridge_iff_adj_and_forall_cycle_not_mem] constructor · intro ha v w hvw diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 3d152240e7844..b7ece6d9eed0b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -494,12 +494,12 @@ variable {G₁ G₂ : SimpleGraph V} `SimpleGraph.edgeSet`. The way `edgeSet` is defined is such that `mem_edgeSet` is proved by `refl`. -(That is, `⟦(v, w)⟧ ∈ G.edgeSet` is definitionally equal to `G.Adj v w`.) +(That is, `s(v, w) ∈ G.edgeSet` is definitionally equal to `G.Adj v w`.) -/ -- porting note: We need a separate definition so that dot notation works. def edgeSetEmbedding (V : Type*) : SimpleGraph V ↪o Set (Sym2 V) := OrderEmbedding.ofMapLEIff (fun G => Sym2.fromRel G.symm) fun _ _ => - ⟨fun h a b => @h ⟦(a, b)⟧, fun h e => Sym2.ind @h e⟩ + ⟨fun h a b => @h s(a, b), fun h e => Sym2.ind @h e⟩ /-- `G.edgeSet` is the edge set for `G`. This is an abbreviation for `edgeSetEmbedding G` that permits dot notation. -/ @@ -508,7 +508,7 @@ abbrev edgeSet (G : SimpleGraph V) : Set (Sym2 V) := edgeSetEmbedding V G #align simple_graph.edge_set SimpleGraph.edgeSetEmbedding @[simp] -theorem mem_edgeSet : ⟦(v, w)⟧ ∈ G.edgeSet ↔ G.Adj v w := +theorem mem_edgeSet : s(v, w) ∈ G.edgeSet ↔ G.Adj v w := Iff.rfl #align simple_graph.mem_edge_set SimpleGraph.mem_edgeSet @@ -605,14 +605,14 @@ which is necessary since when `v = w` the existential `∃ (e ∈ G.edgeSet), v ∈ e ∧ w ∈ e` is satisfied by every edge incident to `v`. -/ theorem adj_iff_exists_edge {v w : V} : G.Adj v w ↔ v ≠ w ∧ ∃ e ∈ G.edgeSet, v ∈ e ∧ w ∈ e := by - refine' ⟨fun _ => ⟨G.ne_of_adj ‹_›, ⟦(v, w)⟧, by simpa⟩, _⟩ + refine' ⟨fun _ => ⟨G.ne_of_adj ‹_›, s(v, w), by simpa⟩, _⟩ rintro ⟨hne, e, he, hv⟩ rw [Sym2.mem_and_mem_iff hne] at hv subst e rwa [mem_edgeSet] at he #align simple_graph.adj_iff_exists_edge SimpleGraph.adj_iff_exists_edge -theorem adj_iff_exists_edge_coe : G.Adj a b ↔ ∃ e : G.edgeSet, e.val = ⟦(a, b)⟧ := by +theorem adj_iff_exists_edge_coe : G.Adj a b ↔ ∃ e : G.edgeSet, e.val = s(a, b) := by simp only [mem_edgeSet, exists_prop, SetCoe.exists, exists_eq_right, Subtype.coe_mk] #align simple_graph.adj_iff_exists_edge_coe SimpleGraph.adj_iff_exists_edge_coe @@ -668,12 +668,12 @@ def fromEdgeSet : SimpleGraph V where #align simple_graph.from_edge_set SimpleGraph.fromEdgeSet @[simp] -theorem fromEdgeSet_adj : (fromEdgeSet s).Adj v w ↔ ⟦(v, w)⟧ ∈ s ∧ v ≠ w := +theorem fromEdgeSet_adj : (fromEdgeSet s).Adj v w ↔ s(v, w) ∈ s ∧ v ≠ w := Iff.rfl #align simple_graph.from_edge_set_adj SimpleGraph.fromEdgeSet_adj -- Note: we need to make sure `fromEdgeSet_adj` and this lemma are confluent. --- In particular, both yield `⟦(u, v)⟧ ∈ (fromEdgeSet s).edgeSet` ==> `⟦(v, w)⟧ ∈ s ∧ v ≠ w`. +-- In particular, both yield `s(u, v) ∈ (fromEdgeSet s).edgeSet` ==> `s(v, w) ∈ s ∧ v ≠ w`. @[simp] theorem edgeSet_fromEdgeSet : (fromEdgeSet s).edgeSet = s \ { e | e.IsDiag } := by ext e @@ -786,11 +786,11 @@ instance Dart.fintype [Fintype V] [DecidableRel G.Adj] : Fintype G.Dart := /-- The edge associated to the dart. -/ def Dart.edge (d : G.Dart) : Sym2 V := - ⟦d.toProd⟧ + Sym2.mk d.toProd #align simple_graph.dart.edge SimpleGraph.Dart.edge @[simp] -theorem Dart.edge_mk {p : V × V} (h : G.Adj p.1 p.2) : (Dart.mk p h).edge = ⟦p⟧ := +theorem Dart.edge_mk {p : V × V} (h : G.Adj p.1 p.2) : (Dart.mk p h).edge = Sym2.mk p := rfl #align simple_graph.dart.edge_mk SimpleGraph.Dart.edge_mk @@ -812,7 +812,7 @@ theorem Dart.symm_mk {p : V × V} (h : G.Adj p.1 p.2) : (Dart.mk p h).symm = Dar @[simp] theorem Dart.edge_symm (d : G.Dart) : d.symm.edge = d.edge := - Sym2.mk''_prod_swap_eq + Sym2.mk_prod_swap_eq #align simple_graph.dart.edge_symm SimpleGraph.Dart.edge_symm @[simp] @@ -836,18 +836,18 @@ theorem Dart.symm_ne (d : G.Dart) : d.symm ≠ d := theorem dart_edge_eq_iff : ∀ d₁ d₂ : G.Dart, d₁.edge = d₂.edge ↔ d₁ = d₂ ∨ d₁ = d₂.symm := by rintro ⟨p, hp⟩ ⟨q, hq⟩ - simp [Sym2.mk''_eq_mk''_iff, -Quotient.eq] + simp #align simple_graph.dart_edge_eq_iff SimpleGraph.dart_edge_eq_iff theorem dart_edge_eq_mk'_iff : - ∀ {d : G.Dart} {p : V × V}, d.edge = ⟦p⟧ ↔ d.toProd = p ∨ d.toProd = p.swap := by + ∀ {d : G.Dart} {p : V × V}, d.edge = Sym2.mk p ↔ d.toProd = p ∨ d.toProd = p.swap := by rintro ⟨p, h⟩ - apply Sym2.mk''_eq_mk''_iff + apply Sym2.mk_eq_mk_iff #align simple_graph.dart_edge_eq_mk_iff SimpleGraph.dart_edge_eq_mk'_iff theorem dart_edge_eq_mk'_iff' : ∀ {d : G.Dart} {u v : V}, - d.edge = ⟦(u, v)⟧ ↔ d.fst = u ∧ d.snd = v ∨ d.fst = v ∧ d.snd = u := by + d.edge = s(u, v) ↔ d.fst = u ∧ d.snd = v ∨ d.fst = v ∧ d.snd = u := by rintro ⟨⟨a, b⟩, h⟩ u v rw [dart_edge_eq_mk'_iff] simp @@ -894,16 +894,16 @@ def incidenceSet (v : V) : Set (Sym2 V) := theorem incidenceSet_subset (v : V) : G.incidenceSet v ⊆ G.edgeSet := fun _ h => h.1 #align simple_graph.incidence_set_subset SimpleGraph.incidenceSet_subset -theorem mk'_mem_incidenceSet_iff : ⟦(b, c)⟧ ∈ G.incidenceSet a ↔ G.Adj b c ∧ (a = b ∨ a = c) := +theorem mk'_mem_incidenceSet_iff : s(b, c) ∈ G.incidenceSet a ↔ G.Adj b c ∧ (a = b ∨ a = c) := and_congr_right' Sym2.mem_iff #align simple_graph.mk_mem_incidence_set_iff SimpleGraph.mk'_mem_incidenceSet_iff -theorem mk'_mem_incidenceSet_left_iff : ⟦(a, b)⟧ ∈ G.incidenceSet a ↔ G.Adj a b := - and_iff_left <| Sym2.mem_mk''_left _ _ +theorem mk'_mem_incidenceSet_left_iff : s(a, b) ∈ G.incidenceSet a ↔ G.Adj a b := + and_iff_left <| Sym2.mem_mk_left _ _ #align simple_graph.mk_mem_incidence_set_left_iff SimpleGraph.mk'_mem_incidenceSet_left_iff -theorem mk'_mem_incidenceSet_right_iff : ⟦(a, b)⟧ ∈ G.incidenceSet b ↔ G.Adj a b := - and_iff_left <| Sym2.mem_mk''_right _ _ +theorem mk'_mem_incidenceSet_right_iff : s(a, b) ∈ G.incidenceSet b ↔ G.Adj a b := + and_iff_left <| Sym2.mem_mk_right _ _ #align simple_graph.mk_mem_incidence_set_right_iff SimpleGraph.mk'_mem_incidenceSet_right_iff theorem edge_mem_incidenceSet_iff {e : G.edgeSet} : ↑e ∈ G.incidenceSet a ↔ a ∈ (e : Sym2 V) := @@ -911,14 +911,14 @@ theorem edge_mem_incidenceSet_iff {e : G.edgeSet} : ↑e ∈ G.incidenceSet a #align simple_graph.edge_mem_incidence_set_iff SimpleGraph.edge_mem_incidenceSet_iff theorem incidenceSet_inter_incidenceSet_subset (h : a ≠ b) : - G.incidenceSet a ∩ G.incidenceSet b ⊆ {⟦(a, b)⟧} := fun _e he => + G.incidenceSet a ∩ G.incidenceSet b ⊆ {s(a, b)} := fun _e he => (Sym2.mem_and_mem_iff h).1 ⟨he.1.2, he.2.2⟩ #align simple_graph.incidence_set_inter_incidence_set_subset SimpleGraph.incidenceSet_inter_incidenceSet_subset theorem incidenceSet_inter_incidenceSet_of_adj (h : G.Adj a b) : - G.incidenceSet a ∩ G.incidenceSet b = {⟦(a, b)⟧} := by + G.incidenceSet a ∩ G.incidenceSet b = {s(a, b)} := by refine' (G.incidenceSet_inter_incidenceSet_subset <| h.ne).antisymm _ - rintro _ (rfl : _ = ⟦(a, b)⟧) + rintro _ (rfl : _ = s(a, b)) exact ⟨G.mk'_mem_incidenceSet_left_iff.2 h, G.mk'_mem_incidenceSet_right_iff.2 h⟩ #align simple_graph.incidence_set_inter_incidence_set_of_adj SimpleGraph.incidenceSet_inter_incidenceSet_of_adj @@ -1037,11 +1037,11 @@ lemma not_mem_neighborSet_self : a ∉ G.neighborSet a := by simp #align simple_graph.not_mem_neighbor_set_self SimpleGraph.not_mem_neighborSet_self @[simp] -theorem mem_incidenceSet (v w : V) : ⟦(v, w)⟧ ∈ G.incidenceSet v ↔ G.Adj v w := by +theorem mem_incidenceSet (v w : V) : s(v, w) ∈ G.incidenceSet v ↔ G.Adj v w := by simp [incidenceSet] #align simple_graph.mem_incidence_set SimpleGraph.mem_incidenceSet -theorem mem_incidence_iff_neighbor {v w : V} : ⟦(v, w)⟧ ∈ G.incidenceSet v ↔ w ∈ G.neighborSet v := +theorem mem_incidence_iff_neighbor {v w : V} : s(v, w) ∈ G.incidenceSet v ↔ w ∈ G.neighborSet v := by simp only [mem_incidenceSet, mem_neighborSet] #align simple_graph.mem_incidence_iff_neighbor SimpleGraph.mem_incidence_iff_neighbor @@ -1165,7 +1165,7 @@ vertex and the set of vertices adjacent to the vertex. -/ def incidenceSetEquivNeighborSet (v : V) : G.incidenceSet v ≃ G.neighborSet v where toFun e := ⟨G.otherVertexOfIncident e.2, G.incidence_other_prop e.2⟩ - invFun w := ⟨⟦(v, w.1)⟧, G.mem_incidence_iff_neighbor.mpr w.2⟩ + invFun w := ⟨s(v, w.1), G.mem_incidence_iff_neighbor.mpr w.2⟩ left_inv x := by simp [otherVertexOfIncident] right_inv := fun ⟨w, hw⟩ => by simp only [mem_neighborSet, Subtype.mk.injEq] @@ -1190,7 +1190,7 @@ def deleteEdges (s : Set (Sym2 V)) : SimpleGraph V @[simp] theorem deleteEdges_adj (s : Set (Sym2 V)) (v w : V) : - (G.deleteEdges s).Adj v w ↔ G.Adj v w ∧ ¬⟦(v, w)⟧ ∈ s := + (G.deleteEdges s).Adj v w ↔ G.Adj v w ∧ ¬s(v, w) ∈ s := Iff.rfl #align simple_graph.delete_edges_adj SimpleGraph.deleteEdges_adj diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity.lean index 671f4ac3d2cd1..83c4a00358465 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity.lean @@ -674,7 +674,7 @@ theorem edges_subset_edgeSet {u v : V} : next h' => exact edges_subset_edgeSet p' h' #align simple_graph.walk.edges_subset_edge_set SimpleGraph.Walk.edges_subset_edgeSet -theorem adj_of_mem_edges {u v x y : V} (p : G.Walk u v) (h : ⟦(x, y)⟧ ∈ p.edges) : G.Adj x y := +theorem adj_of_mem_edges {u v x y : V} (p : G.Walk u v) (h : s(x, y) ∈ p.edges) : G.Adj x y := edges_subset_edgeSet p h #align simple_graph.walk.adj_of_mem_edges SimpleGraph.Walk.adj_of_mem_edges @@ -739,12 +739,12 @@ theorem edges_nil {u : V} : (nil : G.Walk u u).edges = [] := rfl @[simp] theorem edges_cons {u v w : V} (h : G.Adj u v) (p : G.Walk v w) : - (cons h p).edges = ⟦(u, v)⟧ :: p.edges := rfl + (cons h p).edges = s(u, v) :: p.edges := rfl #align simple_graph.walk.edges_cons SimpleGraph.Walk.edges_cons @[simp] theorem edges_concat {u v w : V} (p : G.Walk u v) (h : G.Adj v w) : - (p.concat h).edges = p.edges.concat ⟦(v, w)⟧ := by simp [edges] + (p.concat h).edges = p.edges.concat s(v, w) := by simp [edges] #align simple_graph.walk.edges_concat SimpleGraph.Walk.edges_concat @[simp] @@ -792,7 +792,7 @@ theorem dart_snd_mem_support_of_mem_darts {u v : V} (p : G.Walk u v) {d : G.Dart simpa using p.reverse.dart_fst_mem_support_of_mem_darts (by simp [h] : d.symm ∈ p.reverse.darts) #align simple_graph.walk.dart_snd_mem_support_of_mem_darts SimpleGraph.Walk.dart_snd_mem_support_of_mem_darts -theorem fst_mem_support_of_mem_edges {t u v w : V} (p : G.Walk v w) (he : ⟦(t, u)⟧ ∈ p.edges) : +theorem fst_mem_support_of_mem_edges {t u v w : V} (p : G.Walk v w) (he : s(t, u) ∈ p.edges) : t ∈ p.support := by obtain ⟨d, hd, he⟩ := List.mem_map.mp he rw [dart_edge_eq_mk'_iff'] at he @@ -801,7 +801,7 @@ theorem fst_mem_support_of_mem_edges {t u v w : V} (p : G.Walk v w) (he : ⟦(t, · exact dart_snd_mem_support_of_mem_darts _ hd #align simple_graph.walk.fst_mem_support_of_mem_edges SimpleGraph.Walk.fst_mem_support_of_mem_edges -theorem snd_mem_support_of_mem_edges {t u v w : V} (p : G.Walk v w) (he : ⟦(t, u)⟧ ∈ p.edges) : +theorem snd_mem_support_of_mem_edges {t u v w : V} (p : G.Walk v w) (he : s(t, u) ∈ p.edges) : u ∈ p.support := by rw [Sym2.eq_swap] at he exact p.fst_mem_support_of_mem_edges he @@ -883,7 +883,7 @@ def firstDart (p : G.Walk v w) (hp : ¬ p.Nil) : G.Dart where is_adj := p.adj_sndOfNotNil hp lemma edge_firstDart (p : G.Walk v w) (hp : ¬ p.Nil) : - (p.firstDart hp).edge = ⟦(v, p.sndOfNotNil hp)⟧ := rfl + (p.firstDart hp).edge = s(v, p.sndOfNotNil hp) := rfl @[simp] lemma cons_tail_eq (p : G.Walk x y) (hp : ¬ p.Nil) : cons (p.adj_sndOfNotNil hp) (p.tail hp) = p := @@ -993,7 +993,7 @@ theorem IsTrail.of_cons {u v w : V} {h : G.Adj u v} {p : G.Walk v w} : @[simp] theorem cons_isTrail_iff {u v w : V} (h : G.Adj u v) (p : G.Walk v w) : - (cons h p).IsTrail ↔ p.IsTrail ∧ ⟦(u, v)⟧ ∉ p.edges := by simp [isTrail_def, and_comm] + (cons h p).IsTrail ↔ p.IsTrail ∧ s(u, v) ∉ p.edges := by simp [isTrail_def, and_comm] #align simple_graph.walk.cons_is_trail_iff SimpleGraph.Walk.cons_isTrail_iff theorem IsTrail.reverse {u v : V} (p : G.Walk u v) (h : p.IsTrail) : p.reverse.IsTrail := by @@ -1083,7 +1083,7 @@ lemma IsCycle.ne_bot : ∀ {p : G.Walk u u}, p.IsCycle → G ≠ ⊥ | cons h _, hp => by rintro rfl; exact h theorem cons_isCycle_iff {u v : V} (p : G.Walk v u) (h : G.Adj u v) : - (Walk.cons h p).IsCycle ↔ p.IsPath ∧ ¬⟦(u, v)⟧ ∈ p.edges := by + (Walk.cons h p).IsCycle ↔ p.IsPath ∧ ¬s(u, v) ∈ p.edges := by simp only [Walk.isCycle_def, Walk.isPath_def, Walk.isTrail_def, edges_cons, List.nodup_cons, support_cons, List.tail_cons] have : p.support.Nodup → p.edges.Nodup := edges_nodup_of_support_nodup @@ -1174,7 +1174,7 @@ theorem count_support_takeUntil_eq_one {u v w : V} (p : G.Walk v w) (h : u ∈ p #align simple_graph.walk.count_support_take_until_eq_one SimpleGraph.Walk.count_support_takeUntil_eq_one theorem count_edges_takeUntil_le_one {u v w : V} (p : G.Walk v w) (h : u ∈ p.support) (x : V) : - (p.takeUntil u h).edges.count ⟦(u, x)⟧ ≤ 1 := by + (p.takeUntil u h).edges.count s(u, x) ≤ 1 := by induction' p with u' u' v' w' ha p' ih · rw [mem_support_nil_iff] at h subst u @@ -1377,7 +1377,7 @@ def singleton {u v : V} (h : G.Adj u v) : G.Path u v := #align simple_graph.path.singleton SimpleGraph.Path.singleton theorem mk'_mem_edges_singleton {u v : V} (h : G.Adj u v) : - ⟦(u, v)⟧ ∈ (singleton h : G.Walk u v).edges := by simp [singleton] + s(u, v) ∈ (singleton h : G.Walk u v).edges := by simp [singleton] #align simple_graph.path.mk_mem_edges_singleton SimpleGraph.Path.mk'_mem_edges_singleton /-- The reverse of a path is another path. See also `SimpleGraph.Walk.reverse`. -/ @@ -1412,7 +1412,7 @@ theorem not_mem_edges_of_loop {v : V} {e : Sym2 V} {p : G.Path v v} : ¬e ∈ (p #align simple_graph.path.not_mem_edges_of_loop SimpleGraph.Path.not_mem_edges_of_loop theorem cons_isCycle {u v : V} (p : G.Path v u) (h : G.Adj u v) - (he : ¬⟦(u, v)⟧ ∈ (p : G.Walk v u).edges) : (Walk.cons h ↑p).IsCycle := by + (he : ¬s(u, v) ∈ (p : G.Walk v u).edges) : (Walk.cons h ↑p).IsCycle := by simp [Walk.isCycle_def, Walk.cons_isTrail_iff, he] #align simple_graph.path.cons_is_cycle SimpleGraph.Path.cons_isCycle @@ -1760,7 +1760,7 @@ protected def transfer {u v : V} (p : G.Walk u v) match p with | nil => nil | cons' u v w a p => - cons (h ⟦(u, v)⟧ (by simp)) (p.transfer H fun e he => h e (by simp [he])) + cons (h s(u, v) (by simp)) (p.transfer H fun e he => h e (by simp [he])) #align simple_graph.walk.transfer SimpleGraph.Walk.transfer variable {u v : V} (p : G.Walk u v) @@ -2556,11 +2556,11 @@ def IsBridge (G : SimpleGraph V) (e : Sym2 V) : Prop := #align simple_graph.is_bridge SimpleGraph.IsBridge theorem isBridge_iff {u v : V} : - G.IsBridge ⟦(u, v)⟧ ↔ G.Adj u v ∧ ¬(G \ fromEdgeSet {⟦(u, v)⟧}).Reachable u v := Iff.rfl + G.IsBridge s(u, v) ↔ G.Adj u v ∧ ¬(G \ fromEdgeSet {s(u, v)}).Reachable u v := Iff.rfl #align simple_graph.is_bridge_iff SimpleGraph.isBridge_iff theorem reachable_delete_edges_iff_exists_walk {v w : V} : - (G \ fromEdgeSet {⟦(v, w)⟧}).Reachable v w ↔ ∃ p : G.Walk v w, ¬⟦(v, w)⟧ ∈ p.edges := by + (G \ fromEdgeSet {s(v, w)}).Reachable v w ↔ ∃ p : G.Walk v w, ¬s(v, w) ∈ p.edges := by constructor · rintro ⟨p⟩ use p.map (Hom.mapSpanningSubgraphs (by simp)) @@ -2575,14 +2575,14 @@ theorem reachable_delete_edges_iff_exists_walk {v w : V} : #align simple_graph.reachable_delete_edges_iff_exists_walk SimpleGraph.reachable_delete_edges_iff_exists_walk theorem isBridge_iff_adj_and_forall_walk_mem_edges {v w : V} : - G.IsBridge ⟦(v, w)⟧ ↔ G.Adj v w ∧ ∀ p : G.Walk v w, ⟦(v, w)⟧ ∈ p.edges := by + G.IsBridge s(v, w) ↔ G.Adj v w ∧ ∀ p : G.Walk v w, s(v, w) ∈ p.edges := by rw [isBridge_iff, and_congr_right'] rw [reachable_delete_edges_iff_exists_walk, not_exists_not] #align simple_graph.is_bridge_iff_adj_and_forall_walk_mem_edges SimpleGraph.isBridge_iff_adj_and_forall_walk_mem_edges theorem reachable_deleteEdges_iff_exists_cycle.aux [DecidableEq V] {u v w : V} - (hb : ∀ p : G.Walk v w, ⟦(v, w)⟧ ∈ p.edges) (c : G.Walk u u) (hc : c.IsTrail) - (he : ⟦(v, w)⟧ ∈ c.edges) + (hb : ∀ p : G.Walk v w, s(v, w) ∈ p.edges) (c : G.Walk u u) (hc : c.IsTrail) + (he : s(v, w) ∈ c.edges) (hw : w ∈ (c.takeUntil v (c.fst_mem_support_of_mem_edges he)).support) : False := by have hv := c.fst_mem_support_of_mem_edges he -- decompose c into @@ -2598,7 +2598,7 @@ theorem reachable_deleteEdges_iff_exists_cycle.aux [DecidableEq V] {u v w : V} -- | ^ -- `-------------' -- pwv.reverse - -- so they both contain the edge ⟦(v, w)⟧, but that's a contradiction since c is a trail. + -- so they both contain the edge s(v, w), but that's a contradiction since c is a trail. have hbq := hb (pvu.append puw) have hpq' := hb pwv.reverse rw [Walk.edges_reverse, List.mem_reverse] at hpq' @@ -2609,8 +2609,8 @@ theorem reachable_deleteEdges_iff_exists_cycle.aux [DecidableEq V] {u v w : V} -- porting note: the unused variable checker helped eliminate a good amount of this proof (!) theorem adj_and_reachable_delete_edges_iff_exists_cycle {v w : V} : - G.Adj v w ∧ (G \ fromEdgeSet {⟦(v, w)⟧}).Reachable v w ↔ - ∃ (u : V) (p : G.Walk u u), p.IsCycle ∧ ⟦(v, w)⟧ ∈ p.edges := by + G.Adj v w ∧ (G \ fromEdgeSet {s(v, w)}).Reachable v w ↔ + ∃ (u : V) (p : G.Walk u u), p.IsCycle ∧ s(v, w) ∈ p.edges := by classical rw [reachable_delete_edges_iff_exists_walk] constructor @@ -2624,7 +2624,7 @@ theorem adj_and_reachable_delete_edges_iff_exists_cycle {v w : V} : · rintro ⟨u, c, hc, he⟩ refine ⟨c.adj_of_mem_edges he, ?_⟩ by_contra! hb - have hb' : ∀ p : G.Walk w v, ⟦(w, v)⟧ ∈ p.edges := by + have hb' : ∀ p : G.Walk w v, s(w, v) ∈ p.edges := by intro p simpa [Sym2.eq_swap] using hb p.reverse have hvc : v ∈ c.support := Walk.fst_mem_support_of_mem_edges c he @@ -2633,8 +2633,8 @@ theorem adj_and_reachable_delete_edges_iff_exists_cycle {v w : V} : rwa [(Walk.rotate_edges c hvc).mem_iff, Sym2.eq_swap] #align simple_graph.adj_and_reachable_delete_edges_iff_exists_cycle SimpleGraph.adj_and_reachable_delete_edges_iff_exists_cycle -theorem isBridge_iff_adj_and_forall_cycle_not_mem {v w : V} : G.IsBridge ⟦(v, w)⟧ ↔ - G.Adj v w ∧ ∀ ⦃u : V⦄ (p : G.Walk u u), p.IsCycle → ⟦(v, w)⟧ ∉ p.edges := by +theorem isBridge_iff_adj_and_forall_cycle_not_mem {v w : V} : G.IsBridge s(v, w) ↔ + G.Adj v w ∧ ∀ ⦃u : V⦄ (p : G.Walk u u), p.IsCycle → s(v, w) ∉ p.edges := by rw [isBridge_iff, and_congr_right_iff] intro h rw [← not_iff_not] diff --git a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean index f64864503ce12..1d9daceba8ef4 100644 --- a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean +++ b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean @@ -5,6 +5,7 @@ Authors: Kyle Miller -/ import Mathlib.Combinatorics.SimpleGraph.Basic import Mathlib.Algebra.BigOperators.Basic +import Mathlib.Data.Finset.Sym import Mathlib.Data.Nat.Parity import Mathlib.Data.ZMod.Parity diff --git a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean index 69b655b014144..2034a17d1cd43 100644 --- a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Moise, Yaël Dillies, Kyle Miller -/ import Mathlib.Combinatorics.SimpleGraph.Basic +import Mathlib.Data.Finset.Sym import Mathlib.Data.Matrix.Basic #align_import combinatorics.simple_graph.inc_matrix from "leanprover-community/mathlib"@"bb168510ef455e9280a152e7f31673cabd3d7496" @@ -180,7 +181,7 @@ theorem incMatrix_mul_transpose_apply_of_adj (h : G.Adj a b) : simp_rw [Matrix.mul_apply, Matrix.transpose_apply, incMatrix_apply_mul_incMatrix_apply, Set.indicator_apply, Pi.one_apply, sum_boole] convert @Nat.cast_one R _ - convert card_singleton ⟦(a, b)⟧ + convert card_singleton s(a, b) rw [← coe_eq_singleton, coe_filter_univ] exact G.incidenceSet_inter_incidenceSet_of_adj h #align simple_graph.inc_matrix_mul_transpose_apply_of_adj SimpleGraph.incMatrix_mul_transpose_apply_of_adj diff --git a/Mathlib/Combinatorics/SimpleGraph/Matching.lean b/Mathlib/Combinatorics/SimpleGraph/Matching.lean index a678f8125d3e6..ec75a55a31a4e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Matching.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Matching.lean @@ -57,11 +57,11 @@ def IsMatching : Prop := ∀ ⦃v⦄, v ∈ M.verts → ∃! w, M.Adj v w /-- Given a vertex, returns the unique edge of the matching it is incident to. -/ noncomputable def IsMatching.toEdge {M : Subgraph G} (h : M.IsMatching) (v : M.verts) : M.edgeSet := - ⟨⟦(v, (h v.property).choose)⟧, (h v.property).choose_spec.1⟩ + ⟨s(v, (h v.property).choose), (h v.property).choose_spec.1⟩ #align simple_graph.subgraph.is_matching.to_edge SimpleGraph.Subgraph.IsMatching.toEdge theorem IsMatching.toEdge_eq_of_adj {M : Subgraph G} (h : M.IsMatching) {v w : V} (hv : v ∈ M.verts) - (hvw : M.Adj v w) : h.toEdge ⟨v, hv⟩ = ⟨⟦(v, w)⟧, hvw⟩ := by + (hvw : M.Adj v w) : h.toEdge ⟨v, hv⟩ = ⟨s(v, w), hvw⟩ := by simp only [IsMatching.toEdge, Subtype.mk_eq_mk] congr exact ((h (M.edge_vert hvw)).choose_spec.2 w hvw).symm diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index 11ab0642b56f4..fb701994057ce 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean @@ -83,7 +83,7 @@ protected def singletonSubgraph (G : SimpleGraph V) (v : V) : G.Subgraph where @[simps] def subgraphOfAdj (G : SimpleGraph V) {v w : V} (hvw : G.Adj v w) : G.Subgraph where verts := {v, w} - Adj a b := ⟦(v, w)⟧ = ⟦(a, b)⟧ + Adj a b := s(v, w) = s(a, b) adj_sub h := by rw [← G.mem_edgeSet, ← h] exact hvw @@ -239,7 +239,7 @@ theorem edgeSet_subset (G' : Subgraph G) : G'.edgeSet ⊆ G.edgeSet := #align simple_graph.subgraph.edge_set_subset SimpleGraph.Subgraph.edgeSet_subset @[simp] -theorem mem_edgeSet {G' : Subgraph G} {v w : V} : ⟦(v, w)⟧ ∈ G'.edgeSet ↔ G'.Adj v w := Iff.rfl +theorem mem_edgeSet {G' : Subgraph G} {v w : V} : s(v, w) ∈ G'.edgeSet ↔ G'.Adj v w := Iff.rfl #align simple_graph.subgraph.mem_edge_set SimpleGraph.Subgraph.mem_edgeSet theorem mem_verts_if_mem_edge {G' : Subgraph G} {e : Sym2 V} {v : V} (he : e ∈ G'.edgeSet) @@ -893,7 +893,7 @@ instance nonempty_subgraphOfAdj_verts {v w : V} (hvw : G.Adj v w) : @[simp] theorem edgeSet_subgraphOfAdj {v w : V} (hvw : G.Adj v w) : - (G.subgraphOfAdj hvw).edgeSet = {⟦(v, w)⟧} := by + (G.subgraphOfAdj hvw).edgeSet = {s(v, w)} := by ext e refine' e.ind _ simp only [eq_comm, Set.mem_singleton_iff, Subgraph.mem_edgeSet, subgraphOfAdj_adj, iff_self_iff, @@ -906,7 +906,7 @@ lemma subgraphOfAdj_le_of_adj (H : G.Subgraph) (h : H.Adj v w) : constructor · intro x rintro (rfl | rfl) <;> simp [H.edge_vert h, H.edge_vert h.symm] - · simp only [subgraphOfAdj_adj, Quotient.eq, Sym2.rel_iff] + · simp only [subgraphOfAdj_adj, Sym2.eq, Sym2.rel_iff] rintro _ _ (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩) <;> simp [h, h.symm] theorem subgraphOfAdj_symm {v w : V} (hvw : G.Adj v w) : @@ -927,7 +927,7 @@ theorem map_subgraphOfAdj (f : G →g G') {v w : V} (hvw : G.Adj v w) : simp · use w simp - · simp only [Relation.Map, Subgraph.map_adj, subgraphOfAdj_adj, Quotient.eq, Sym2.rel_iff] + · simp only [Relation.Map, Subgraph.map_adj, subgraphOfAdj_adj, Sym2.eq, Sym2.rel_iff] constructor · rintro ⟨a, b, ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩, rfl, rfl⟩ <;> simp · rintro (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩) @@ -1065,7 +1065,7 @@ theorem deleteEdges_verts : (G'.deleteEdges s).verts = G'.verts := #align simple_graph.subgraph.delete_edges_verts SimpleGraph.Subgraph.deleteEdges_verts @[simp] -theorem deleteEdges_adj (v w : V) : (G'.deleteEdges s).Adj v w ↔ G'.Adj v w ∧ ¬⟦(v, w)⟧ ∈ s := +theorem deleteEdges_adj (v w : V) : (G'.deleteEdges s).Adj v w ↔ G'.Adj v w ∧ ¬s(v, w) ∈ s := Iff.rfl #align simple_graph.subgraph.delete_edges_adj SimpleGraph.Subgraph.deleteEdges_adj @@ -1097,7 +1097,7 @@ theorem deleteEdges_coe_eq (s : Set (Sym2 G'.verts)) : · intro hs refine' Sym2.ind _ rintro ⟨v', hv'⟩ ⟨w', hw'⟩ - simp only [Sym2.map_pair_eq, Quotient.eq] + simp only [Sym2.map_pair_eq, Sym2.eq] contrapose! rintro (_ | _) <;> simpa only [Sym2.eq_swap] · intro h' hs @@ -1231,7 +1231,7 @@ theorem subgraphOfAdj_eq_induce {v w : V} (hvw : G.Adj v w) : · simp · constructor · intro h - simp only [subgraphOfAdj_adj, Quotient.eq, Sym2.rel_iff] at h + simp only [subgraphOfAdj_adj, Sym2.eq, Sym2.rel_iff] at h obtain ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩ := h <;> simp [hvw, hvw.symm] · intro h simp only [induce_adj, Set.mem_insert_iff, Set.mem_singleton_iff, top_adj] at h diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean index c1df57f589534..8e7e5dec19701 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Bhavik Mehta -/ import Mathlib.Combinatorics.SimpleGraph.Clique +import Mathlib.Data.Finset.Sym import Mathlib.Tactic.GCongr #align_import combinatorics.simple_graph.triangle.basic from "leanprover-community/mathlib"@"3365b20c2ffa7c35e47e5209b89ba9abdddf3ffe" diff --git a/Mathlib/Data/Finset/Sym.lean b/Mathlib/Data/Finset/Sym.lean index 90fe5b22a5786..b9c5f52c9eecc 100644 --- a/Mathlib/Data/Finset/Sym.lean +++ b/Mathlib/Data/Finset/Sym.lean @@ -44,7 +44,7 @@ protected def sym2 (s : Finset α) : Finset (Sym2 α) := ⟨s.1.sym2, s.2.sym2 section variable {s t : Finset α} {a b : α} -theorem mk_mem_sym2_iff : ⟦(a, b)⟧ ∈ s.sym2 ↔ a ∈ s ∧ b ∈ s := by +theorem mk_mem_sym2_iff : s(a, b) ∈ s.sym2 ↔ a ∈ s ∧ b ∈ s := by rw [mem_mk, sym2_val, Multiset.mk_mem_sym2_iff, mem_mk, mem_mk] #align finset.mk_mem_sym2_iff Finset.mk_mem_sym2_iff @@ -78,7 +78,7 @@ theorem monotone_sym2 : Monotone (Finset.sym2 : Finset α → _) := fun _ _ => s theorem injective_sym2 : Function.Injective (Finset.sym2 : Finset α → _) := by intro s t h ext x - simpa using congr(⟦(x, x)⟧ ∈ $h) + simpa using congr(s(x, x) ∈ $h) theorem strictMono_sym2 : StrictMono (Finset.sym2 : Finset α → _) := monotone_sym2.strictMono_of_injective injective_sym2 @@ -120,7 +120,7 @@ end variable [DecidableEq α] {s t : Finset α} {a b : α} -theorem sym2_eq_image : s.sym2 = (s ×ˢ s).image (Quotient.mk _) := by +theorem sym2_eq_image : s.sym2 = (s ×ˢ s).image Sym2.mk := by ext z refine z.ind fun x y ↦ ?_ rw [mk_mem_sym2_iff, mem_image] @@ -133,11 +133,12 @@ theorem sym2_eq_image : s.sym2 = (s ×ˢ s).image (Quotient.mk _) := by obtain ⟨h, (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)⟩ := h <;> simp [h] -theorem isDiag_mk_of_mem_diag {a : α × α} (h : a ∈ s.diag) : Sym2.IsDiag ⟦a⟧ := +theorem isDiag_mk_of_mem_diag {a : α × α} (h : a ∈ s.diag) : (Sym2.mk a).IsDiag := (Sym2.isDiag_iff_proj_eq _).2 (mem_diag.1 h).2 #align finset.is_diag_mk_of_mem_diag Finset.isDiag_mk_of_mem_diag -theorem not_isDiag_mk_of_mem_offDiag {a : α × α} (h : a ∈ s.offDiag) : ¬Sym2.IsDiag ⟦a⟧ := by +theorem not_isDiag_mk_of_mem_offDiag {a : α × α} (h : a ∈ s.offDiag) : + ¬ (Sym2.mk a).IsDiag := by rw [Sym2.isDiag_iff_proj_eq] exact (mem_offDiag.1 h).2.2 #align finset.not_is_diag_mk_of_mem_off_diag Finset.not_isDiag_mk_of_mem_offDiag @@ -157,7 +158,7 @@ theorem diag_mem_sym2_iff : Sym2.diag a ∈ s.sym2 ↔ a ∈ s := by simp [diag_ #align finset.diag_mem_sym2_iff Finset.diag_mem_sym2_iff theorem image_diag_union_image_offDiag : - s.diag.image (Quotient.mk _) ∪ s.offDiag.image (Quotient.mk _) = s.sym2 := by + s.diag.image Sym2.mk ∪ s.offDiag.image Sym2.mk = s.sym2 := by rw [← image_union, diag_union_offDiag, sym2_eq_image] #align finset.image_diag_union_image_off_diag Finset.image_diag_union_image_offDiag diff --git a/Mathlib/Data/List/Sym.lean b/Mathlib/Data/List/Sym.lean index c9122e6170a41..8ff6e87a57ae7 100644 --- a/Mathlib/Data/List/Sym.lean +++ b/Mathlib/Data/List/Sym.lean @@ -35,10 +35,10 @@ section Sym2 If `xs` has no duplicates then neither does `xs.sym2`. -/ protected def sym2 : List α → List (Sym2 α) | [] => [] - | x :: xs => (x :: xs).map (fun y => ⟦(x, y)⟧) ++ xs.sym2 + | x :: xs => (x :: xs).map (fun y => s(x, y)) ++ xs.sym2 theorem mem_sym2_cons_iff {x : α} {xs : List α} {z : Sym2 α} : - z ∈ (x :: xs).sym2 ↔ z = ⟦(x, x)⟧ ∨ (∃ y, y ∈ xs ∧ z = ⟦(x, y)⟧) ∨ z ∈ xs.sym2 := by + z ∈ (x :: xs).sym2 ↔ z = s(x, x) ∨ (∃ y, y ∈ xs ∧ z = s(x, y)) ∨ z ∈ xs.sym2 := by simp only [List.sym2, map_cons, cons_append, mem_cons, mem_append, mem_map] simp only [eq_comm] @@ -47,7 +47,7 @@ theorem sym2_eq_nil_iff {xs : List α} : xs.sym2 = [] ↔ xs = [] := by cases xs <;> simp [List.sym2] theorem left_mem_of_mk_mem_sym2 {xs : List α} {a b : α} - (h : ⟦(a, b)⟧ ∈ xs.sym2) : a ∈ xs := by + (h : s(a, b) ∈ xs.sym2) : a ∈ xs := by induction xs with | nil => exact (not_mem_nil _ h).elim | cons x xs ih => @@ -61,12 +61,12 @@ theorem left_mem_of_mk_mem_sym2 {xs : List α} {a b : α} · exact .inr <| ih h theorem right_mem_of_mk_mem_sym2 {xs : List α} {a b : α} - (h : ⟦(a, b)⟧ ∈ xs.sym2) : b ∈ xs := by + (h : s(a, b) ∈ xs.sym2) : b ∈ xs := by rw [Sym2.eq_swap] at h exact left_mem_of_mk_mem_sym2 h theorem mk_mem_sym2 {xs : List α} {a b : α} (ha : a ∈ xs) (hb : b ∈ xs) : - ⟦(a, b)⟧ ∈ xs.sym2 := by + s(a, b) ∈ xs.sym2 := by induction xs with | nil => simp at ha | cons x xs ih => @@ -79,7 +79,7 @@ theorem mk_mem_sym2 {xs : List α} {a b : α} (ha : a ∈ xs) (hb : b ∈ xs) : · right; right; exact ih ha hb theorem mk_mem_sym2_iff {xs : List α} {a b : α} : - ⟦(a, b)⟧ ∈ xs.sym2 ↔ a ∈ xs ∧ b ∈ xs := by + s(a, b) ∈ xs.sym2 ↔ a ∈ xs ∧ b ∈ xs := by constructor · intro h exact ⟨left_mem_of_mk_mem_sym2 h, right_mem_of_mk_mem_sym2 h⟩ diff --git a/Mathlib/Data/Multiset/Sym.lean b/Mathlib/Data/Multiset/Sym.lean index 1da72ce97876b..67af1557a529f 100644 --- a/Mathlib/Data/Multiset/Sym.lean +++ b/Mathlib/Data/Multiset/Sym.lean @@ -48,7 +48,7 @@ theorem sym2_eq_zero_iff {m : Multiset α} : m.sym2 = 0 ↔ m = 0 := m.inductionOn fun xs => by simp theorem mk_mem_sym2_iff {m : Multiset α} {a b : α} : - ⟦(a, b)⟧ ∈ m.sym2 ↔ a ∈ m ∧ b ∈ m := + s(a, b) ∈ m.sym2 ↔ a ∈ m ∧ b ∈ m := m.inductionOn fun xs => by simp [List.mk_mem_sym2_iff] theorem mem_sym2_iff {m : Multiset α} {z : Sym2 α} : diff --git a/Mathlib/Data/Sym/Card.lean b/Mathlib/Data/Sym/Card.lean index e6828cc1c4df5..14f61935dc771 100644 --- a/Mathlib/Data/Sym/Card.lean +++ b/Mathlib/Data/Sym/Card.lean @@ -129,68 +129,61 @@ namespace Sym2 variable [DecidableEq α] /-- The `diag` of `s : Finset α` is sent on a finset of `Sym2 α` of card `s.card`. -/ -theorem card_image_diag (s : Finset α) : (s.diag.image (Quotient.mk _)).card = s.card := by +theorem card_image_diag (s : Finset α) : (s.diag.image Sym2.mk).card = s.card := by rw [card_image_of_injOn, diag_card] rintro ⟨x₀, x₁⟩ hx _ _ h - cases Quotient.eq'.1 h + cases Sym2.eq.1 h · rfl · simp only [mem_coe, mem_diag] at hx rw [hx.2] #align sym2.card_image_diag Sym2.card_image_diag theorem two_mul_card_image_offDiag (s : Finset α) : - 2 * (s.offDiag.image (Quotient.mk _)).card = s.offDiag.card := by - rw [card_eq_sum_card_image (Quotient.mk _ : α × α → _), sum_const_nat (Quotient.ind' _), mul_comm] - rintro ⟨x, y⟩ hxy + 2 * (s.offDiag.image Sym2.mk).card = s.offDiag.card := by + rw [card_eq_sum_card_image (Sym2.mk : α × α → _), sum_const_nat (Sym2.ind _), mul_comm] + rintro x y hxy simp_rw [mem_image, mem_offDiag] at hxy obtain ⟨a, ⟨ha₁, ha₂, ha⟩, h⟩ := hxy - replace h := Quotient.eq.1 h + replace h := Sym2.eq.1 h obtain ⟨hx, hy, hxy⟩ : x ∈ s ∧ y ∈ s ∧ x ≠ y := by cases h <;> refine' ⟨‹_›, ‹_›, _⟩ <;> [exact ha; exact ha.symm] have hxy' : y ≠ x := hxy.symm - have : (s.offDiag.filter fun z => ⟦z⟧ = ⟦(x, y)⟧) = ({(x, y), (y, x)} : Finset _) := by + have : (s.offDiag.filter fun z => Sym2.mk z = s(x, y)) = ({(x, y), (y, x)} : Finset _) := by ext ⟨x₁, y₁⟩ rw [mem_filter, mem_insert, mem_singleton, Sym2.eq_iff, Prod.mk.inj_iff, Prod.mk.inj_iff, and_iff_right_iff_imp] -- `hxy'` is used in `exact` rintro (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩) <;> rw [mem_offDiag] <;> exact ⟨‹_›, ‹_›, ‹_›⟩ - dsimp only [Quotient.mk''_eq_mk] -- Porting note: Added `dsimp` rw [this, card_insert_of_not_mem, card_singleton] simp only [not_and, Prod.mk.inj_iff, mem_singleton] exact fun _ => hxy' #align sym2.two_mul_card_image_off_diag Sym2.two_mul_card_image_offDiag /-- The `offDiag` of `s : Finset α` is sent on a finset of `Sym2 α` of card `s.offDiag.card / 2`. -This is because every element `⟦(x, y)⟧` of `Sym2 α` not on the diagonal comes from exactly two +This is because every element `s(x, y)` of `Sym2 α` not on the diagonal comes from exactly two pairs: `(x, y)` and `(y, x)`. -/ theorem card_image_offDiag (s : Finset α) : - (s.offDiag.image (Quotient.mk _)).card = s.card.choose 2 := by + (s.offDiag.image Sym2.mk).card = s.card.choose 2 := by rw [Nat.choose_two_right, mul_tsub, mul_one, ← offDiag_card, Nat.div_eq_of_eq_mul_right zero_lt_two (two_mul_card_image_offDiag s).symm] #align sym2.card_image_off_diag Sym2.card_image_offDiag theorem card_subtype_diag [Fintype α] : card { a : Sym2 α // a.IsDiag } = card α := by convert card_image_diag (univ : Finset α) - -- Porting note (kmill): Quotient.mk and Quotient.mk'' are syntactically different. - -- `filter_image_quotient_mk''_isDiag` was part of rw - refine Eq.trans ?_ congr(Finset.card $(filter_image_quotient_mk''_isDiag univ)) - rw [Fintype.card_of_subtype] + rw [← filter_image_mk_isDiag, Fintype.card_of_subtype] rintro x rw [mem_filter, univ_product_univ, mem_image] - obtain ⟨a, ha⟩ := Quotient.exists_rep x + obtain ⟨a, ha⟩ := Quot.exists_rep x exact and_iff_right ⟨a, mem_univ _, ha⟩ #align sym2.card_subtype_diag Sym2.card_subtype_diag theorem card_subtype_not_diag [Fintype α] : card { a : Sym2 α // ¬a.IsDiag } = (card α).choose 2 := by convert card_image_offDiag (univ : Finset α) - -- Porting note (kmill): Quotient.mk and Quotient.mk'' are syntactically different. - -- `filter_image_quotient_mk''_not_isDiag` was part of rw - refine Eq.trans ?_ congr(Finset.card $(filter_image_quotient_mk''_not_isDiag univ)) - rw [Fintype.card_of_subtype] + rw [← filter_image_mk_not_isDiag, Fintype.card_of_subtype] rintro x rw [mem_filter, univ_product_univ, mem_image] - obtain ⟨a, ha⟩ := Quotient.exists_rep x + obtain ⟨a, ha⟩ := Quot.exists_rep x exact and_iff_right ⟨a, mem_univ _, ha⟩ #align sym2.card_subtype_not_diag Sym2.card_subtype_not_diag diff --git a/Mathlib/Data/Sym/Sym2.lean b/Mathlib/Data/Sym/Sym2.lean index cb6513f988586..2a462d17db1e2 100644 --- a/Mathlib/Data/Sym/Sym2.lean +++ b/Mathlib/Data/Sym/Sym2.lean @@ -37,19 +37,13 @@ constructed by `Sym2.fromRel` which is a special case of `Sym2.lift`. ## Notation -The symmetric square has a setoid instance, so `⟦(a, b)⟧` denotes a -term of the symmetric square. +The element `Sym2.mk (a, b)` can be written as `s(a, b)` for short. ## Tags symmetric square, unordered pairs, symmetric powers -/ - --- porting note: using `aesop` in place of `tidy` to simplify proofs --- porting note: remove import `Tactic.Linarith.Default` --- porting note: adding the above porting note here to avoid module docs linter error - open Finset Function Sym universe u @@ -58,15 +52,15 @@ variable {α β γ : Type*} namespace Sym2 -/-- This is the relation capturing the notion of pairs equivalent up to permutations. --/ +/-- This is the relation capturing the notion of pairs equivalent up to permutations. -/ @[aesop (rule_sets [Sym2]) [safe [constructors, cases], norm]] inductive Rel (α : Type u) : α × α → α × α → Prop | refl (x y : α) : Rel _ (x, y) (x, y) | swap (x y : α) : Rel _ (x, y) (y, x) #align sym2.rel Sym2.Rel +#align sym2.rel.refl Sym2.Rel.refl +#align sym2.rel.swap Sym2.Rel.swap --- porting note: somehow the name was not aligned attribute [refl] Rel.refl @[symm] @@ -79,16 +73,21 @@ theorem Rel.trans {x y z : α × α} (a : Rel α x y) (b : Rel α y z) : Rel α #align sym2.rel.trans Sym2.Rel.trans theorem Rel.is_equivalence : Equivalence (Rel α) := - { refl := fun (x, y)↦Rel.refl x y, symm := Rel.symm, trans := Rel.trans } + { refl := fun (x, y) ↦ Rel.refl x y, symm := Rel.symm, trans := Rel.trans } #align sym2.rel.is_equivalence Sym2.Rel.is_equivalence -instance Rel.setoid (α : Type u) : Setoid (α × α) := +/-- One can use `attribute [local instance] Sym2.Rel.setoid` to temporarily +make `Quotient` functionality work for `α × α`. -/ +def Rel.setoid (α : Type u) : Setoid (α × α) := ⟨Rel α, Rel.is_equivalence⟩ #align sym2.rel.setoid Sym2.Rel.setoid @[simp] -theorem rel_iff {x y z w : α} : (x, y) ≈ (z, w) ↔ x = z ∧ y = w ∨ x = w ∧ y = z := - show Rel _ _ _ ↔ _ by aesop (rule_sets [Sym2]) +theorem rel_iff' {p q : α × α} : Rel α p q ↔ p = q ∨ p = q.swap := by + aesop (rule_sets [Sym2]) + +theorem rel_iff {x y z w : α} : Rel α (x, y) (z, w) ↔ x = z ∧ y = w ∨ x = w ∧ y = z := by + simp #align sym2.rel_iff Sym2.rel_iff end Sym2 @@ -100,77 +99,100 @@ It is equivalent in a natural way to multisets of cardinality 2 (see `Sym2.equivMultiset`). -/ @[reducible] -def Sym2 (α : Type u) := - Quotient (Sym2.Rel.setoid α) +def Sym2 (α : Type u) := Quot (Sym2.Rel α) #align sym2 Sym2 +/-- Constructor for `Sym2`. This is the quotient map `α × α → Sym2 α`. -/ +protected abbrev Sym2.mk {α : Type*} (p : α × α) : Sym2 α := Quot.mk (Sym2.Rel α) p + +/-- `s(x, y)` is an unordered pair, +which is to say a pair modulo the action of the symmetric group. + +It is equal to `Sym2.mk (x, y)`. -/ +notation3 "s(" x ", " y ")" => Sym2.mk (x, y) + namespace Sym2 +protected theorem sound {p p' : α × α} (h : Sym2.Rel α p p') : Sym2.mk p = Sym2.mk p' := + Quot.sound h + +protected theorem exact {p p' : α × α} (h : Sym2.mk p = Sym2.mk p') : Sym2.Rel α p p' := + Quotient.exact (s := Sym2.Rel.setoid α) h + +@[simp] +protected theorem eq {p p' : α × α} : Sym2.mk p = Sym2.mk p' ↔ Sym2.Rel α p p' := + Quotient.eq' (s₁ := Sym2.Rel.setoid α) + @[elab_as_elim] -protected theorem ind {f : Sym2 α → Prop} (h : ∀ x y, f ⟦(x, y)⟧) : ∀ i, f i := - Quotient.ind <| Prod.rec <| h +protected theorem ind {f : Sym2 α → Prop} (h : ∀ x y, f s(x, y)) : ∀ i, f i := + Quot.ind <| Prod.rec <| h #align sym2.ind Sym2.ind @[elab_as_elim] -protected theorem inductionOn {f : Sym2 α → Prop} (i : Sym2 α) (hf : ∀ x y, f ⟦(x, y)⟧) : f i := +protected theorem inductionOn {f : Sym2 α → Prop} (i : Sym2 α) (hf : ∀ x y, f s(x, y)) : f i := i.ind hf #align sym2.induction_on Sym2.inductionOn @[elab_as_elim] protected theorem inductionOn₂ {f : Sym2 α → Sym2 β → Prop} (i : Sym2 α) (j : Sym2 β) - (hf : ∀ a₁ a₂ b₁ b₂, f ⟦(a₁, a₂)⟧ ⟦(b₁, b₂)⟧) : f i j := - Quotient.inductionOn₂ i j <| by + (hf : ∀ a₁ a₂ b₁ b₂, f s(a₁, a₂) s(b₁, b₂)) : f i j := + Quot.induction_on₂ i j <| by intro ⟨a₁, a₂⟩ ⟨b₁, b₂⟩ exact hf _ _ _ _ #align sym2.induction_on₂ Sym2.inductionOn₂ --- porting note: `exists` seems to be an invalid identifier +/-- Dependent recursion principal for `Sym2`. See `Quot.rec`. -/ +@[elab_as_elim] +protected def rec {motive : Sym2 α → Sort*} + (f : (p : α × α) → motive (Sym2.mk p)) + (h : (p q : α × α) → (h : Sym2.Rel α p q) → Eq.ndrec (f p) (Sym2.sound h) = f q) + (z : Sym2 α) : motive z := + Quot.rec f h z + +/-- Dependent recursion principal for `Sym2` when the target is a `Subsingleton` type. +See `Quot.recOnSubsingleton`. -/ +@[elab_as_elim] +protected abbrev recOnSubsingleton {motive : Sym2 α → Sort*} + [(p : α × α) → Subsingleton (motive (Sym2.mk p))] + (z : Sym2 α) (f : (p : α × α) → motive (Sym2.mk p)) : motive z := + Quot.recOnSubsingleton z f + protected theorem «exists» {α : Sort _} {f : Sym2 α → Prop} : - (∃ x : Sym2 α, f x) ↔ ∃ x y, f ⟦(x, y)⟧ := - (surjective_quotient_mk' _).exists.trans Prod.exists + (∃ x : Sym2 α, f x) ↔ ∃ x y, f s(x, y) := + (surjective_quot_mk _).exists.trans Prod.exists #align sym2.exists Sym2.exists --- porting note: `forall` seems to be an invalid identifier protected theorem «forall» {α : Sort _} {f : Sym2 α → Prop} : - (∀ x : Sym2 α, f x) ↔ ∀ x y, f ⟦(x, y)⟧ := - (surjective_quotient_mk' _).forall.trans Prod.forall + (∀ x : Sym2 α, f x) ↔ ∀ x y, f s(x, y) := + (surjective_quot_mk _).forall.trans Prod.forall #align sym2.forall Sym2.forall --- porting note: The `⟦⟧` notation does not infer the setoid structure automatically -theorem eq_swap {a b : α} : Eq (α := Sym2 α) ⟦(a, b)⟧ ⟦(b, a)⟧ := by - rw [Quotient.eq] - apply Rel.swap +theorem eq_swap {a b : α} : s(a, b) = s(b, a) := Quot.sound (Rel.swap _ _) #align sym2.eq_swap Sym2.eq_swap @[simp] -theorem mk''_prod_swap_eq {p : α × α} : Eq (α := Sym2 α) ⟦p.swap⟧ ⟦p⟧ := by +theorem mk_prod_swap_eq {p : α × α} : Sym2.mk p.swap = Sym2.mk p := by cases p exact eq_swap -#align sym2.mk_prod_swap_eq Sym2.mk''_prod_swap_eq +#align sym2.mk_prod_swap_eq Sym2.mk_prod_swap_eq -theorem congr_right {a b c : α} : Eq (α := Sym2 α) ⟦(a, b)⟧ ⟦(a, c)⟧ ↔ b = c := by - constructor <;> intro h - · rw [Quotient.eq] at h - cases h <;> rfl - rw [h] +theorem congr_right {a b c : α} : s(a, b) = s(a, c) ↔ b = c := by + simp (config := {contextual := true}) #align sym2.congr_right Sym2.congr_right -theorem congr_left {a b c : α} : Eq (α := Sym2 α) ⟦(b, a)⟧ ⟦(c, a)⟧ ↔ b = c := by - constructor <;> intro h - · rw [Quotient.eq] at h - cases h <;> rfl - rw [h] +theorem congr_left {a b c : α} : s(b, a) = s(c, a) ↔ b = c := by + simp (config := {contextual := true}) #align sym2.congr_left Sym2.congr_left -theorem eq_iff {x y z w : α} : Eq (α := Sym2 α) ⟦(x, y)⟧ ⟦(z, w)⟧ ↔ x = z ∧ y = w ∨ x = w ∧ y = z := +theorem eq_iff {x y z w : α} : s(x, y) = s(z, w) ↔ x = z ∧ y = w ∨ x = w ∧ y = z := by simp #align sym2.eq_iff Sym2.eq_iff -theorem mk''_eq_mk''_iff {p q : α × α} : Eq (α := Sym2 α) ⟦p⟧ ⟦q⟧ ↔ p = q ∨ p = q.swap := by +theorem mk_eq_mk_iff {p q : α × α} : Sym2.mk p = Sym2.mk q ↔ p = q ∨ p = q.swap := by cases p cases q simp only [eq_iff, Prod.mk.inj_iff, Prod.swap_prod_mk] -#align sym2.mk_eq_mk_iff Sym2.mk''_eq_mk''_iff +#align sym2.mk_eq_mk_iff Sym2.mk_eq_mk_iff /-- The universal property of `Sym2`; symmetric functions of two arguments are equivalent to functions from `Sym2`. Note that when `β` is `Prop`, it can sometimes be more convenient to use @@ -178,23 +200,23 @@ functions from `Sym2`. Note that when `β` is `Prop`, it can sometimes be more c def lift : { f : α → α → β // ∀ a₁ a₂, f a₁ a₂ = f a₂ a₁ } ≃ (Sym2 α → β) where toFun f := - Quotient.lift (uncurry ↑f) <| by + Quot.lift (uncurry ↑f) <| by rintro _ _ ⟨⟩ exacts [rfl, f.prop _ _] - invFun F := ⟨curry (F ∘ Quotient.mk''), fun a₁ a₂ => congr_arg F eq_swap⟩ + invFun F := ⟨curry (F ∘ Sym2.mk), fun a₁ a₂ => congr_arg F eq_swap⟩ left_inv f := Subtype.ext rfl right_inv F := funext <| Sym2.ind fun x y => rfl #align sym2.lift Sym2.lift @[simp] -theorem lift_mk'' (f : { f : α → α → β // ∀ a₁ a₂, f a₁ a₂ = f a₂ a₁ }) (a₁ a₂ : α) : - lift f ⟦(a₁, a₂)⟧ = (f : α → α → β) a₁ a₂ := +theorem lift_mk (f : { f : α → α → β // ∀ a₁ a₂, f a₁ a₂ = f a₂ a₁ }) (a₁ a₂ : α) : + lift f s(a₁, a₂) = (f : α → α → β) a₁ a₂ := rfl -#align sym2.lift_mk Sym2.lift_mk'' +#align sym2.lift_mk Sym2.lift_mk @[simp] theorem coe_lift_symm_apply (F : Sym2 α → β) (a₁ a₂ : α) : - (lift.symm F : α → α → β) a₁ a₂ = F ⟦(a₁, a₂)⟧ := + (lift.symm F : α → α → β) a₁ a₂ = F s(a₁, a₂) := rfl #align sym2.coe_lift_symm_apply Sym2.coe_lift_symm_apply @@ -205,12 +227,13 @@ def lift₂ : (Sym2 α → Sym2 β → γ) where toFun f := - Quotient.lift₂ (fun (a : α × α) (b : β × β) => f.1 a.1 a.2 b.1 b.2) + Quotient.lift₂ (s₁ := Sym2.Rel.setoid α) (s₂ := Sym2.Rel.setoid β) + (fun (a : α × α) (b : β × β) => f.1 a.1 a.2 b.1 b.2) (by rintro _ _ _ _ ⟨⟩ ⟨⟩ exacts [rfl, (f.2 _ _ _ _).2, (f.2 _ _ _ _).1, (f.2 _ _ _ _).1.trans (f.2 _ _ _ _).2]) invFun F := - ⟨fun a₁ a₂ b₁ b₂ => F ⟦(a₁, a₂)⟧ ⟦(b₁, b₂)⟧, fun a₁ a₂ b₁ b₂ => by + ⟨fun a₁ a₂ b₁ b₂ => F s(a₁, a₂) s(b₁, b₂), fun a₁ a₂ b₁ b₂ => by constructor exacts [congr_arg₂ F eq_swap rfl, congr_arg₂ F rfl eq_swap]⟩ left_inv f := Subtype.ext rfl @@ -218,29 +241,25 @@ def lift₂ : #align sym2.lift₂ Sym2.lift₂ @[simp] -theorem lift₂_mk'' +theorem lift₂_mk (f : { f : α → α → β → β → γ // ∀ a₁ a₂ b₁ b₂, f a₁ a₂ b₁ b₂ = f a₂ a₁ b₁ b₂ ∧ f a₁ a₂ b₁ b₂ = f a₁ a₂ b₂ b₁ }) - (a₁ a₂ : α) (b₁ b₂ : β) : lift₂ f ⟦(a₁, a₂)⟧ ⟦(b₁, b₂)⟧ = (f : α → α → β → β → γ) a₁ a₂ b₁ b₂ := + (a₁ a₂ : α) (b₁ b₂ : β) : lift₂ f s(a₁, a₂) s(b₁, b₂) = (f : α → α → β → β → γ) a₁ a₂ b₁ b₂ := rfl -#align sym2.lift₂_mk Sym2.lift₂_mk'' +#align sym2.lift₂_mk Sym2.lift₂_mk @[simp] theorem coe_lift₂_symm_apply (F : Sym2 α → Sym2 β → γ) (a₁ a₂ : α) (b₁ b₂ : β) : - (lift₂.symm F : α → α → β → β → γ) a₁ a₂ b₁ b₂ = F ⟦(a₁, a₂)⟧ ⟦(b₁, b₂)⟧ := + (lift₂.symm F : α → α → β → β → γ) a₁ a₂ b₁ b₂ = F s(a₁, a₂) s(b₁, b₂) := rfl #align sym2.coe_lift₂_symm_apply Sym2.coe_lift₂_symm_apply /-- The functor `Sym2` is functorial, and this function constructs the induced maps. -/ def map (f : α → β) : Sym2 α → Sym2 β := - Quotient.map (Prod.map f f) - (by - intro _ _ h - cases h - · constructor - apply Rel.swap) + Quot.map (Prod.map f f) + (by intro _ _ h; cases h <;> constructor) #align sym2.map Sym2.map @[simp] @@ -259,17 +278,14 @@ theorem map_map {g : β → γ} {f : α → β} (x : Sym2 α) : map g (map f x) #align sym2.map_map Sym2.map_map @[simp] -theorem map_pair_eq (f : α → β) (x y : α) : map f ⟦(x, y)⟧ = ⟦(f x, f y)⟧ := +theorem map_pair_eq (f : α → β) (x y : α) : map f s(x, y) = s(f x, f y) := rfl #align sym2.map_pair_eq Sym2.map_pair_eq theorem map.injective {f : α → β} (hinj : Injective f) : Injective (map f) := by intro z z' - refine' Quotient.ind₂ (fun z z' => _) z z' - cases' z with x y - cases' z' with x' y' - repeat' rw [map_pair_eq, eq_iff] - rintro (h | h) <;> simp [hinj h.1, hinj h.2] + refine Sym2.inductionOn₂ z z' (fun x y x' y' => ?_) + simp [hinj.eq_iff] #align sym2.map.injective Sym2.map.injective section Membership @@ -282,11 +298,11 @@ symmetric square. From this point of view, the symmetric square is the subtype cardinality-two multisets on `α`. -/ protected def Mem (x : α) (z : Sym2 α) : Prop := - ∃ y : α, z = ⟦(x, y)⟧ + ∃ y : α, z = s(x, y) #align sym2.mem Sym2.Mem @[aesop norm (rule_sets [Sym2])] -theorem mem_iff' {a b c : α} : Sym2.Mem a ⟦(b, c)⟧ ↔ a = b ∨ a = c := +theorem mem_iff' {a b c : α} : Sym2.Mem a s(b, c) ↔ a = b ∨ a = c := { mp := by rintro ⟨_, h⟩ rw [eq_iff] at h @@ -314,7 +330,7 @@ theorem mem_iff_mem {x : α} {z : Sym2 α} : Sym2.Mem x z ↔ x ∈ z := Iff.rfl #align sym2.mem_iff_mem Sym2.mem_iff_mem -theorem mem_iff_exists {x : α} {z : Sym2 α} : x ∈ z ↔ ∃ y : α, z = ⟦(x, y)⟧ := +theorem mem_iff_exists {x : α} {z : Sym2 α} : x ∈ z ↔ ∃ y : α, z = s(x, y) := Iff.rfl #align sym2.mem_iff_exists Sym2.mem_iff_exists @@ -323,29 +339,29 @@ theorem ext {p q : Sym2 α} (h : ∀ x, x ∈ p ↔ x ∈ q) : p = q := SetLike.ext h #align sym2.ext Sym2.ext -theorem mem_mk''_left (x y : α) : x ∈ (⟦(x, y)⟧ : Sym2 α) := +theorem mem_mk_left (x y : α) : x ∈ s(x, y) := ⟨y, rfl⟩ -#align sym2.mem_mk_left Sym2.mem_mk''_left +#align sym2.mem_mk_left Sym2.mem_mk_left -theorem mem_mk''_right (x y : α) : y ∈ (⟦(x, y)⟧ : Sym2 α) := - eq_swap.subst <| mem_mk''_left y x -#align sym2.mem_mk_right Sym2.mem_mk''_right +theorem mem_mk_right (x y : α) : y ∈ s(x, y) := + eq_swap.subst <| mem_mk_left y x +#align sym2.mem_mk_right Sym2.mem_mk_right @[simp, aesop norm (rule_sets [Sym2])] -theorem mem_iff {a b c : α} : a ∈ (⟦(b, c)⟧ : Sym2 α) ↔ a = b ∨ a = c := +theorem mem_iff {a b c : α} : a ∈ s(b, c) ↔ a = b ∨ a = c := mem_iff' #align sym2.mem_iff Sym2.mem_iff theorem out_fst_mem (e : Sym2 α) : e.out.1 ∈ e := - ⟨e.out.2, by rw [e.out_eq]⟩ + ⟨e.out.2, by rw [Sym2.mk, e.out_eq]⟩ #align sym2.out_fst_mem Sym2.out_fst_mem theorem out_snd_mem (e : Sym2 α) : e.out.2 ∈ e := - ⟨e.out.1, by rw [eq_swap, e.out_eq]⟩ + ⟨e.out.1, by rw [eq_swap, Sym2.mk, e.out_eq]⟩ #align sym2.out_snd_mem Sym2.out_snd_mem -theorem ball {p : α → Prop} {a b : α} : (∀ c ∈ (⟦(a, b)⟧ : Sym2 α), p c) ↔ p a ∧ p b := by - refine' ⟨fun h => ⟨h _ <| mem_mk''_left _ _, h _ <| mem_mk''_right _ _⟩, fun h c hc => _⟩ +theorem ball {p : α → Prop} {a b : α} : (∀ c ∈ s(a, b), p c) ↔ p a ∧ p b := by + refine' ⟨fun h => ⟨h _ <| mem_mk_left _ _, h _ <| mem_mk_right _ _⟩, fun h c hc => _⟩ obtain rfl | rfl := Sym2.mem_iff.1 hc · exact h.1 · exact h.2 @@ -359,16 +375,16 @@ noncomputable def Mem.other {a : α} {z : Sym2 α} (h : a ∈ z) : α := #align sym2.mem.other Sym2.Mem.other @[simp] -theorem other_spec {a : α} {z : Sym2 α} (h : a ∈ z) : ⟦(a, Mem.other h)⟧ = z := by +theorem other_spec {a : α} {z : Sym2 α} (h : a ∈ z) : s(a, Mem.other h) = z := by erw [← Classical.choose_spec h] #align sym2.other_spec Sym2.other_spec theorem other_mem {a : α} {z : Sym2 α} (h : a ∈ z) : Mem.other h ∈ z := by - convert mem_mk''_right a <| Mem.other h + convert mem_mk_right a <| Mem.other h rw [other_spec h] #align sym2.other_mem Sym2.other_mem -theorem mem_and_mem_iff {x y : α} {z : Sym2 α} (hne : x ≠ y) : x ∈ z ∧ y ∈ z ↔ z = ⟦(x, y)⟧ := by +theorem mem_and_mem_iff {x y : α} {z : Sym2 α} (hne : x ≠ y) : x ∈ z ∧ y ∈ z ↔ z = s(x, y) := by constructor · induction' z using Sym2.ind with x' y' rw [mem_iff, mem_iff] @@ -383,7 +399,7 @@ theorem eq_of_ne_mem {x y : α} {z z' : Sym2 α} (h : x ≠ y) (h1 : x ∈ z) (h #align sym2.eq_of_ne_mem Sym2.eq_of_ne_mem instance Mem.decidable [DecidableEq α] (x : α) (z : Sym2 α) : Decidable (x ∈ z) := - Quotient.recOnSubsingleton z fun ⟨_, _⟩ => decidable_of_iff' _ mem_iff + z.recOnSubsingleton fun ⟨_, _⟩ => decidable_of_iff' _ mem_iff #align sym2.mem.decidable Sym2.Mem.decidable end Membership @@ -391,12 +407,8 @@ end Membership @[simp] theorem mem_map {f : α → β} {b : β} {z : Sym2 α} : b ∈ Sym2.map f z ↔ ∃ a, a ∈ z ∧ f a = b := by induction' z using Sym2.ind with x y - simp only [map, Quotient.map_mk, Prod.map_mk, mem_iff] - constructor - · rintro (rfl | rfl) - · exact ⟨x, by simp⟩ - · exact ⟨y, by simp⟩ - · rintro ⟨w, rfl | rfl, rfl⟩ <;> simp + simp only [map_pair_eq, mem_iff, exists_eq_or_imp, exists_eq_left] + aesop #align sym2.mem_map Sym2.mem_map @[congr] @@ -421,12 +433,11 @@ variable {e : Sym2 α} {f : α → β} /-- A type `α` is naturally included in the diagonal of `α × α`, and this function gives the image of this diagonal in `Sym2 α`. -/ -def diag (x : α) : Sym2 α := - ⟦(x, x)⟧ +def diag (x : α) : Sym2 α := s(x, x) #align sym2.diag Sym2.diag theorem diag_injective : Function.Injective (Sym2.diag : α → Sym2 α) := fun x y h => by - cases Quotient.exact h <;> rfl + cases Sym2.exact h <;> rfl #align sym2.diag_injective Sym2.diag_injective /-- A predicate for testing whether an element of `Sym2 α` is on the diagonal. @@ -435,13 +446,13 @@ def IsDiag : Sym2 α → Prop := lift ⟨Eq, fun _ _ => propext eq_comm⟩ #align sym2.is_diag Sym2.IsDiag -theorem mk''_isDiag_iff {x y : α} : IsDiag ⟦(x, y)⟧ ↔ x = y := +theorem mk_isDiag_iff {x y : α} : IsDiag s(x, y) ↔ x = y := Iff.rfl -#align sym2.mk_is_diag_iff Sym2.mk''_isDiag_iff +#align sym2.mk_is_diag_iff Sym2.mk_isDiag_iff @[simp] -theorem isDiag_iff_proj_eq (z : α × α) : IsDiag ⟦z⟧ ↔ z.1 = z.2 := - Prod.recOn z fun _ _ => mk''_isDiag_iff +theorem isDiag_iff_proj_eq (z : α × α) : IsDiag (Sym2.mk z) ↔ z.1 = z.2 := + Prod.recOn z fun _ _ => mk_isDiag_iff #align sym2.is_diag_iff_proj_eq Sym2.isDiag_iff_proj_eq protected lemma IsDiag.map : e.IsDiag → (e.map f).IsDiag := Sym2.ind (fun _ _ ↦ congr_arg f) e @@ -464,10 +475,8 @@ theorem isDiag_iff_mem_range_diag (z : Sym2 α) : IsDiag z ↔ z ∈ Set.range ( ⟨IsDiag.mem_range_diag, fun ⟨i, hi⟩ => hi ▸ diag_isDiag i⟩ #align sym2.is_diag_iff_mem_range_diag Sym2.isDiag_iff_mem_range_diag -instance IsDiag.decidablePred (α : Type u) [DecidableEq α] : DecidablePred (@IsDiag α) := by - refine' fun z => Quotient.recOnSubsingleton z fun a => _ - erw [isDiag_iff_proj_eq] - infer_instance +instance IsDiag.decidablePred (α : Type u) [DecidableEq α] : DecidablePred (@IsDiag α) := + fun z => z.recOnSubsingleton fun a => decidable_of_iff' _ (isDiag_iff_proj_eq a) #align sym2.is_diag.decidable_pred Sym2.IsDiag.decidablePred theorem other_ne {a : α} {z : Sym2 α} (hd : ¬IsDiag z) (h : a ∈ z) : Mem.other h ≠ a := by @@ -493,13 +502,11 @@ def fromRel (sym : Symmetric r) : Set (Sym2 α) := #align sym2.from_rel Sym2.fromRel @[simp] -theorem fromRel_proj_prop {sym : Symmetric r} {z : α × α} : ⟦z⟧ ∈ fromRel sym ↔ r z.1 z.2 := +theorem fromRel_proj_prop {sym : Symmetric r} {z : α × α} : Sym2.mk z ∈ fromRel sym ↔ r z.1 z.2 := Iff.rfl #align sym2.from_rel_proj_prop Sym2.fromRel_proj_prop --- porting note: commenting out `simp`, `simp` can prove it --- @[simp] -theorem fromRel_prop {sym : Symmetric r} {a b : α} : ⟦(a, b)⟧ ∈ fromRel sym ↔ r a b := +theorem fromRel_prop {sym : Symmetric r} {a b : α} : s(a, b) ∈ fromRel sym ↔ r a b := Iff.rfl #align sym2.from_rel_prop Sym2.fromRel_prop @@ -530,17 +537,17 @@ theorem mem_fromRel_irrefl_other_ne {sym : Symmetric r} (irrefl : Irreflexive r) #align sym2.mem_from_rel_irrefl_other_ne Sym2.mem_fromRel_irrefl_other_ne instance fromRel.decidablePred (sym : Symmetric r) [h : DecidableRel r] : - DecidablePred (· ∈ Sym2.fromRel sym) := fun z => Quotient.recOnSubsingleton z fun _ => h _ _ + DecidablePred (· ∈ Sym2.fromRel sym) := fun z => z.recOnSubsingleton fun _ => h _ _ #align sym2.from_rel.decidable_pred Sym2.fromRel.decidablePred /-- The inverse to `Sym2.fromRel`. Given a set on `Sym2 α`, give a symmetric relation on `α` (see `Sym2.toRel_symmetric`). -/ def ToRel (s : Set (Sym2 α)) (x y : α) : Prop := - ⟦(x, y)⟧ ∈ s + s(x, y) ∈ s #align sym2.to_rel Sym2.ToRel @[simp] -theorem toRel_prop (s : Set (Sym2 α)) (x y : α) : ToRel s x y ↔ ⟦(x, y)⟧ ∈ s := +theorem toRel_prop (s : Set (Sym2 α)) (x y : α) : ToRel s x y ↔ s(x, y) ∈ s := Iff.rfl #align sym2.to_rel_prop Sym2.toRel_prop @@ -566,7 +573,6 @@ attribute [local instance] Vector.Perm.isSetoid private def fromVector : Vector α 2 → α × α | ⟨[a, b], _⟩ => (a, b) --- porting note: remove alignment for private definition private theorem perm_card_two_iff {a₁ b₁ a₂ b₂ : α} : [a₁, b₁].Perm [a₂, b₂] ↔ a₁ = a₂ ∧ b₁ = b₂ ∨ a₁ = b₂ ∧ b₁ = a₂ := @@ -579,21 +585,19 @@ private theorem perm_card_two_iff {a₁ b₁ a₂ b₂ : α} : | .inl ⟨h₁, h₂⟩ | .inr ⟨h₁, h₂⟩ => by rw [h₁, h₂] first | done | apply List.Perm.swap'; rfl } --- porting note: remove alignment for private theorem -/-- The symmetric square is equivalent to length-2 vectors up to permutations. --/ +/-- The symmetric square is equivalent to length-2 vectors up to permutations. -/ def sym2EquivSym' : Equiv (Sym2 α) (Sym' α 2) where toFun := - Quotient.map (fun x : α × α => ⟨[x.1, x.2], rfl⟩) + Quot.map (fun x : α × α => ⟨[x.1, x.2], rfl⟩) (by rintro _ _ ⟨_⟩ · constructor; apply List.Perm.refl apply List.Perm.swap' rfl) invFun := - Quotient.map fromVector + Quot.map fromVector (by rintro ⟨x, hx⟩ ⟨y, hy⟩ h cases' x with _ x; · simp at hx @@ -611,7 +615,7 @@ def sym2EquivSym' : Equiv (Sym2 α) (Sym' α 2) apply Sym2.Rel.swap) left_inv := by apply Sym2.ind; aesop (add norm unfold [Sym2.fromVector]) right_inv x := by - refine' Quotient.recOnSubsingleton x fun x => _ + refine' x.recOnSubsingleton fun x => _ · cases' x with x hx cases' x with _ x · simp at hx @@ -624,16 +628,14 @@ def sym2EquivSym' : Equiv (Sym2 α) (Sym' α 2) rfl #align sym2.sym2_equiv_sym' Sym2.sym2EquivSym' -/-- The symmetric square is equivalent to the second symmetric power. --/ +/-- The symmetric square is equivalent to the second symmetric power. -/ def equivSym (α : Type*) : Sym2 α ≃ Sym α 2 := Equiv.trans sym2EquivSym' symEquivSym'.symm #align sym2.equiv_sym Sym2.equivSym /-- The symmetric square is equivalent to multisets of cardinality two. (This is currently a synonym for `equivSym`, but it's provided -in case the definition for `Sym` changes.) --/ +in case the definition for `Sym` changes.) -/ def equivMultiset (α : Type*) : Sym2 α ≃ { s : Multiset α // Multiset.card s = 2 } := equivSym α #align sym2.equiv_multiset Sym2.equivMultiset @@ -650,11 +652,16 @@ section Decidable instance instDecidableRel [DecidableEq α] : DecidableRel (Rel α) := fun _ _ => decidable_of_iff' _ rel_iff +section +attribute [local instance] Sym2.Rel.setoid + instance instDecidableRel' [DecidableEq α] : DecidableRel (HasEquiv.Equiv (α := α × α)) := instDecidableRel --- the `Equiv` version above is needed for this -example [DecidableEq α] : DecidableEq (Sym2 α) := inferInstance +end + +instance [DecidableEq α] : DecidableEq (Sym2 α) := + inferInstanceAs <| DecidableEq (Quotient (Sym2.Rel.setoid α)) /-! ### The other element of an element of the symmetric square -/ @@ -665,19 +672,18 @@ A function that gives the other element of a pair given one of the elements. Us @[aesop norm unfold (rule_sets [Sym2])] private def pairOther [DecidableEq α] (a : α) (z : α × α) : α := if a = z.1 then z.2 else z.1 --- porting note: remove align for private def + /-- Get the other element of the unordered pair using the decidable equality. -This is the computable version of `Mem.other`. --/ +This is the computable version of `Mem.other`. -/ @[aesop norm unfold (rule_sets [Sym2])] def Mem.other' [DecidableEq α] {a : α} {z : Sym2 α} (h : a ∈ z) : α := - Quotient.rec (fun s _ => pairOther a s) (by + Sym2.rec (fun s _ => pairOther a s) (by clear h z intro x y h ext hy convert_to Sym2.pairOther a x = _ - · have : ∀ {c e h}, @Eq.ndrec (Quotient (Rel.setoid α)) (Quotient.mk (Rel.setoid α) x) + · have : ∀ {c e h}, @Eq.ndrec (Sym2 α) (Sym2.mk x) (fun x => a ∈ x → α) (fun _ => Sym2.pairOther a x) c e h = Sym2.pairOther a x := by intro _ e _; subst e; rfl apply this @@ -687,10 +693,10 @@ def Mem.other' [DecidableEq α] {a : α} {z : Sym2 α} (h : a ∈ z) : α := #align sym2.mem.other' Sym2.Mem.other' @[simp] -theorem other_spec' [DecidableEq α] {a : α} {z : Sym2 α} (h : a ∈ z) : ⟦(a, Mem.other' h)⟧ = z := by +theorem other_spec' [DecidableEq α] {a : α} {z : Sym2 α} (h : a ∈ z) : s(a, Mem.other' h) = z := by induction z using Sym2.ind have h' := mem_iff.mp h - aesop (add norm unfold [Quotient.rec, Quot.rec]) (rule_sets [Sym2]) + aesop (add norm unfold [Sym2.rec, Quot.rec]) (rule_sets [Sym2]) #align sym2.other_spec' Sym2.other_spec' @[simp] @@ -706,7 +712,7 @@ theorem other_mem' [DecidableEq α] {a : α} {z : Sym2 α} (h : a ∈ z) : Mem.o theorem other_invol' [DecidableEq α] {a : α} {z : Sym2 α} (ha : a ∈ z) (hb : Mem.other' ha ∈ z) : Mem.other' hb = a := by induction z using Sym2.ind - aesop (rule_sets [Sym2]) (add norm unfold [Quotient.rec, Quot.rec]) + aesop (rule_sets [Sym2]) (add norm unfold [Sym2.rec, Quot.rec]) #align sym2.other_invol' Sym2.other_invol' theorem other_invol {a : α} {z : Sym2 α} (ha : a ∈ z) (hb : Mem.other ha ∈ z) : Mem.other hb = a := @@ -716,34 +722,34 @@ theorem other_invol {a : α} {z : Sym2 α} (ha : a ∈ z) (hb : Mem.other ha ∈ apply other_eq_other' #align sym2.other_invol Sym2.other_invol -theorem filter_image_quotient_mk''_isDiag [DecidableEq α] (s : Finset α) : - ((s ×ˢ s).image Quotient.mk'').filter IsDiag = s.diag.image Quotient.mk'' := by +theorem filter_image_mk_isDiag [DecidableEq α] (s : Finset α) : + ((s ×ˢ s).image Sym2.mk).filter IsDiag = s.diag.image Sym2.mk := by ext z induction' z using Sym2.inductionOn simp only [mem_image, mem_diag, exists_prop, mem_filter, Prod.exists, mem_product] constructor - · rintro ⟨⟨a, b, ⟨ha, hb⟩, (h : Quotient.mk _ _ = _)⟩, hab⟩ - rw [← h, Sym2.mk''_isDiag_iff] at hab + · rintro ⟨⟨a, b, ⟨ha, hb⟩, h⟩, hab⟩ + rw [← h, Sym2.mk_isDiag_iff] at hab exact ⟨a, b, ⟨ha, hab⟩, h⟩ · rintro ⟨a, b, ⟨ha, rfl⟩, h⟩ rw [← h] exact ⟨⟨a, a, ⟨ha, ha⟩, rfl⟩, rfl⟩ -#align sym2.filter_image_quotient_mk_is_diag Sym2.filter_image_quotient_mk''_isDiag +#align sym2.filter_image_quotient_mk_is_diag Sym2.filter_image_mk_isDiag -theorem filter_image_quotient_mk''_not_isDiag [DecidableEq α] (s : Finset α) : - (((s ×ˢ s).image Quotient.mk'').filter fun a : Sym2 α => ¬a.IsDiag) = - s.offDiag.image Quotient.mk'' := by +theorem filter_image_mk_not_isDiag [DecidableEq α] (s : Finset α) : + (((s ×ˢ s).image Sym2.mk).filter fun a : Sym2 α => ¬a.IsDiag) = + s.offDiag.image Sym2.mk := by ext z induction z using Sym2.inductionOn simp only [mem_image, mem_offDiag, mem_filter, Prod.exists, mem_product] constructor - · rintro ⟨⟨a, b, ⟨ha, hb⟩, (h : Quotient.mk _ _ = _)⟩, hab⟩ - rw [← h, Sym2.mk''_isDiag_iff] at hab + · rintro ⟨⟨a, b, ⟨ha, hb⟩, h⟩, hab⟩ + rw [← h, Sym2.mk_isDiag_iff] at hab exact ⟨a, b, ⟨ha, hb, hab⟩, h⟩ - · rintro ⟨a, b, ⟨ha, hb, hab⟩, (h : Quotient.mk _ _ = _)⟩ - rw [Ne.def, ← Sym2.mk''_isDiag_iff, h] at hab + · rintro ⟨a, b, ⟨ha, hb, hab⟩, h⟩ + rw [Ne.def, ← Sym2.mk_isDiag_iff, h] at hab exact ⟨⟨a, b, ⟨ha, hb⟩, h⟩, hab⟩ -#align sym2.filter_image_quotient_mk_not_is_diag Sym2.filter_image_quotient_mk''_not_isDiag +#align sym2.filter_image_quotient_mk_not_is_diag Sym2.filter_image_mk_not_isDiag end Decidable diff --git a/Mathlib/Order/GameAdd.lean b/Mathlib/Order/GameAdd.lean index c2d66053d34b7..428022e59af62 100644 --- a/Mathlib/Order/GameAdd.lean +++ b/Mathlib/Order/GameAdd.lean @@ -161,37 +161,37 @@ def GameAdd (rα : α → α → Prop) : Sym2 α → Sym2 α → Prop := simp [or_comm]⟩ #align sym2.game_add Sym2.GameAdd -theorem gameAdd_iff : - ∀ {x y : α × α}, GameAdd rα ⟦x⟧ ⟦y⟧ ↔ Prod.GameAdd rα rα x y ∨ Prod.GameAdd rα rα x.swap y := by +theorem gameAdd_iff : ∀ {x y : α × α}, + GameAdd rα (Sym2.mk x) (Sym2.mk y) ↔ Prod.GameAdd rα rα x y ∨ Prod.GameAdd rα rα x.swap y := by rintro ⟨_, _⟩ ⟨_, _⟩ rfl #align sym2.game_add_iff Sym2.gameAdd_iff theorem gameAdd_mk'_iff {a₁ a₂ b₁ b₂ : α} : - GameAdd rα ⟦(a₁, b₁)⟧ ⟦(a₂, b₂)⟧ ↔ + GameAdd rα s(a₁, b₁) s(a₂, b₂) ↔ Prod.GameAdd rα rα (a₁, b₁) (a₂, b₂) ∨ Prod.GameAdd rα rα (b₁, a₁) (a₂, b₂) := Iff.rfl #align sym2.game_add_mk_iff Sym2.gameAdd_mk'_iff theorem _root_.Prod.GameAdd.to_sym2 {a₁ a₂ b₁ b₂ : α} (h : Prod.GameAdd rα rα (a₁, b₁) (a₂, b₂)) : - Sym2.GameAdd rα ⟦(a₁, b₁)⟧ ⟦(a₂, b₂)⟧ := + Sym2.GameAdd rα s(a₁, b₁) s(a₂, b₂) := gameAdd_mk'_iff.2 <| Or.inl <| h #align prod.game_add.to_sym2 Prod.GameAdd.to_sym2 -theorem GameAdd.fst {a₁ a₂ b : α} (h : rα a₁ a₂) : GameAdd rα ⟦(a₁, b)⟧ ⟦(a₂, b)⟧ := +theorem GameAdd.fst {a₁ a₂ b : α} (h : rα a₁ a₂) : GameAdd rα s(a₁, b) s(a₂, b) := (Prod.GameAdd.fst h).to_sym2 #align sym2.game_add.fst Sym2.GameAdd.fst -theorem GameAdd.snd {a b₁ b₂ : α} (h : rα b₁ b₂) : GameAdd rα ⟦(a, b₁)⟧ ⟦(a, b₂)⟧ := +theorem GameAdd.snd {a b₁ b₂ : α} (h : rα b₁ b₂) : GameAdd rα s(a, b₁) s(a, b₂) := (Prod.GameAdd.snd h).to_sym2 #align sym2.game_add.snd Sym2.GameAdd.snd -theorem GameAdd.fst_snd {a₁ a₂ b : α} (h : rα a₁ a₂) : GameAdd rα ⟦(a₁, b)⟧ ⟦(b, a₂)⟧ := by +theorem GameAdd.fst_snd {a₁ a₂ b : α} (h : rα a₁ a₂) : GameAdd rα s(a₁, b) s(b, a₂) := by rw [Sym2.eq_swap] exact GameAdd.snd h #align sym2.game_add.fst_snd Sym2.GameAdd.fst_snd -theorem GameAdd.snd_fst {a₁ a₂ b : α} (h : rα a₁ a₂) : GameAdd rα ⟦(b, a₁)⟧ ⟦(a₂, b)⟧ := by +theorem GameAdd.snd_fst {a₁ a₂ b : α} (h : rα a₁ a₂) : GameAdd rα s(b, a₁) s(a₂, b) := by rw [Sym2.eq_swap] exact GameAdd.fst h #align sym2.game_add.snd_fst Sym2.GameAdd.snd_fst @@ -199,7 +199,7 @@ theorem GameAdd.snd_fst {a₁ a₂ b : α} (h : rα a₁ a₂) : GameAdd rα ⟦ end Sym2 theorem Acc.sym2_gameAdd {a b} (ha : Acc rα a) (hb : Acc rα b) : - Acc (Sym2.GameAdd rα) ⟦(a, b)⟧ := by + Acc (Sym2.GameAdd rα) s(a, b) := by induction' ha with a _ iha generalizing b induction' hb with b hb ihb refine' Acc.intro _ fun s => _ @@ -222,9 +222,11 @@ theorem WellFounded.sym2_gameAdd (h : WellFounded rα) : WellFounded (Sym2.GameA namespace Sym2 +attribute [local instance] Sym2.Rel.setoid + /-- Recursion on the well-founded `Sym2.GameAdd` relation. -/ def GameAdd.fix {C : α → α → Sort*} (hr : WellFounded rα) - (IH : ∀ a₁ b₁, (∀ a₂ b₂, Sym2.GameAdd rα ⟦(a₂, b₂)⟧ ⟦(a₁, b₁)⟧ → C a₂ b₂) → C a₁ b₁) (a b : α) : + (IH : ∀ a₁ b₁, (∀ a₂ b₂, Sym2.GameAdd rα s(a₂, b₂) s(a₁, b₁) → C a₂ b₂) → C a₁ b₁) (a b : α) : C a b := by -- Porting note: this was refactored for #3414 (reenableeta), and could perhaps be cleaned up. have := hr.sym2_gameAdd @@ -234,7 +236,7 @@ def GameAdd.fix {C : α → α → Sort*} (hr : WellFounded rα) #align sym2.game_add.fix Sym2.GameAdd.fix theorem GameAdd.fix_eq {C : α → α → Sort*} (hr : WellFounded rα) - (IH : ∀ a₁ b₁, (∀ a₂ b₂, Sym2.GameAdd rα ⟦(a₂, b₂)⟧ ⟦(a₁, b₁)⟧ → C a₂ b₂) → C a₁ b₁) (a b : α) : + (IH : ∀ a₁ b₁, (∀ a₂ b₂, Sym2.GameAdd rα s(a₂, b₂) s(a₁, b₁) → C a₂ b₂) → C a₁ b₁) (a b : α) : GameAdd.fix hr IH a b = IH a b fun a' b' _ => GameAdd.fix hr IH a' b' := by -- Porting note: this was refactored for #3414 (reenableeta), and could perhaps be cleaned up. dsimp [GameAdd.fix] @@ -244,7 +246,7 @@ theorem GameAdd.fix_eq {C : α → α → Sort*} (hr : WellFounded rα) /-- Induction on the well-founded `Sym2.GameAdd` relation. -/ theorem GameAdd.induction {C : α → α → Prop} : WellFounded rα → - (∀ a₁ b₁, (∀ a₂ b₂, Sym2.GameAdd rα ⟦(a₂, b₂)⟧ ⟦(a₁, b₁)⟧ → C a₂ b₂) → C a₁ b₁) → + (∀ a₁ b₁, (∀ a₂ b₂, Sym2.GameAdd rα s(a₂, b₂) s(a₁, b₁) → C a₂ b₂) → C a₁ b₁) → ∀ a b, C a b := GameAdd.fix #align sym2.game_add.induction Sym2.GameAdd.induction From 9623806f920b77d44e91162f0a6fb2d661476181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 05:26:41 +0000 Subject: [PATCH 226/353] feat(Algebra/Homology): API for the computation of the homology of homological complexes (#8845) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR introduces more homology API in order to ease the computation of group cohomology in low degrees #8802. The main definition `HomologicalComplex.homologyIsoSc' : K.homology j ≅ (K.sc' i j k).homology` relates the homology of a complex `K` in degree `j` to the homology of a short complex `K.X i ⟶ K.X j ⟶ K.X k` when `i` and `k` are degrees which appear respectively before `j` and after `j`. --- .../ShortComplex/HomologicalComplex.lean | 91 +++++++++++++++++++ .../Homology/ShortComplex/ModuleCat.lean | 48 +++++++++- 2 files changed, 135 insertions(+), 4 deletions(-) diff --git a/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean b/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean index a6c1637262aa5..75db007623634 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean @@ -697,3 +697,94 @@ lemma isIso_descOpcycles_iff (K : ChainComplex C ℕ) {X : C} (φ : K.X 0 ⟶ X) (ShortComplex.quasiIso_iff_of_zeros' α (by simp) rfl rfl) end ChainComplex + +namespace HomologicalComplex + +variable {C : Type*} [Category C] [HasZeroMorphisms C] {ι : Type*} {c : ComplexShape ι} + (K : HomologicalComplex C c) + (i j k : ι) (hi : c.prev j = i) (hk : c.next j = k) + [K.HasHomology j] [(K.sc' i j k).HasHomology] + +/-- The cycles of a homological complex in degree `j` can be computed +by specifying a choice of `c.prev j` and `c.next j`. -/ +noncomputable def cyclesIsoSc' : K.cycles j ≅ (K.sc' i j k).cycles := + ShortComplex.cyclesMapIso (K.isoSc' i j k hi hk) + +@[reassoc (attr := simp)] +lemma cyclesIsoSc'_hom_iCycles : + (K.cyclesIsoSc' i j k hi hk).hom ≫ (K.sc' i j k).iCycles = K.iCycles j := by + dsimp [cyclesIsoSc'] + simp only [ShortComplex.cyclesMap_i, shortComplexFunctor_obj_X₂, shortComplexFunctor'_obj_X₂, + natIsoSc'_hom_app_τ₂, comp_id] + rfl + +@[reassoc (attr := simp)] +lemma cyclesIsoSc'_inv_iCycles : + (K.cyclesIsoSc' i j k hi hk).inv ≫ K.iCycles j = (K.sc' i j k).iCycles := by + dsimp [cyclesIsoSc'] + erw [ShortComplex.cyclesMap_i] + apply comp_id + +@[reassoc (attr := simp)] +lemma toCycles_cyclesIsoSc'_hom : + K.toCycles i j ≫ (K.cyclesIsoSc' i j k hi hk).hom = (K.sc' i j k).toCycles := by + simp only [← cancel_mono (K.sc' i j k).iCycles, assoc, cyclesIsoSc'_hom_iCycles, + toCycles_i, ShortComplex.toCycles_i, shortComplexFunctor'_obj_f] + +/-- The homology of a homological complex in degree `j` can be computed +by specifying a choice of `c.prev j` and `c.next j`. -/ +noncomputable def opcyclesIsoSc' : K.opcycles j ≅ (K.sc' i j k).opcycles := + ShortComplex.opcyclesMapIso (K.isoSc' i j k hi hk) + +@[reassoc (attr := simp)] +lemma pOpcycles_opcyclesIsoSc'_inv : + (K.sc' i j k).pOpcycles ≫ (K.opcyclesIsoSc' i j k hi hk).inv = K.pOpcycles j := by + dsimp [opcyclesIsoSc'] + simp only [ShortComplex.p_opcyclesMap, shortComplexFunctor'_obj_X₂, shortComplexFunctor_obj_X₂, + natIsoSc'_inv_app_τ₂, id_comp] + rfl + +@[reassoc (attr := simp)] +lemma pOpcycles_opcyclesIsoSc'_hom : + K.pOpcycles j ≫ (K.opcyclesIsoSc' i j k hi hk).hom = (K.sc' i j k).pOpcycles := by + dsimp [opcyclesIsoSc'] + erw [ShortComplex.p_opcyclesMap] + apply id_comp + +@[reassoc (attr := simp)] +lemma opcyclesIsoSc'_inv_fromOpcycles : + (K.opcyclesIsoSc' i j k hi hk).inv ≫ K.fromOpcycles j k = + (K.sc' i j k).fromOpcycles := by + simp only [← cancel_epi (K.sc' i j k).pOpcycles, pOpcycles_opcyclesIsoSc'_inv_assoc, + p_fromOpcycles, ShortComplex.p_fromOpcycles, shortComplexFunctor'_obj_g] + +/-- The opcycles of a homological complex in degree `j` can be computed +by specifying a choice of `c.prev j` and `c.next j`. -/ +noncomputable def homologyIsoSc' : K.homology j ≅ (K.sc' i j k).homology := + ShortComplex.homologyMapIso (K.isoSc' i j k hi hk) + +@[reassoc (attr := simp)] +lemma π_homologyIsoSc'_hom : + K.homologyπ j ≫ (K.homologyIsoSc' i j k hi hk).hom = + (K.cyclesIsoSc' i j k hi hk).hom ≫ (K.sc' i j k).homologyπ := by + apply ShortComplex.homologyπ_naturality + +@[reassoc (attr := simp)] +lemma π_homologyIsoSc'_inv : + (K.sc' i j k).homologyπ ≫ (K.homologyIsoSc' i j k hi hk).inv = + (K.cyclesIsoSc' i j k hi hk).inv ≫ K.homologyπ j := by + apply ShortComplex.homologyπ_naturality + +@[reassoc (attr := simp)] +lemma homologyIsoSc'_hom_ι : + (K.homologyIsoSc' i j k hi hk).hom ≫ (K.sc' i j k).homologyι = + K.homologyι j ≫ (K.opcyclesIsoSc' i j k hi hk).hom := by + apply ShortComplex.homologyι_naturality + +@[reassoc (attr := simp)] +lemma homologyIsoSc'_inv_ι : + (K.homologyIsoSc' i j k hi hk).inv ≫ K.homologyι j = + (K.sc' i j k).homologyι ≫ (K.opcyclesIsoSc' i j k hi hk).inv := by + apply ShortComplex.homologyι_naturality + +end HomologicalComplex diff --git a/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean b/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean index e9c4fc5b0a1b2..c0dea3d302732 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean @@ -106,14 +106,23 @@ def moduleCatToCycles : S.X₁ →ₗ[R] LinearMap.ker S.g where map_add' x y := by aesop map_smul' a x := by aesop +/-- The homology of `S`, defined as the quotient of the kernel of `S.g` by +the image of `S.moduleCatToCycles` -/ +abbrev moduleCatHomology := + ModuleCat.of R (LinearMap.ker S.g ⧸ LinearMap.range S.moduleCatToCycles) + +/-- The canonical map `ModuleCat.of R (LinearMap.ker S.g) ⟶ S.moduleCatHomology`. -/ +abbrev moduleCatHomologyπ : ModuleCat.of R (LinearMap.ker S.g) ⟶ S.moduleCatHomology := + (LinearMap.range S.moduleCatToCycles).mkQ + /-- The explicit left homology data of a short complex of modules that is given by a kernel and a quotient given by the `LinearMap` API. -/ @[simps] def moduleCatLeftHomologyData : S.LeftHomologyData where K := ModuleCat.of R (LinearMap.ker S.g) - H := ModuleCat.of R (LinearMap.ker S.g ⧸ LinearMap.range S.moduleCatToCycles) + H := S.moduleCatHomology i := (LinearMap.ker S.g).subtype - π := (LinearMap.range S.moduleCatToCycles).mkQ + π := S.moduleCatHomologyπ wi := by ext ⟨_, hx⟩ exact hx @@ -130,21 +139,52 @@ def moduleCatLeftHomologyData : S.LeftHomologyData where lemma moduleCatLeftHomologyData_f' : S.moduleCatLeftHomologyData.f' = S.moduleCatToCycles := rfl +instance : Epi S.moduleCatHomologyπ := + (inferInstance : Epi S.moduleCatLeftHomologyData.π) + /-- Given a short complex `S` of modules, this is the isomorphism between the abstract `S.cycles` of the homology API and the more concrete description as `LinearMap.ker S.g`. -/ noncomputable def moduleCatCyclesIso : S.cycles ≅ ModuleCat.of R (LinearMap.ker S.g) := S.moduleCatLeftHomologyData.cyclesIso +@[reassoc (attr := simp, elementwise)] +lemma moduleCatCyclesIso_hom_subtype : + S.moduleCatCyclesIso.hom ≫ (LinearMap.ker S.g).subtype = S.iCycles := + S.moduleCatLeftHomologyData.cyclesIso_hom_comp_i + +@[reassoc (attr := simp, elementwise)] +lemma moduleCatCyclesIso_inv_iCycles : + S.moduleCatCyclesIso.inv ≫ S.iCycles = (LinearMap.ker S.g).subtype := + S.moduleCatLeftHomologyData.cyclesIso_inv_comp_iCycles + +@[reassoc (attr := simp, elementwise)] +lemma toCycles_moduleCatCyclesIso_hom : + S.toCycles ≫ S.moduleCatCyclesIso.hom = S.moduleCatToCycles := by + rw [← cancel_mono S.moduleCatLeftHomologyData.i, moduleCatLeftHomologyData_i, + Category.assoc, S.moduleCatCyclesIso_hom_subtype, toCycles_i] + rfl + /-- Given a short complex `S` of modules, this is the isomorphism between the abstract `S.homology` of the homology API and the more explicit quotient of `LinearMap.ker S.g` by the image of `S.moduleCatToCycles : S.X₁ →ₗ[R] LinearMap.ker S.g`. -/ noncomputable def moduleCatHomologyIso : - S.homology ≅ - ModuleCat.of R ((LinearMap.ker S.g) ⧸ LinearMap.range S.moduleCatToCycles) := + S.homology ≅ S.moduleCatHomology := S.moduleCatLeftHomologyData.homologyIso +@[reassoc (attr := simp, elementwise)] +lemma π_moduleCatCyclesIso_hom : + S.homologyπ ≫ S.moduleCatHomologyIso.hom = + S.moduleCatCyclesIso.hom ≫ S.moduleCatHomologyπ := + S.moduleCatLeftHomologyData.homologyπ_comp_homologyIso_hom + +@[reassoc (attr := simp, elementwise)] +lemma moduleCatCyclesIso_inv_π : + S.moduleCatCyclesIso.inv ≫ S.homologyπ = + S.moduleCatHomologyπ ≫ S.moduleCatHomologyIso.inv := + S.moduleCatLeftHomologyData.π_comp_homologyIso_inv + lemma exact_iff_surjective_moduleCatToCycles : S.Exact ↔ Function.Surjective S.moduleCatToCycles := by rw [S.moduleCatLeftHomologyData.exact_iff_epi_f', moduleCatLeftHomologyData_f', From e270b052a397f480011b1daa79db0422a01765f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 05:26:42 +0000 Subject: [PATCH 227/353] feat(CategoryTheory): localization of product categories (#8864) The product of finitely many localized categories is the localized category of the product category, provided the classes of morphisms contain identities. --- Mathlib.lean | 1 + Mathlib/CategoryTheory/Localization/Pi.lean | 70 +++++++++++++++++++ .../Localization/Predicate.lean | 6 ++ 3 files changed, 77 insertions(+) create mode 100644 Mathlib/CategoryTheory/Localization/Pi.lean diff --git a/Mathlib.lean b/Mathlib.lean index bfffbaf6cbc12..ba0f23be4a057 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1149,6 +1149,7 @@ import Mathlib.CategoryTheory.Localization.Construction import Mathlib.CategoryTheory.Localization.Equivalence import Mathlib.CategoryTheory.Localization.LocalizerMorphism import Mathlib.CategoryTheory.Localization.Opposite +import Mathlib.CategoryTheory.Localization.Pi import Mathlib.CategoryTheory.Localization.Predicate import Mathlib.CategoryTheory.Localization.Prod import Mathlib.CategoryTheory.Monad.Adjunction diff --git a/Mathlib/CategoryTheory/Localization/Pi.lean b/Mathlib/CategoryTheory/Localization/Pi.lean new file mode 100644 index 0000000000000..ea98e5396fc93 --- /dev/null +++ b/Mathlib/CategoryTheory/Localization/Pi.lean @@ -0,0 +1,70 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.CategoryTheory.Localization.Prod + +/-! +# Localization of product categories + +In this file, it is shown that if for all `j : J` (with `J` finite), +functors `L j : C j ⥤ D j` are localization functors with respect +to a class of morphisms `W j : MorphismProperty (C j)`, then the product +functor `Functor.pi L : (∀ j, C j) ⥤ ∀ j, D j` is a localization +functor for the product class of morphisms `MorphismProperty.pi W`. +The proof proceeds by induction on the cardinal of `J` using the +main result of the file `Mathlib.CategoryTheory.Localization.Prod`. + +-/ + +universe w v₁ v₂ u₁ u₂ + +namespace CategoryTheory.Functor.IsLocalization + +instance pi {J : Type w} [Finite J] {C : J → Type u₁} {D : J → Type u₂} + [∀ j, Category.{v₁} (C j)] [∀ j, Category.{v₂} (D j)] + (L : ∀ j, C j ⥤ D j) (W : ∀ j, MorphismProperty (C j)) + [∀ j, (W j).ContainsIdentities] [∀ j, (L j).IsLocalization (W j)] : + (Functor.pi L).IsLocalization (MorphismProperty.pi W) := by + revert J + apply Finite.induction_empty_option + · intro J₁ J₂ e hJ₁ C₂ D₂ _ _ L₂ W₂ _ _ + let L₁ := fun j => (L₂ (e j)) + let E := Pi.equivalenceOfEquiv C₂ e + let E' := Pi.equivalenceOfEquiv D₂ e + haveI : CatCommSq E.functor (Functor.pi L₁) (Functor.pi L₂) E'.functor := + (CatCommSq.hInvEquiv E (Functor.pi L₁) (Functor.pi L₂) E').symm ⟨Iso.refl _⟩ + refine IsLocalization.of_equivalences (Functor.pi L₁) + (MorphismProperty.pi (fun j => (W₂ (e j)))) (Functor.pi L₂) + (MorphismProperty.pi W₂) E E' ?_ + (MorphismProperty.IsInvertedBy.pi _ _ (fun _ => Localization.inverts _ _)) + intro _ _ f hf + refine ⟨_, _, E.functor.map f, fun i => ?_, ⟨Iso.refl _⟩⟩ + have H : ∀ {j j' : J₂} (h : j = j') {X Y : C₂ j} (g : X ⟶ Y) (_ : W₂ j g), + W₂ j' ((Pi.eqToEquivalence C₂ h).functor.map g) := by + rintro j _ rfl _ _ g hg + exact hg + exact H (e.apply_symm_apply i) _ (hf (e.symm i)) + · intro C D _ _ L W _ _ + haveI : ∀ j, IsEquivalence (L j) := by rintro ⟨⟩ + refine IsLocalization.of_isEquivalence _ _ (fun _ _ _ _ => ?_) + rw [MorphismProperty.isomorphisms.iff, isIso_pi_iff] + rintro ⟨⟩ + · intro J _ hJ C D _ _ L W _ _ + let L₁ := (L none).prod (Functor.pi (fun j => L (some j))) + haveI : CatCommSq (Pi.optionEquivalence C).symm.functor L₁ (Functor.pi L) + (Pi.optionEquivalence D).symm.functor := + ⟨NatIso.pi' (by rintro (_|i) <;> apply Iso.refl)⟩ + refine IsLocalization.of_equivalences L₁ + ((W none).prod (MorphismProperty.pi (fun j => W (some j)))) (Functor.pi L) _ + (Pi.optionEquivalence C).symm (Pi.optionEquivalence D).symm ?_ ?_ + · intro ⟨X₁, X₂⟩ ⟨Y₁, Y₂⟩ f ⟨hf₁, hf₂⟩ + refine ⟨_, _, (Pi.optionEquivalence C).inverse.map f, ?_, ⟨Iso.refl _⟩⟩ + · rintro (_|i) + · exact hf₁ + · apply hf₂ + · apply MorphismProperty.IsInvertedBy.pi + rintro (_|i) <;> apply Localization.inverts + +end CategoryTheory.Functor.IsLocalization diff --git a/Mathlib/CategoryTheory/Localization/Predicate.lean b/Mathlib/CategoryTheory/Localization/Predicate.lean index a059c145afd76..bde3a8e3310a1 100644 --- a/Mathlib/CategoryTheory/Localization/Predicate.lean +++ b/Mathlib/CategoryTheory/Localization/Predicate.lean @@ -434,6 +434,12 @@ theorem of_equivalence_target {E : Type*} [Category E] (L' : C ⥤ E) (eq : D nonempty_isEquivalence := Nonempty.intro (IsEquivalence.ofIso e' inferInstance) } #align category_theory.functor.is_localization.of_equivalence_target CategoryTheory.Functor.IsLocalization.of_equivalence_target +lemma of_isEquivalence (L : C ⥤ D) (W : MorphismProperty C) + (hW : W ⊆ MorphismProperty.isomorphisms C) [IsEquivalence L] : + L.IsLocalization W := by + haveI : (𝟭 C).IsLocalization W := for_id W hW + exact of_equivalence_target (𝟭 C) W L L.asEquivalence L.leftUnitor + end IsLocalization end Functor From e981962405eef42de281623dc636b8f2feacc2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 05:26:43 +0000 Subject: [PATCH 228/353] feat(CategoryTheory): the localized category when there is a left calculus of fractions (#8921) --- .../Localization/CalculusOfFractions.lean | 156 +++++++++++++++++- 1 file changed, 153 insertions(+), 3 deletions(-) diff --git a/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean b/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean index e1bb1ce977f88..e9fd0409a60b9 100644 --- a/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean +++ b/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean @@ -272,6 +272,8 @@ variable {W} namespace LeftFraction +open HasLeftCalculusOfFractions + /-- Auxiliary definition for the composition of left fractions. -/ @[simp] def comp₀ {X Y Z : C} (z₁ : W.LeftFraction X Y) (z₂ : W.LeftFraction Y Z) @@ -285,12 +287,11 @@ lemma comp₀_rel {X Y Z : C} (z₁ : W.LeftFraction X Y) (z₂ : W.LeftFraction (z₃ z₃' : W.LeftFraction z₁.Y' z₂.Y') (h₃ : z₂.f ≫ z₃.s = z₁.s ≫ z₃.f) (h₃' : z₂.f ≫ z₃'.s = z₁.s ≫ z₃'.f) : LeftFractionRel (z₁.comp₀ z₂ z₃) (z₁.comp₀ z₂ z₃') := by - obtain ⟨z₄, fac⟩ := HasLeftCalculusOfFractions.exists_leftFraction - (RightFraction.mk z₃.s z₃.hs z₃'.s) + obtain ⟨z₄, fac⟩ := exists_leftFraction (RightFraction.mk z₃.s z₃.hs z₃'.s) dsimp at fac have eq : z₁.s ≫ z₃.f ≫ z₄.f = z₁.s ≫ z₃'.f ≫ z₄.s := by rw [← reassoc_of% h₃, ← reassoc_of% h₃', fac] - obtain ⟨Y, t, ht, fac'⟩ := HasLeftCalculusOfFractions.ext _ _ _ z₁.hs eq + obtain ⟨Y, t, ht, fac'⟩ := ext _ _ _ z₁.hs eq simp only [assoc] at fac' refine' ⟨Y, z₄.f ≫ t, z₄.s ≫ t, _, _, _⟩ · simp only [comp₀, assoc, reassoc_of% fac] @@ -329,6 +330,155 @@ lemma comp_eq {X Y Z : C} (z₁ : W.LeftFraction X Y) (z₂ : W.LeftFraction Y Z Quot.sound (LeftFraction.comp₀_rel _ _ _ _ (RightFraction.leftFraction_fac (RightFraction.mk z₁.s z₁.hs z₂.f)) h₃) +namespace Localization + +/-- Composition of morphisms in the constructed localized category +for a morphism property that has left calculus of fractions. -/ +noncomputable def Hom.comp {X Y Z : C} (z₁ : Hom W X Y) (z₂ : Hom W Y Z) : Hom W X Z := by + refine' Quot.lift₂ (fun a b => a.comp b) _ _ z₁ z₂ + · rintro a b₁ b₂ ⟨U, t₁, t₂, hst, hft, ht⟩ + obtain ⟨z₁, fac₁⟩ := exists_leftFraction (RightFraction.mk a.s a.hs b₁.f) + obtain ⟨z₂, fac₂⟩ := exists_leftFraction (RightFraction.mk a.s a.hs b₂.f) + obtain ⟨w₁, fac₁'⟩ := exists_leftFraction (RightFraction.mk z₁.s z₁.hs t₁) + obtain ⟨w₂, fac₂'⟩ := exists_leftFraction (RightFraction.mk z₂.s z₂.hs t₂) + obtain ⟨u, fac₃⟩ := exists_leftFraction (RightFraction.mk w₁.s w₁.hs w₂.s) + dsimp at fac₁ fac₂ fac₁' fac₂' fac₃ ⊢ + have eq : a.s ≫ z₁.f ≫ w₁.f ≫ u.f = a.s ≫ z₂.f ≫ w₂.f ≫ u.s := by + rw [← reassoc_of% fac₁, ← reassoc_of% fac₂, ← reassoc_of% fac₁', ← reassoc_of% fac₂', + reassoc_of% hft, fac₃] + obtain ⟨Z, p, hp, fac₄⟩ := ext _ _ _ a.hs eq + simp only [assoc] at fac₄ + rw [comp_eq _ _ z₁ fac₁, comp_eq _ _ z₂ fac₂] + apply Quot.sound + refine' ⟨Z, w₁.f ≫ u.f ≫ p, w₂.f ≫ u.s ≫ p, _, _, _⟩ + · dsimp + simp only [assoc, ← reassoc_of% fac₁', ← reassoc_of% fac₂', + reassoc_of% hst, reassoc_of% fac₃] + · dsimp + simp only [assoc, fac₄] + · dsimp + simp only [assoc] + rw [← reassoc_of% fac₁', ← reassoc_of% fac₃, ← assoc] + exact W.comp_mem _ _ ht (W.comp_mem _ _ w₂.hs (W.comp_mem _ _ u.hs hp)) + · rintro a₁ a₂ b ⟨U, t₁, t₂, hst, hft, ht⟩ + obtain ⟨z₁, fac₁⟩ := exists_leftFraction (RightFraction.mk a₁.s a₁.hs b.f) + obtain ⟨z₂, fac₂⟩ := exists_leftFraction (RightFraction.mk a₂.s a₂.hs b.f) + obtain ⟨w₁, fac₁'⟩ := exists_leftFraction (RightFraction.mk (a₁.s ≫ t₁) ht (b.f ≫ z₁.s)) + obtain ⟨w₂, fac₂'⟩ := exists_leftFraction (RightFraction.mk (a₂.s ≫ t₂) + (show W _ by rw [← hst]; exact ht) (b.f ≫ z₂.s)) + let p₁ : W.LeftFraction X Z := LeftFraction.mk (a₁.f ≫ t₁ ≫ w₁.f) (b.s ≫ z₁.s ≫ w₁.s) + (W.comp_mem _ _ b.hs (W.comp_mem _ _ z₁.hs w₁.hs)) + let p₂ : W.LeftFraction X Z := LeftFraction.mk (a₂.f ≫ t₂ ≫ w₂.f) (b.s ≫ z₂.s ≫ w₂.s) + (W.comp_mem _ _ b.hs (W.comp_mem _ _ z₂.hs w₂.hs)) + dsimp at fac₁ fac₂ fac₁' fac₂' ⊢ + simp only [assoc] at fac₁' fac₂' + rw [comp_eq _ _ z₁ fac₁, comp_eq _ _ z₂ fac₂] + apply Quot.sound + refine' LeftFractionRel.trans _ ((_ : LeftFractionRel p₁ p₂).trans _) + · have eq : a₁.s ≫ z₁.f ≫ w₁.s = a₁.s ≫ t₁ ≫ w₁.f := by rw [← fac₁', reassoc_of% fac₁] + obtain ⟨Z, u, hu, fac₃⟩ := ext _ _ _ a₁.hs eq + simp only [assoc] at fac₃ + refine' ⟨Z, w₁.s ≫ u, u, _, _, _⟩ + · dsimp + simp only [assoc] + · dsimp + simp only [assoc, fac₃] + · dsimp + simp only [assoc] + exact W.comp_mem _ _ b.hs (W.comp_mem _ _ z₁.hs (W.comp_mem _ _ w₁.hs hu)) + · obtain ⟨q, fac₃⟩ := exists_leftFraction (RightFraction.mk (z₁.s ≫ w₁.s) + (W.comp_mem _ _ z₁.hs w₁.hs) (z₂.s ≫ w₂.s)) + dsimp at fac₃ + simp only [assoc] at fac₃ + have eq : a₁.s ≫ t₁ ≫ w₁.f ≫ q.f = a₁.s ≫ t₁ ≫ w₂.f ≫ q.s := by + rw [← reassoc_of% fac₁', ← fac₃, reassoc_of% hst, reassoc_of% fac₂'] + obtain ⟨Z, u, hu, fac₄⟩ := ext _ _ _ a₁.hs eq + simp only [assoc] at fac₄ + refine' ⟨Z, q.f ≫ u, q.s ≫ u, _, _, _⟩ + · simp only [assoc, reassoc_of% fac₃] + · rw [assoc, assoc, assoc, assoc, fac₄, reassoc_of% hft] + · simp only [assoc, ← reassoc_of% fac₃] + exact W.comp_mem _ _ b.hs (W.comp_mem _ _ z₂.hs + (W.comp_mem _ _ w₂.hs (W.comp_mem _ _ q.hs hu))) + · have eq : a₂.s ≫ z₂.f ≫ w₂.s = a₂.s ≫ t₂ ≫ w₂.f := by + rw [← fac₂', reassoc_of% fac₂] + obtain ⟨Z, u, hu, fac₄⟩ := ext _ _ _ a₂.hs eq + simp only [assoc] at fac₄ + refine' ⟨Z, u, w₂.s ≫ u, _, _, _⟩ + · dsimp + simp only [assoc] + · dsimp + simp only [assoc, fac₄] + · dsimp + simp only [assoc] + exact W.comp_mem _ _ b.hs (W.comp_mem _ _ z₂.hs (W.comp_mem _ _ w₂.hs hu)) + +lemma Hom.comp_eq {X Y Z : C} (z₁ : W.LeftFraction X Y) (z₂ : W.LeftFraction Y Z) : + Hom.comp (mk z₁) (mk z₂) = z₁.comp z₂ := rfl + +end Localization + +/-- The constructed localized category for a morphism property +that has left calculus of fractions. -/ +@[nolint unusedArguments] +def Localization (_ : MorphismProperty C) := C + +namespace Localization + +noncomputable instance : Category (Localization W) where + Hom X Y := Localization.Hom W X Y + id X := Localization.Hom.mk (ofHom W (𝟙 _)) + comp f g := f.comp g + comp_id := by + rintro (X Y : C) f + obtain ⟨z, rfl⟩ := Hom.mk_surjective f + change (Hom.mk z).comp (Hom.mk (ofHom W (𝟙 Y))) = Hom.mk z + rw [Hom.comp_eq, comp_eq z (ofHom W (𝟙 Y)) (ofInv z.s z.hs) (by simp)] + dsimp [comp₀] + simp only [comp_id, id_comp] + id_comp := by + rintro (X Y : C) f + obtain ⟨z, rfl⟩ := Hom.mk_surjective f + change (Hom.mk (ofHom W (𝟙 X))).comp (Hom.mk z) = Hom.mk z + rw [Hom.comp_eq, comp_eq (ofHom W (𝟙 X)) z (ofHom W z.f) (by simp)] + dsimp + simp only [comp₀, id_comp, comp_id] + assoc := by + rintro (X₁ X₂ X₃ X₄ : C) f₁ f₂ f₃ + obtain ⟨z₁, rfl⟩ := Hom.mk_surjective f₁ + obtain ⟨z₂, rfl⟩ := Hom.mk_surjective f₂ + obtain ⟨z₃, rfl⟩ := Hom.mk_surjective f₃ + change ((Hom.mk z₁).comp (Hom.mk z₂)).comp (Hom.mk z₃) = + (Hom.mk z₁).comp ((Hom.mk z₂).comp (Hom.mk z₃)) + rw [Hom.comp_eq z₁ z₂, Hom.comp_eq z₂ z₃] + obtain ⟨z₁₂, fac₁₂⟩ := exists_leftFraction (RightFraction.mk z₁.s z₁.hs z₂.f) + obtain ⟨z₂₃, fac₂₃⟩ := exists_leftFraction (RightFraction.mk z₂.s z₂.hs z₃.f) + obtain ⟨z', fac⟩ := exists_leftFraction (RightFraction.mk z₁₂.s z₁₂.hs z₂₃.f) + dsimp at fac₁₂ fac₂₃ fac + rw [comp_eq z₁ z₂ z₁₂ fac₁₂, comp_eq z₂ z₃ z₂₃ fac₂₃, comp₀, comp₀, + Hom.comp_eq, Hom.comp_eq, + comp_eq _ z₃ (mk z'.f (z₂₃.s ≫ z'.s) (W.comp_mem _ _ z₂₃.hs z'.hs)) + (by dsimp; rw [assoc, reassoc_of% fac₂₃, fac]), + comp_eq z₁ _ (mk (z₁₂.f ≫ z'.f) z'.s z'.hs) + (by dsimp; rw [assoc, ← reassoc_of% fac₁₂, fac])] + simp + +variable (W) + +/-- The localization functor to the constructed localized category for a morphism property +that has left calculus of fractions. -/ +@[simps obj] +def Q : C ⥤ Localization W where + obj X := X + map f := Hom.mk (ofHom W f) + map_id _ := rfl + map_comp {X Y Z} f g := by + change _ = Hom.comp _ _ + rw [Hom.comp_eq, comp_eq (ofHom W f) (ofHom W g) (ofHom W g) (by simp)] + simp only [ofHom, comp₀, comp_id] + +end Localization + end LeftFraction end From b6d69218bff053bf67334a87d58033b6fb6be086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 05:26:44 +0000 Subject: [PATCH 229/353] feat(Algebra/Homology): the category of complexes up to quasi-isomorphisms (#8970) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR, we define the category of homological complexes up to quasi-isomorphisms. The derived category of an abelian category shall be a particular case on this construction, but the additional structures on the derived category will require more work. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- Mathlib.lean | 2 + Mathlib/Algebra/Homology/Localization.lean | 61 ++++++++++++++ .../Localization/HasLocalization.lean | 80 +++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 Mathlib/Algebra/Homology/Localization.lean create mode 100644 Mathlib/CategoryTheory/Localization/HasLocalization.lean diff --git a/Mathlib.lean b/Mathlib.lean index ba0f23be4a057..1d36225342aa6 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -247,6 +247,7 @@ import Mathlib.Algebra.Homology.HomotopyCategory.HomComplex import Mathlib.Algebra.Homology.HomotopyCategory.Shift import Mathlib.Algebra.Homology.ImageToKernel import Mathlib.Algebra.Homology.LocalCohomology +import Mathlib.Algebra.Homology.Localization import Mathlib.Algebra.Homology.ModuleCat import Mathlib.Algebra.Homology.Opposite import Mathlib.Algebra.Homology.QuasiIso @@ -1147,6 +1148,7 @@ import Mathlib.CategoryTheory.Localization.CalculusOfFractions import Mathlib.CategoryTheory.Localization.Composition import Mathlib.CategoryTheory.Localization.Construction import Mathlib.CategoryTheory.Localization.Equivalence +import Mathlib.CategoryTheory.Localization.HasLocalization import Mathlib.CategoryTheory.Localization.LocalizerMorphism import Mathlib.CategoryTheory.Localization.Opposite import Mathlib.CategoryTheory.Localization.Pi diff --git a/Mathlib/Algebra/Homology/Localization.lean b/Mathlib/Algebra/Homology/Localization.lean new file mode 100644 index 0000000000000..3d5912e76ba04 --- /dev/null +++ b/Mathlib/Algebra/Homology/Localization.lean @@ -0,0 +1,61 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ + +import Mathlib.Algebra.Homology.HomotopyCategory +import Mathlib.Algebra.Homology.QuasiIso +import Mathlib.CategoryTheory.Localization.HasLocalization + +/-! The category of homological complexes up to quasi-isomorphisms + +Given a category `C` with homology and any complex shape `c`, we define +the category `HomologicalComplexUpToQis C c` which is the localized +category of `HomologicalComplex C c` with respect to quasi-isomorphisms. +When `C` is abelian, this will be the derived category of `C` in the +particular case of the complex shape `ComplexShape.up ℤ`. + +Under suitable assumptions on `c` (e.g. chain or cochain complexes), +we shall show that `HomologicalComplexUpToQis C c` is also the +localized category of `HomotopyCategory C c` with respect to +the class of quasi-isomorphisms (TODO). + +-/ + +open CategoryTheory Limits + +variable (C : Type*) [Category C] {ι : Type*} (c : ComplexShape ι) [HasZeroMorphisms C] + [CategoryWithHomology C] [(HomologicalComplex.qis C c).HasLocalization] + +/-- The category of homological complexes up to quasi-isomorphisms. -/ +abbrev HomologicalComplexUpToQis := (HomologicalComplex.qis C c).Localization' + +variable {C c} + +/-- The localization functor `HomologicalComplex C c ⥤ HomologicalComplexUpToQis C c`. -/ +abbrev HomologicalComplexUpToQis.Q : + HomologicalComplex C c ⥤ HomologicalComplexUpToQis C c := + (HomologicalComplex.qis C c).Q' + +variable (C c) + +lemma HomologicalComplex.homologyFunctor_inverts_qis (i : ι) : + (qis C c).IsInvertedBy (homologyFunctor C c i) := fun _ _ _ hf => by + rw [qis_iff] at hf + dsimp + infer_instance + +namespace HomologicalComplexUpToQis + +/-- The homology functor `HomologicalComplexUpToQis C c ⥤ C` for each `i : ι`. -/ +noncomputable def homologyFunctor (i : ι) : HomologicalComplexUpToQis C c ⥤ C := + Localization.lift _ (HomologicalComplex.homologyFunctor_inverts_qis C c i) Q + +/-- The homology functor on `HomologicalComplexUpToQis C c` is induced by +the homology functor on `HomologicalComplex C c`. -/ +noncomputable def homologyFunctorFactors (i : ι) : + Q ⋙ homologyFunctor C c i ≅ HomologicalComplex.homologyFunctor C c i := + Localization.fac _ (HomologicalComplex.homologyFunctor_inverts_qis C c i) Q + +end HomologicalComplexUpToQis diff --git a/Mathlib/CategoryTheory/Localization/HasLocalization.lean b/Mathlib/CategoryTheory/Localization/HasLocalization.lean new file mode 100644 index 0000000000000..c826197962c32 --- /dev/null +++ b/Mathlib/CategoryTheory/Localization/HasLocalization.lean @@ -0,0 +1,80 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.CategoryTheory.Localization.Predicate + +/-! Morphism properties equipped with a localized category + +If `C : Type u` is a category (with `[Category.{v} C]`), and +`W : MorphismProperty C`, then the constructed localized +category `W.Localization` is in `Type u` (the objects are +essentially the same as that of `C`), but the morphisms +are in `Type (max u v)`. In particular situations, it +may happen that there is a localized category for `W` +whose morphisms are in a lower universe like `v`: it shall +be so for the homotopy categories of model categories (TODO), +and it should also be so for the derived categories of +Grothendieck abelian categories (TODO: but this shall be +very technical). + +Then, in order to allow the user to provide a localized +category with specific universe parameters when it exists, +we introduce a typeclass `MorphismProperty.HasLocalization.{w} W` +which contains the data of a localized category `D` for `W` +with `D : Type u` and `[Category.{w} D]`. Then, all +definitions which involve "the" localized category +for `W` should contain a `[MorphismProperty.HasLocalization.{w} W]` +assumption for a suitable `w`. The functor `W.Q' : C ⥤ W.Localization'` +shall be the localization functor for this fixed choice of the +localized category. If the statement of a theorem does not +involve the localized category, but the proof does, +it is no longer necessary to use a `HasLocalization` +assumption, but one may use +`HasLocalization.standard` in the proof instead. + +-/ + +universe w v u + +namespace CategoryTheory + +variable {C : Type u} [Category.{v} C] + +variable (W : MorphismProperty C) + +namespace MorphismProperty + +/-- The data of a localized category with a given universe +for the morphisms. -/ +class HasLocalization where + /-- the objects of the localized category. -/ + {D : Type u} + /-- the category structure. -/ + [hD : Category.{w} D] + /-- the localization functor. -/ + L : C ⥤ D + [hL : L.IsLocalization W] + +variable [HasLocalization.{w} W] + +/-- The localized category for `W : MorphismProperty C` +that is fixed by the `[HasLocalization W]` instance. -/ +def Localization' := HasLocalization.D W + +instance : Category W.Localization' := HasLocalization.hD + +/-- The localization functor `C ⥤ W.Localization'` +that is fixed by the `[HasLocalization W]` instance. -/ +def Q' : C ⥤ W.Localization' := HasLocalization.L + +instance : W.Q'.IsLocalization W := HasLocalization.hL + +/-- The constructed localized category. -/ +def HasLocalization.standard : HasLocalization.{max u v} W where + L := W.Q + +end MorphismProperty + +end CategoryTheory From aede33055710fe967fd079409ce85a4f992ec863 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 27 Dec 2023 05:26:45 +0000 Subject: [PATCH 230/353] chore(*): golf, mostly dropping unused `have`s (#9292) --- .../ContinuedFractions/ConvergentsEquiv.lean | 4 +-- Mathlib/Analysis/MeanInequalitiesPow.lean | 5 +--- .../Analysis/SpecialFunctions/CompareExp.lean | 1 - Mathlib/Data/Fin/Tuple/Basic.lean | 5 +--- Mathlib/Data/Matroid/IndepAxioms.lean | 2 +- Mathlib/Data/Rat/Cast/Defs.lean | 3 -- Mathlib/Init/Data/Nat/Lemmas.lean | 5 ++-- Mathlib/LinearAlgebra/AffineSpace/Basis.lean | 1 - Mathlib/LinearAlgebra/FreeModule/Basic.lean | 3 -- Mathlib/MeasureTheory/Integral/Lebesgue.lean | 1 - .../Integral/MeanInequalities.lean | 4 --- Mathlib/MeasureTheory/Measure/Trim.lean | 28 +++++++++---------- .../NumberTheory/LegendreSymbol/GaussSum.lean | 1 - Mathlib/RingTheory/DedekindDomain/Dvr.lean | 4 +-- Mathlib/RingTheory/Henselian.lean | 15 +++++----- Mathlib/RingTheory/PowerSeries/Basic.lean | 5 ++-- 16 files changed, 30 insertions(+), 57 deletions(-) diff --git a/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean b/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean index d135e1de98d03..715b3210257fe 100644 --- a/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean +++ b/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean @@ -145,9 +145,7 @@ theorem squashSeq_succ_n_tail_eq_squashSeq_tail_n : ext1 m cases' Decidable.em (m = n) with m_eq_n m_ne_n · simp [*, squashSeq] - · have : s.tail.get? m = s.get? (m + 1) := s.get?_tail m - cases s_succ_mth_eq : s.get? (m + 1) - all_goals have _ := this.trans s_succ_mth_eq + · cases s_succ_mth_eq : s.get? (m + 1) · simp only [*, squashSeq, Stream'.Seq.get?_tail, Stream'.Seq.get?_zipWith, Option.map₂_none_right] · simp [*, squashSeq] diff --git a/Mathlib/Analysis/MeanInequalitiesPow.lean b/Mathlib/Analysis/MeanInequalitiesPow.lean index e5516d0873a84..92bab49265059 100644 --- a/Mathlib/Analysis/MeanInequalitiesPow.lean +++ b/Mathlib/Analysis/MeanInequalitiesPow.lean @@ -289,13 +289,10 @@ theorem rpow_arith_mean_le_arith_mean2_rpow (w₁ w₂ z₁ z₂ : ℝ≥0∞) ( /-- Unweighted mean inequality, version for two elements of `ℝ≥0∞` and real exponents. -/ theorem rpow_add_le_mul_rpow_add_rpow (z₁ z₂ : ℝ≥0∞) {p : ℝ} (hp : 1 ≤ p) : (z₁ + z₂) ^ p ≤ (2 : ℝ≥0∞) ^ (p - 1) * (z₁ ^ p + z₂ ^ p) := by - rcases eq_or_lt_of_le hp with (rfl | h'p) - · simp only [rpow_one, sub_self, rpow_zero, one_mul, le_refl] convert rpow_arith_mean_le_arith_mean2_rpow (1 / 2) (1 / 2) (2 * z₁) (2 * z₂) (ENNReal.add_halves 1) hp using 1 · simp [← mul_assoc, ENNReal.inv_mul_cancel two_ne_zero two_ne_top] - · have _ : p - 1 ≠ 0 := ne_of_gt (sub_pos.2 h'p) - simp only [mul_rpow_of_nonneg _ _ (zero_le_one.trans hp), rpow_sub _ _ two_ne_zero two_ne_top, + · simp only [mul_rpow_of_nonneg _ _ (zero_le_one.trans hp), rpow_sub _ _ two_ne_zero two_ne_top, ENNReal.div_eq_inv_mul, rpow_one, mul_one] ring #align ennreal.rpow_add_le_mul_rpow_add_rpow ENNReal.rpow_add_le_mul_rpow_add_rpow diff --git a/Mathlib/Analysis/SpecialFunctions/CompareExp.lean b/Mathlib/Analysis/SpecialFunctions/CompareExp.lean index 09a89fb93a389..f87f45038313c 100644 --- a/Mathlib/Analysis/SpecialFunctions/CompareExp.lean +++ b/Mathlib/Analysis/SpecialFunctions/CompareExp.lean @@ -132,7 +132,6 @@ theorem isLittleO_log_abs_re (hl : IsExpCmpFilter l) : (fun z => Real.log (abs z (hl.tendsto_re.eventually_ge_atTop 1).mono fun z hz => by have h2 : 0 < Real.sqrt 2 := by simp have hz' : 1 ≤ abs z := hz.trans (re_le_abs z) - have _ : 0 < abs z := one_pos.trans_le hz' have hm₀ : 0 < max z.re |z.im| := lt_max_iff.2 (Or.inl <| one_pos.trans_le hz) rw [one_mul, Real.norm_eq_abs, _root_.abs_of_nonneg (Real.log_nonneg hz')] refine' le_trans _ (le_abs_self _) diff --git a/Mathlib/Data/Fin/Tuple/Basic.lean b/Mathlib/Data/Fin/Tuple/Basic.lean index c671690af9721..7a7b5d2de6ae5 100644 --- a/Mathlib/Data/Fin/Tuple/Basic.lean +++ b/Mathlib/Data/Fin/Tuple/Basic.lean @@ -569,10 +569,7 @@ theorem update_snoc_last : update (snoc p x) (last n) z = snoc p z := by theorem snoc_init_self : snoc (init q) (q (last n)) = q := by ext j by_cases h : j.val < n - · simp only [init, snoc, h, cast_eq, dite_true] - have _ : castSucc (castLT j h) = j := castSucc_castLT _ _ - rw [← cast_eq rfl (q j)] - congr + · simp only [init, snoc, h, cast_eq, dite_true, castSucc_castLT] · rw [eq_last_of_not_lt h] simp #align fin.snoc_init_self Fin.snoc_init_self diff --git a/Mathlib/Data/Matroid/IndepAxioms.lean b/Mathlib/Data/Matroid/IndepAxioms.lean index 47dc9fc7bf89c..8a4a71b9bb66b 100644 --- a/Mathlib/Data/Matroid/IndepAxioms.lean +++ b/Mathlib/Data/Matroid/IndepAxioms.lean @@ -199,7 +199,7 @@ attribute [pp_dot] Indep E · have hchoose : ∀ (b : ↑(B₀ \ I)), ∃ Ib, Ib ⊆ I ∧ Ib.Finite ∧ ¬Indep (insert (b : α) Ib) · rintro ⟨b, hb⟩; exact htofin I b hI (hcon b ⟨hB₀B hb.1, hb.2⟩) choose! f hf using hchoose - have _ := finite_coe_iff.2 (hB₀fin.diff I) + have := (hB₀fin.diff I).to_subtype refine ⟨iUnion f ∪ (B₀ ∩ I), union_subset (iUnion_subset (fun i ↦ (hf i).1)) (inter_subset_right _ _), (finite_iUnion <| fun i ↦ (hf i).2.1).union (hB₀fin.subset (inter_subset_left _ _)), diff --git a/Mathlib/Data/Rat/Cast/Defs.lean b/Mathlib/Data/Rat/Cast/Defs.lean index d560da79fd4b0..d6f44bc29ef98 100644 --- a/Mathlib/Data/Rat/Cast/Defs.lean +++ b/Mathlib/Data/Rat/Cast/Defs.lean @@ -150,9 +150,6 @@ theorem cast_mul_of_ne_zero : theorem cast_inv_of_ne_zero : ∀ {n : ℚ}, (n.num : α) ≠ 0 → (n.den : α) ≠ 0 → ((n⁻¹ : ℚ) : α) = (n : α)⁻¹ | ⟨n, d, h, c⟩ => fun (n0 : (n : α) ≠ 0) (d0 : (d : α) ≠ 0) => by - have _ : (n : ℤ) ≠ 0 := fun e => by rw [e] at n0; exact n0 Int.cast_zero - have _ : (d : ℤ) ≠ 0 := - Int.coe_nat_ne_zero.2 fun e => by rw [e] at d0; exact d0 Nat.cast_zero rw [num_den', inv_def'] rw [cast_mk_of_ne_zero, cast_mk_of_ne_zero, inv_div] <;> simp [n0, d0] #align rat.cast_inv_of_ne_zero Rat.cast_inv_of_ne_zero diff --git a/Mathlib/Init/Data/Nat/Lemmas.lean b/Mathlib/Init/Data/Nat/Lemmas.lean index 28f50c9071859..87b1725ce4bdf 100644 --- a/Mathlib/Init/Data/Nat/Lemmas.lean +++ b/Mathlib/Init/Data/Nat/Lemmas.lean @@ -784,10 +784,9 @@ lemma to_digits_core_length (b : Nat) (h : 2 <= b) (f n e : Nat) to_digits_core_lens_eq b f (n / b) (Nat.digitChar $ n % b), if_false] exact Nat.succ_le_succ ih case neg => - have _ : e = 0 := Nat.eq_zero_of_not_pos h_pred_pos - rw [‹e = 0›] + obtain rfl : e = 0 := Nat.eq_zero_of_not_pos h_pred_pos have _ : b ^ 1 = b := by simp only [pow_succ, pow_zero, Nat.one_mul] - have _ : n < b := ‹b ^ 1 = b› ▸ (‹e = 0› ▸ hlt : n < b ^ Nat.succ 0) + have _ : n < b := ‹b ^ 1 = b› ▸ hlt simp [(@Nat.div_eq_of_lt n b ‹n < b› : n / b = 0)] /-- The core implementation of `Nat.repr` returns a String with length less than or equal to the diff --git a/Mathlib/LinearAlgebra/AffineSpace/Basis.lean b/Mathlib/LinearAlgebra/AffineSpace/Basis.lean index 02e237d8f270b..65ddc86b8d1ed 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Basis.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Basis.lean @@ -258,7 +258,6 @@ theorem surjective_coord [Nontrivial ι] (i : ι) : Function.Surjective <| b.coo obtain ⟨j, hij⟩ := exists_ne i let s : Finset ι := {i, j} have hi : i ∈ s := by simp - have _ : j ∈ s := by simp let w : ι → k := fun j' => if j' = i then x else 1 - x have hw : s.sum w = 1 := by simp [Finset.sum_ite, Finset.filter_insert, hij] use s.affineCombination k b w diff --git a/Mathlib/LinearAlgebra/FreeModule/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Basic.lean index da2330a8587b2..d2236c84b3a6c 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Basic.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Basic.lean @@ -49,9 +49,6 @@ Note that if `M` does not fit in `w`, the reverse direction of this implication `Module.Free.of_basis`. -/ theorem Module.free_def [Small.{w,v} M] : Module.Free R M ↔ ∃ I : Type w, Nonempty (Basis I R M) := - -- Porting note: this is required or Lean cannot solve universe constraints - -- The same error presents if inferInstance is called to solve `small` - have _small (s : Set M) : Small.{w} ↑s := small_of_injective (fun _ _ => (Subtype.val_inj).mp) ⟨fun h => ⟨Shrink (Set.range h.exists_basis.some.2), ⟨(Basis.reindexRange h.exists_basis.some.2).reindex (equivShrink _)⟩⟩, diff --git a/Mathlib/MeasureTheory/Integral/Lebesgue.lean b/Mathlib/MeasureTheory/Integral/Lebesgue.lean index 930cb66d02577..284c1a8e47819 100644 --- a/Mathlib/MeasureTheory/Integral/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Integral/Lebesgue.lean @@ -347,7 +347,6 @@ theorem lintegral_iSup {f : ℕ → α → ℝ≥0∞} (hf : ∀ n, Measurable ( ∫⁻ a, ⨆ n, f n a ∂μ = ⨆ n, ∫⁻ a, f n a ∂μ := by set c : ℝ≥0 → ℝ≥0∞ := (↑) set F := fun a : α => ⨆ n, f n a - have _ : Measurable F := measurable_iSup hf refine' le_antisymm _ (iSup_lintegral_le _) rw [lintegral_eq_nnreal] refine' iSup_le fun s => iSup_le fun hsf => _ diff --git a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean index a408a0e6697e9..53f6968182cf1 100644 --- a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean +++ b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean @@ -322,10 +322,6 @@ theorem lintegral_Lp_mul_le_Lq_mul_Lr {α} [MeasurableSpace α] {p q r : ℝ} (h have hq0_lt : 0 < q := lt_of_le_of_lt hp0 hpq have hq0_ne : q ≠ 0 := (ne_of_lt hq0_lt).symm have h_one_div_r : 1 / r = 1 / p - 1 / q := by rw [hpqr]; simp - have _ : r ≠ 0 := by - have hr_inv_pos : 0 < 1 / r := by rwa [h_one_div_r, sub_pos, one_div_lt_one_div hq0_lt hp0_lt] - rw [one_div, _root_.inv_pos] at hr_inv_pos - exact (ne_of_lt hr_inv_pos).symm let p2 := q / p let q2 := p2.conjugateExponent have hp2q2 : p2.IsConjugateExponent q2 := diff --git a/Mathlib/MeasureTheory/Measure/Trim.lean b/Mathlib/MeasureTheory/Measure/Trim.lean index 386cea8ec4bf1..d4489ecb5f9cd 100644 --- a/Mathlib/MeasureTheory/Measure/Trim.lean +++ b/Mathlib/MeasureTheory/Measure/Trim.lean @@ -106,21 +106,19 @@ instance isFiniteMeasure_trim (hm : m ≤ m0) [IsFiniteMeasure μ] : IsFiniteMea theorem sigmaFiniteTrim_mono {m m₂ m0 : MeasurableSpace α} {μ : Measure α} (hm : m ≤ m0) (hm₂ : m₂ ≤ m) [SigmaFinite (μ.trim (hm₂.trans hm))] : SigmaFinite (μ.trim hm) := by - have _ := Measure.FiniteSpanningSetsIn (μ.trim (hm₂.trans hm)) Set.univ - refine' Measure.FiniteSpanningSetsIn.sigmaFinite _ - · exact Set.univ - · refine' - { set := spanningSets (μ.trim (hm₂.trans hm)) - set_mem := fun _ => Set.mem_univ _ - finite := fun i => _ -- This is the only one left to prove - spanning := iUnion_spanningSets _ } - calc - (μ.trim hm) (spanningSets (μ.trim (hm₂.trans hm)) i) = - ((μ.trim hm).trim hm₂) (spanningSets (μ.trim (hm₂.trans hm)) i) := - by rw [@trim_measurableSet_eq α m₂ m (μ.trim hm) _ hm₂ (measurable_spanningSets _ _)] - _ = (μ.trim (hm₂.trans hm)) (spanningSets (μ.trim (hm₂.trans hm)) i) := by - rw [@trim_trim _ _ μ _ _ hm₂ hm] - _ < ∞ := measure_spanningSets_lt_top _ _ + refine ⟨⟨?_⟩⟩ + refine + { set := spanningSets (μ.trim (hm₂.trans hm)) + set_mem := fun _ => Set.mem_univ _ + finite := fun i => ?_ + spanning := iUnion_spanningSets _ } + calc + (μ.trim hm) (spanningSets (μ.trim (hm₂.trans hm)) i) = + ((μ.trim hm).trim hm₂) (spanningSets (μ.trim (hm₂.trans hm)) i) := + by rw [@trim_measurableSet_eq α m₂ m (μ.trim hm) _ hm₂ (measurable_spanningSets _ _)] + _ = (μ.trim (hm₂.trans hm)) (spanningSets (μ.trim (hm₂.trans hm)) i) := by + rw [@trim_trim _ _ μ _ _ hm₂ hm] + _ < ∞ := measure_spanningSets_lt_top _ _ #align measure_theory.sigma_finite_trim_mono MeasureTheory.sigmaFiniteTrim_mono theorem sigmaFinite_trim_bot_iff : SigmaFinite (μ.trim bot_le) ↔ IsFiniteMeasure μ := by diff --git a/Mathlib/NumberTheory/LegendreSymbol/GaussSum.lean b/Mathlib/NumberTheory/LegendreSymbol/GaussSum.lean index 5b0c5da32cb98..53253f97536a4 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/GaussSum.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/GaussSum.lean @@ -312,7 +312,6 @@ theorem FiniteField.two_pow_card {F : Type*} [Fintype F] [Field F] (hF : ringCha -- we now show that the Gauss sum of `χ` and `ψ₈` has the relevant property have hg : gaussSum χ ψ₈char ^ 2 = χ (-1) * Fintype.card (ZMod 8) := by - have _ := congr_arg (· ^ 2) (Fin.sum_univ_eight fun x => (χ₈ x : FF) * τ ^ x.1) have h₁ : (fun i : Fin 8 => ↑(χ₈ i) * τ ^ i.val) = (fun a : ZMod 8 => χ a * ↑(ψ₈char a)) := by -- Porting note: original proof -- ext; congr; apply pow_one diff --git a/Mathlib/RingTheory/DedekindDomain/Dvr.lean b/Mathlib/RingTheory/DedekindDomain/Dvr.lean index b32fe71a7be3e..33cd60c1ffd1e 100644 --- a/Mathlib/RingTheory/DedekindDomain/Dvr.lean +++ b/Mathlib/RingTheory/DedekindDomain/Dvr.lean @@ -79,8 +79,8 @@ theorem Ring.DimensionLEOne.localization {R : Type*} (Rₘ : Type*) [CommRing R] ((IsLocalization.orderIsoOfPrime M Rₘ) ⟨p, hpp⟩).2.1 haveI : Ideal.IsPrime (Ideal.comap (algebraMap R Rₘ) P) := ((IsLocalization.orderIsoOfPrime M Rₘ) ⟨P, hPm.isPrime⟩).2.1 - have _ : Ideal.comap (algebraMap R Rₘ) p < Ideal.comap (algebraMap R Rₘ) P := hpP' - refine' h.not_lt_lt ⊥ (Ideal.comap _ _) (Ideal.comap _ _) ⟨_, hpP'⟩ + have hlt : Ideal.comap (algebraMap R Rₘ) p < Ideal.comap (algebraMap R Rₘ) P := hpP' + refine' h.not_lt_lt ⊥ (Ideal.comap _ _) (Ideal.comap _ _) ⟨_, hlt⟩ exact IsLocalization.bot_lt_comap_prime _ _ hM _ hp0⟩ #align ring.dimension_le_one.localization Ring.DimensionLEOne.localization diff --git a/Mathlib/RingTheory/Henselian.lean b/Mathlib/RingTheory/Henselian.lean index b3f04b7021ba1..e445ae1620b54 100644 --- a/Mathlib/RingTheory/Henselian.lean +++ b/Mathlib/RingTheory/Henselian.lean @@ -121,16 +121,15 @@ instance (priority := 100) Field.henselian (K : Type*) [Field K] : HenselianLoca theorem HenselianLocalRing.TFAE (R : Type u) [CommRing R] [LocalRing R] : TFAE [HenselianLocalRing R, - ∀ (f : R[X]) (_ : f.Monic) (a₀ : ResidueField R) (_ : aeval a₀ f = 0) - (_ : aeval a₀ (derivative f) ≠ 0), ∃ a : R, f.IsRoot a ∧ residue R a = a₀, + ∀ f : R[X], f.Monic → ∀ a₀ : ResidueField R, aeval a₀ f = 0 → + aeval a₀ (derivative f) ≠ 0 → ∃ a : R, f.IsRoot a ∧ residue R a = a₀, ∀ {K : Type u} [Field K], - ∀ (φ : R →+* K) (_ : Surjective φ) (f : R[X]) (_ : f.Monic) (a₀ : K) - (_ : f.eval₂ φ a₀ = 0) (_ : f.derivative.eval₂ φ a₀ ≠ 0), - ∃ a : R, f.IsRoot a ∧ φ a = a₀] := by - tfae_have _3_2 : 3 → 2; + ∀ (φ : R →+* K), Surjective φ → ∀ f : R[X], f.Monic → ∀ a₀ : K, + f.eval₂ φ a₀ = 0 → f.derivative.eval₂ φ a₀ ≠ 0 → ∃ a : R, f.IsRoot a ∧ φ a = a₀] := by + tfae_have 3 → 2 · intro H exact H (residue R) Ideal.Quotient.mk_surjective - tfae_have _2_1 : 2 → 1 + tfae_have 2 → 1 · intro H constructor intro f hf a₀ h₁ h₂ @@ -142,7 +141,7 @@ theorem HenselianLocalRing.TFAE (R : Type u) [CommRing R] [LocalRing R] : refine' ⟨a, ha₁, _⟩ rw [← Ideal.Quotient.eq_zero_iff_mem] rwa [← sub_eq_zero, ← RingHom.map_sub] at ha₂ - tfae_have _1_3 : 1 → 3 + tfae_have 1 → 3 · intro hR K _K φ hφ f hf a₀ h₁ h₂ obtain ⟨a₀, rfl⟩ := hφ a₀ have H := HenselianLocalRing.is_henselian f hf a₀ diff --git a/Mathlib/RingTheory/PowerSeries/Basic.lean b/Mathlib/RingTheory/PowerSeries/Basic.lean index b37b2f078bd9e..4004fcbd02b49 100644 --- a/Mathlib/RingTheory/PowerSeries/Basic.lean +++ b/Mathlib/RingTheory/PowerSeries/Basic.lean @@ -2363,10 +2363,9 @@ theorem coeff_order (h : (order φ).Dom) : coeff R (φ.order.get h) φ ≠ 0 := then the order of the power series is less than or equal to `n`.-/ theorem order_le (n : ℕ) (h : coeff R n φ ≠ 0) : order φ ≤ n := by classical - have _ : ∃ n, coeff R n φ ≠ 0 := Exists.intro n h rw [order, dif_neg] - · simp only [PartENat.coe_le_coe, Nat.find_le_iff] - exact ⟨n, le_rfl, h⟩ + · simp only [PartENat.coe_le_coe] + exact Nat.find_le h · exact exists_coeff_ne_zero_iff_ne_zero.mp ⟨n, h⟩ #align power_series.order_le PowerSeries.order_le From 7c5331ddc1f2ca3a7d86b6f9eb9dbf239230afea Mon Sep 17 00:00:00 2001 From: Hunter Monroe Date: Wed, 27 Dec 2023 05:26:46 +0000 Subject: [PATCH 231/353] doc:Move misplaced docstring (#9296) --- Mathlib/Computability/TuringMachine.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Computability/TuringMachine.lean b/Mathlib/Computability/TuringMachine.lean index ec92328d785de..bb407555229ca 100644 --- a/Mathlib/Computability/TuringMachine.lean +++ b/Mathlib/Computability/TuringMachine.lean @@ -1015,12 +1015,12 @@ set_option linter.uppercaseLean3 false section +-- type of "labels" or TM states variable (Γ : Type*) [Inhabited Γ] -- type of tape symbols variable (Λ : Type*) [Inhabited Λ] --- type of "labels" or TM states /-- A Turing machine "statement" is just a command to either move left or right, or write a symbol on the tape. -/ inductive Stmt @@ -1207,8 +1207,8 @@ state, but the statements themselves have a fixed structure. The `Stmt`s can be Note that here most statements do not have labels; `goto` commands can only go to a new function. Only the `goto` and `halt` statements actually take a step; the rest is done by recursion on -statements and so take 0 steps. (There is a uniform bound on many statements can be executed before -the next `goto`, so this is an `O(1)` speedup with the constant depending on the machine.) +statements and so take 0 steps. (There is a uniform bound on how many statements can be executed +before the next `goto`, so this is an `O(1)` speedup with the constant depending on the machine.) The `halt` command has a one step stutter before actually halting so that any changes made before the halt have a chance to be "committed", since the `eval` relation uses the final configuration From 4fab13d22e21e9ef916a9cd04f7270dec5838379 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Wed, 27 Dec 2023 07:29:50 +0000 Subject: [PATCH 232/353] chore: shortcut instances for IntermediateField over an IntermediateField (#9291) Removes [manual letI/haveI](https://github.com/leanprover-community/mathlib4/blob/fe76ea7c2bb0c725ad161755ac158171aa9c545a/Mathlib/FieldTheory/SeparableDegree.lean#L568-L571) that appear in four proofs of #9041 Co-authored-by: Junyan Xu --- Mathlib/FieldTheory/IntermediateField.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Mathlib/FieldTheory/IntermediateField.lean b/Mathlib/FieldTheory/IntermediateField.lean index 337b1ed1ee89a..c4a918cdb8fae 100644 --- a/Mathlib/FieldTheory/IntermediateField.lean +++ b/Mathlib/FieldTheory/IntermediateField.lean @@ -401,6 +401,14 @@ instance isScalarTower_mid' : IsScalarTower K S L := S.isScalarTower_mid #align intermediate_field.is_scalar_tower_mid' IntermediateField.isScalarTower_mid' +section shortcut_instances +variable {E} [Field E] [Algebra L E] (T : IntermediateField S E) {S} +instance : Algebra S T := T.algebra +instance : Module S T := Algebra.toModule +instance : SMul S T := Algebra.toSMul +instance [Algebra K E] [IsScalarTower K L E] : IsScalarTower K S T := T.isScalarTower +end shortcut_instances + /-- Given `f : L →ₐ[K] L'`, `S.comap f` is the intermediate field between `K` and `L` such that `f x ∈ S ↔ x ∈ S.comap f`. -/ def comap (f : L →ₐ[K] L') (S : IntermediateField K L') : IntermediateField K L where From 7a302eb97c8a48fef146f33f55eb00fc7a5541e3 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Wed, 27 Dec 2023 07:29:51 +0000 Subject: [PATCH 233/353] feat(Analysis/Calculus/Series): specialize to `deriv` (#9295) Asked by @MichaelStollBayreuth on [Zulip](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Derivative.20of.20series/near/410063277) --- Mathlib/Analysis/Calculus/Series.lean | 71 +++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/Mathlib/Analysis/Calculus/Series.lean b/Mathlib/Analysis/Calculus/Series.lean index a36d58a86614c..f16ed93d48e58 100644 --- a/Mathlib/Analysis/Calculus/Series.lean +++ b/Mathlib/Analysis/Calculus/Series.lean @@ -98,14 +98,15 @@ theorem continuous_tsum [TopologicalSpace β] {f : α → β → F} (hf : ∀ i, variable [NormedSpace 𝕜 F] -variable {f : α → E → F} {f' : α → E → E →L[𝕜] F} {v : ℕ → α → ℝ} {s : Set E} {x₀ x : E} {N : ℕ∞} +variable {f : α → E → F} {f' : α → E → E →L[𝕜] F} {g : α → 𝕜 → F} {g' : α → 𝕜 → F} {v : ℕ → α → ℝ} + {s : Set E} {t : Set 𝕜} {x₀ x : E} {y₀ y : 𝕜} {N : ℕ∞} /-- Consider a series of functions `∑' n, f n x` on a preconnected open set. If the series converges at a point, and all functions in the series are differentiable with a summable bound on the derivatives, then the series converges everywhere on the set. -/ theorem summable_of_summable_hasFDerivAt_of_isPreconnected (hu : Summable u) (hs : IsOpen s) (h's : IsPreconnected s) (hf : ∀ n x, x ∈ s → HasFDerivAt (f n) (f' n x) x) - (hf' : ∀ n x, x ∈ s → ‖f' n x‖ ≤ u n) (hx₀ : x₀ ∈ s) (hf0 : Summable (f · x₀)) {x : E} + (hf' : ∀ n x, x ∈ s → ‖f' n x‖ ≤ u n) (hx₀ : x₀ ∈ s) (hf0 : Summable (f · x₀)) (hx : x ∈ s) : Summable fun n => f n x := by haveI := Classical.decEq α rw [summable_iff_cauchySeq_finset] at hf0 ⊢ @@ -117,6 +118,17 @@ theorem summable_of_summable_hasFDerivAt_of_isPreconnected (hu : Summable u) (hs exact HasFDerivAt.sum fun i _ => hf i y hy #align summable_of_summable_has_fderiv_at_of_is_preconnected summable_of_summable_hasFDerivAt_of_isPreconnected +/-- Consider a series of functions `∑' n, f n x` on a preconnected open set. If the series converges +at a point, and all functions in the series are differentiable with a summable bound on the +derivatives, then the series converges everywhere on the set. -/ +theorem summable_of_summable_hasDerivAt_of_isPreconnected (hu : Summable u) (ht : IsOpen t) + (h't : IsPreconnected t) (hg : ∀ n y, y ∈ t → HasDerivAt (g n) (g' n y) y) + (hg' : ∀ n y, y ∈ t → ‖g' n y‖ ≤ u n) (hy₀ : y₀ ∈ t) (hg0 : Summable (g · y₀)) + (hy : y ∈ t) : Summable fun n => g n y := by + simp_rw [hasDerivAt_iff_hasFDerivAt] at hg + refine summable_of_summable_hasFDerivAt_of_isPreconnected hu ht h't hg ?_ hy₀ hg0 hy + simpa? says simpa only [ContinuousLinearMap.norm_smulRight_apply, norm_one, one_mul] + /-- Consider a series of functions `∑' n, f n x` on a preconnected open set. If the series converges at a point, and all functions in the series are differentiable with a summable bound on the derivatives, then the series is differentiable on the set and its derivative is the sum of the @@ -136,6 +148,20 @@ theorem hasFDerivAt_tsum_of_isPreconnected (hu : Summable u) (hs : IsOpen s) exact HasFDerivAt.sum fun n _ => hf n y hy #align has_fderiv_at_tsum_of_is_preconnected hasFDerivAt_tsum_of_isPreconnected +/-- Consider a series of functions `∑' n, f n x` on a preconnected open set. If the series converges +at a point, and all functions in the series are differentiable with a summable bound on the +derivatives, then the series is differentiable on the set and its derivative is the sum of the +derivatives. -/ +theorem hasDerivAt_tsum_of_isPreconnected (hu : Summable u) (ht : IsOpen t) + (h't : IsPreconnected t) (hg : ∀ n y, y ∈ t → HasDerivAt (g n) (g' n y) y) + (hg' : ∀ n y, y ∈ t → ‖g' n y‖ ≤ u n) (hy₀ : y₀ ∈ t) (hg0 : Summable fun n => g n y₀) + (hy : y ∈ t) : HasDerivAt (fun z => ∑' n, g n z) (∑' n, g' n y) y := by + simp_rw [hasDerivAt_iff_hasFDerivAt] at hg ⊢ + convert hasFDerivAt_tsum_of_isPreconnected hu ht h't hg ?_ hy₀ hg0 hy + · exact (ContinuousLinearMap.smulRightL 𝕜 𝕜 F 1).map_tsum <| + .of_norm_bounded u hu fun n ↦ hg' n y hy + · simpa? says simpa only [ContinuousLinearMap.norm_smulRight_apply, norm_one, one_mul] + /-- Consider a series of functions `∑' n, f n x`. If the series converges at a point, and all functions in the series are differentiable with a summable bound on the derivatives, then the series converges everywhere. -/ @@ -147,6 +173,15 @@ theorem summable_of_summable_hasFDerivAt (hu : Summable u) (fun n x _ => hf n x) (fun n x _ => hf' n x) (mem_univ _) hf0 (mem_univ _) #align summable_of_summable_has_fderiv_at summable_of_summable_hasFDerivAt +/-- Consider a series of functions `∑' n, f n x`. If the series converges at a +point, and all functions in the series are differentiable with a summable bound on the derivatives, +then the series converges everywhere. -/ +theorem summable_of_summable_hasDerivAt (hu : Summable u) + (hg : ∀ n y, HasDerivAt (g n) (g' n y) y) (hg' : ∀ n y, ‖g' n y‖ ≤ u n) + (hg0 : Summable fun n => g n y₀) (y : 𝕜) : Summable fun n => g n y := by + exact summable_of_summable_hasDerivAt_of_isPreconnected hu isOpen_univ isPreconnected_univ + (fun n x _ => hg n x) (fun n x _ => hg' n x) (mem_univ _) hg0 (mem_univ _) + /-- Consider a series of functions `∑' n, f n x`. If the series converges at a point, and all functions in the series are differentiable with a summable bound on the derivatives, then the series is differentiable and its derivative is the sum of the derivatives. -/ @@ -158,6 +193,15 @@ theorem hasFDerivAt_tsum (hu : Summable u) (hf : ∀ n x, HasFDerivAt (f n) (f' (fun n x _ => hf n x) (fun n x _ => hf' n x) (mem_univ _) hf0 (mem_univ _) #align has_fderiv_at_tsum hasFDerivAt_tsum +/-- Consider a series of functions `∑' n, f n x`. If the series converges at a +point, and all functions in the series are differentiable with a summable bound on the derivatives, +then the series is differentiable and its derivative is the sum of the derivatives. -/ +theorem hasDerivAt_tsum (hu : Summable u) (hg : ∀ n y, HasDerivAt (g n) (g' n y) y) + (hg' : ∀ n y, ‖g' n y‖ ≤ u n) (hg0 : Summable fun n => g n y₀) (y : 𝕜) : + HasDerivAt (fun z => ∑' n, g n z) (∑' n, g' n y) y := by + exact hasDerivAt_tsum_of_isPreconnected hu isOpen_univ isPreconnected_univ + (fun n y _ => hg n y) (fun n y _ => hg' n y) (mem_univ _) hg0 (mem_univ _) + /-- Consider a series of functions `∑' n, f n x`. If all functions in the series are differentiable with a summable bound on the derivatives, then the series is differentiable. Note that our assumptions do not ensure the pointwise convergence, but if there is no pointwise @@ -174,19 +218,40 @@ theorem differentiable_tsum (hu : Summable u) (hf : ∀ n x, HasFDerivAt (f n) ( exact differentiable_const 0 #align differentiable_tsum differentiable_tsum +/-- Consider a series of functions `∑' n, f n x`. If all functions in the series are differentiable +with a summable bound on the derivatives, then the series is differentiable. +Note that our assumptions do not ensure the pointwise convergence, but if there is no pointwise +convergence then the series is zero everywhere so the result still holds. -/ +theorem differentiable_tsum' (hu : Summable u) (hg : ∀ n y, HasDerivAt (g n) (g' n y) y) + (hg' : ∀ n y, ‖g' n y‖ ≤ u n) : Differentiable 𝕜 fun z => ∑' n, g n z := by + simp_rw [hasDerivAt_iff_hasFDerivAt] at hg + refine differentiable_tsum hu hg ?_ + simpa? says simpa only [ContinuousLinearMap.norm_smulRight_apply, norm_one, one_mul] + theorem fderiv_tsum_apply (hu : Summable u) (hf : ∀ n, Differentiable 𝕜 (f n)) (hf' : ∀ n x, ‖fderiv 𝕜 (f n) x‖ ≤ u n) (hf0 : Summable fun n => f n x₀) (x : E) : fderiv 𝕜 (fun y => ∑' n, f n y) x = ∑' n, fderiv 𝕜 (f n) x := (hasFDerivAt_tsum hu (fun n x => (hf n x).hasFDerivAt) hf' hf0 _).fderiv #align fderiv_tsum_apply fderiv_tsum_apply +theorem deriv_tsum_apply (hu : Summable u) (hg : ∀ n, Differentiable 𝕜 (g n)) + (hg' : ∀ n y, ‖deriv (g n) y‖ ≤ u n) (hg0 : Summable fun n => g n y₀) (y : 𝕜) : + deriv (fun z => ∑' n, g n z) y = ∑' n, deriv (g n) y := + (hasDerivAt_tsum hu (fun n y => (hg n y).hasDerivAt) hg' hg0 _).deriv + theorem fderiv_tsum (hu : Summable u) (hf : ∀ n, Differentiable 𝕜 (f n)) - (hf' : ∀ n x, ‖fderiv 𝕜 (f n) x‖ ≤ u n) {x₀ : E} (hf0 : Summable fun n => f n x₀) : + (hf' : ∀ n x, ‖fderiv 𝕜 (f n) x‖ ≤ u n) (hf0 : Summable fun n => f n x₀) : (fderiv 𝕜 fun y => ∑' n, f n y) = fun x => ∑' n, fderiv 𝕜 (f n) x := by ext1 x exact fderiv_tsum_apply hu hf hf' hf0 x #align fderiv_tsum fderiv_tsum +theorem deriv_tsum (hu : Summable u) (hg : ∀ n, Differentiable 𝕜 (g n)) + (hg' : ∀ n y, ‖deriv (g n) y‖ ≤ u n) (hg0 : Summable fun n => g n y₀) : + (deriv fun y => ∑' n, g n y) = fun y => ∑' n, deriv (g n) y := by + ext1 x + exact deriv_tsum_apply hu hg hg' hg0 x + /-! ### Higher smoothness -/ /-- Consider a series of smooth functions, with summable uniform bounds on the successive From 54cf2f5b857651534c8bf366c6ff46e7ee9b219a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 08:00:24 +0000 Subject: [PATCH 234/353] feat(CategoryTheory/GradedObject): action of a composition of bifunctors (#8242) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The action on graded objects of a trifunctor obtained by composition of two bifunctors can be computed as a composition of the actions of these two bifunctors. In this PR, we consider the case when we apply a bifunctor to the first two variables and then a bifunctor to this result and the remaining third variable. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- Mathlib/CategoryTheory/GradedObject.lean | 59 ++++++++- .../GradedObject/Trifunctor.lean | 117 +++++++++++++++++- 2 files changed, 170 insertions(+), 6 deletions(-) diff --git a/Mathlib/CategoryTheory/GradedObject.lean b/Mathlib/CategoryTheory/GradedObject.lean index e54419b8dd61e..f44ec540ced44 100644 --- a/Mathlib/CategoryTheory/GradedObject.lean +++ b/Mathlib/CategoryTheory/GradedObject.lean @@ -34,11 +34,10 @@ have a functor `map : GradedObject I C ⥤ GradedObject J C`. set_option autoImplicit true - -open CategoryTheory.Limits - namespace CategoryTheory +open Category Limits + universe w v u /-- A type synonym for `β → C`, used for `β`-graded objects in a category `C`. -/ @@ -279,7 +278,7 @@ end GradedObject namespace GradedObject -variable {I J : Type*} {C : Type*} [Category C] +variable {I J K : Type*} {C : Type*} [Category C] (X Y Z : GradedObject I C) (φ : X ⟶ Y) (e : X ≅ Y) (ψ : Y ⟶ Z) (p : I → J) /-- If `X : GradedObject I C` and `p : I → J`, `X.mapObjFun p j` is the family of objects `X i` @@ -413,6 +412,58 @@ noncomputable def map [∀ (j : J), HasColimitsOfShape (Discrete (p ⁻¹' {j})) obj X := X.mapObj p map φ := mapMap φ p +variable {C} (X Y) +variable (q : J → K) (r : I → K) (hpqr : ∀ i, q (p i) = r i) + +section + +variable (k : K) (c : ∀ (j : J), q j = k → X.CofanMapObjFun p j) + (hc : ∀ j hj, IsColimit (c j hj)) + (c' : Cofan (fun (j : q ⁻¹' {k}) => (c j.1 j.2).pt)) (hc' : IsColimit c') + +/-- Given maps `p : I → J`, `q : J → K` and `r : I → K` such that `q.comp p = r`, +`X : GradedObject I C`, `k : K`, the datum of cofans `X.CofanMapObjFun p j` for all +`j : J` and of a cofan for all the points of these cofans, this is a cofan of +type `X.CofanMapObjFun r k`, which is a colimit (see `isColimitCofanMapObjComp`) if the +given cofans are. -/ +@[simp] +def cofanMapObjComp : X.CofanMapObjFun r k := + CofanMapObjFun.mk _ _ _ c'.pt (fun i hi => + (c (p i) (by rw [hpqr, hi])).inj ⟨i, rfl⟩ ≫ c'.inj (⟨p i, by + rw [Set.mem_preimage, Set.mem_singleton_iff, hpqr, hi]⟩)) + +/-- Given maps `p : I → J`, `q : J → K` and `r : I → K` such that `q.comp p = r`, +`X : GradedObject I C`, `k : K`, the cofan constructed by `cofanMapObjComp` is a colimit. +In other words, if we have, for all `j : J` such that `hj : q j = k`, +a colimit cofan `c j hj` which computes the coproduct of the `X i` such that `p i = j`, +and also a colimit cofan which computes the coproduct of the points of these `c j hj`, then +the point of this latter cofan computes the coproduct of the `X i` such that `r i = k`. +.-/ +@[simp] +def isColimitCofanMapObjComp : + IsColimit (cofanMapObjComp X p q r hpqr k c c') := + mkCofanColimit _ + (fun s => Cofan.IsColimit.desc hc' + (fun ⟨j, (hj : q j = k)⟩ => Cofan.IsColimit.desc (hc j hj) + (fun ⟨i, (hi : p i = j)⟩ => s.inj ⟨i, by + simp only [Set.mem_preimage, Set.mem_singleton_iff, ← hpqr, hi, hj]⟩))) + (fun s ⟨i, (hi : r i = k)⟩ => by simp) + (fun s m hm => by + apply Cofan.IsColimit.hom_ext hc' + rintro ⟨j, rfl : q j = k⟩ + apply Cofan.IsColimit.hom_ext (hc j rfl) + rintro ⟨i, rfl : p i = j⟩ + dsimp + rw [Cofan.IsColimit.fac, Cofan.IsColimit.fac, ← hm] + dsimp + rw [assoc]) + +lemma hasMap_comp [X.HasMap p] [(X.mapObj p).HasMap q] : X.HasMap r := + fun k => ⟨_, isColimitCofanMapObjComp X p q r hpqr k _ + (fun j _ => X.isColimitCofanMapObj p j) _ ((X.mapObj p).isColimitCofanMapObj q k)⟩ + +end + end GradedObject end CategoryTheory diff --git a/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean b/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean index 41f6b3ae074c2..05dc4e7e11a50 100644 --- a/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean +++ b/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ import Mathlib.CategoryTheory.GradedObject.Bifunctor +import Mathlib.CategoryTheory.Functor.Trifunctor /-! # The action of trifunctors on graded objects @@ -26,8 +27,8 @@ namespace CategoryTheory open Category Limits -variable {C₁ C₂ C₃ C₄ : Type*} - [Category C₁] [Category C₂] [Category C₃] [Category C₄] +variable {C₁ C₂ C₃ C₄ C₁₂ : Type*} + [Category C₁] [Category C₂] [Category C₃] [Category C₄] [Category C₁₂] (F F' : C₁ ⥤ C₂ ⥤ C₃ ⥤ C₄) namespace GradedObject @@ -239,6 +240,118 @@ noncomputable def mapTrifunctorMap end +section + +variable (F₁₂ : C₁ ⥤ C₂ ⥤ C₁₂) (G : C₁₂ ⥤ C₃ ⥤ C₄) + {I₁ I₂ I₃ J : Type*} (r : I₁ × I₂ × I₃ → J) + +/-- Given a map `r : I₁ × I₂ × I₃ → J`, a `BifunctorComp₁₂IndexData r` consists of the data +of a type `I₁₂`, maps `p : I₁ × I₂ → I₁₂` and `q : I₁₂ × I₃ → J`, such that `r` is obtained +by composition of `p` and `q`. -/ +structure BifunctorComp₁₂IndexData := + /-- an auxiliary type -/ + I₁₂ : Type* + /-- a map `I₁ × I₂ → I₁₂` -/ + p : I₁ × I₂ → I₁₂ + /-- a map `I₁₂ × I₃ → J` -/ + q : I₁₂ × I₃ → J + hpq (i : I₁ × I₂ × I₃) : q ⟨p ⟨i.1, i.2.1⟩, i.2.2⟩ = r i + +variable {r} (ρ₁₂ : BifunctorComp₁₂IndexData r) + (X₁ : GradedObject I₁ C₁) (X₂ : GradedObject I₂ C₂) (X₃ : GradedObject I₃ C₃) + +/-- Given bifunctors `F₁₂ : C₁ ⥤ C₂ ⥤ C₁₂`, `G : C₁₂ ⥤ C₃ ⥤ C₄`, graded objects +`X₁ : GradedObject I₁ C₁`, `X₂ : GradedObject I₂ C₂`, `X₃ : GradedObject I₃ C₃` and +`ρ₁₂ : BifunctorComp₁₂IndexData r`, this asserts that for all `i₁₂ : ρ₁₂.I₁₂` and `i₃ : I₃`, +the functor `G(-, X₃ i₃)` commutes wich the coproducts of the `F₁₂(X₁ i₁, X₂ i₂)` +such that `ρ₁₂.p ⟨i₁, i₂⟩ = i₁₂`. -/ +abbrev HasGoodTrifunctor₁₂Obj := + ∀ (i₁₂ : ρ₁₂.I₁₂) (i₃ : I₃), PreservesColimit + (Discrete.functor (mapObjFun (((mapBifunctor F₁₂ I₁ I₂).obj X₁).obj X₂) ρ₁₂.p i₁₂)) + ((Functor.flip G).obj (X₃ i₃)) + +variable [HasMap (((mapBifunctor F₁₂ I₁ I₂).obj X₁).obj X₂) ρ₁₂.p] + [HasMap (((mapBifunctor G ρ₁₂.I₁₂ I₃).obj (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂)).obj X₃) ρ₁₂.q] + +/-- The inclusion of `(G.obj ((F₁₂.obj (X₁ i₁)).obj (X₂ i₂))).obj (X₃ i₃)` in +`mapBifunctorMapObj G ρ₁₂.q (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂) X₃ j` +when `r (i₁, i₂, i₃) = j`. -/ +noncomputable def ιMapBifunctor₁₂BifunctorMapObj (i₁ : I₁) (i₂ : I₂) (i₃ : I₃) (j : J) + (h : r (i₁, i₂, i₃) = j) : + (G.obj ((F₁₂.obj (X₁ i₁)).obj (X₂ i₂))).obj (X₃ i₃) ⟶ + mapBifunctorMapObj G ρ₁₂.q (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂) X₃ j := + (G.map (ιMapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂ i₁ i₂ _ rfl)).app (X₃ i₃) ≫ + ιMapBifunctorMapObj G ρ₁₂.q (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂) X₃ (ρ₁₂.p ⟨i₁, i₂⟩) i₃ j + (by rw [← h, ← ρ₁₂.hpq]) + +/-- The cofan consisting of the inclusions given by `ιMapBifunctor₁₂BifunctorMapObj`. -/ +noncomputable def cofan₃MapBifunctor₁₂BifunctorMapObj (j : J) : + ((((mapTrifunctor (bifunctorComp₁₂ F₁₂ G) I₁ I₂ I₃).obj X₁).obj X₂).obj + X₃).CofanMapObjFun r j := + Cofan.mk (mapBifunctorMapObj G ρ₁₂.q (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂) X₃ j) + (fun ⟨⟨i₁, i₂, i₃⟩, (hi : r ⟨i₁, i₂, i₃⟩ = j)⟩ => + ιMapBifunctor₁₂BifunctorMapObj F₁₂ G ρ₁₂ X₁ X₂ X₃ i₁ i₂ i₃ j hi) + +variable [H : HasGoodTrifunctor₁₂Obj F₁₂ G ρ₁₂ X₁ X₂ X₃] + +/-- The cofan `cofan₃MapBifunctor₁₂BifunctorMapObj` is a colimit, see the induced isomorphism +`mapBifunctorComp₁₂MapObjIso`. -/ +noncomputable def isColimitCofan₃MapBifunctor₁₂BifunctorMapObj (j : J) : + IsColimit (cofan₃MapBifunctor₁₂BifunctorMapObj F₁₂ G ρ₁₂ X₁ X₂ X₃ j) := by + let c₁₂ := fun i₁₂ => (((mapBifunctor F₁₂ I₁ I₂).obj X₁).obj X₂).cofanMapObj ρ₁₂.p i₁₂ + have h₁₂ : ∀ i₁₂, IsColimit (c₁₂ i₁₂) := fun i₁₂ => + (((mapBifunctor F₁₂ I₁ I₂).obj X₁).obj X₂).isColimitCofanMapObj ρ₁₂.p i₁₂ + let c := (((mapBifunctor G ρ₁₂.I₁₂ I₃).obj + (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂)).obj X₃).cofanMapObj ρ₁₂.q j + have hc : IsColimit c := (((mapBifunctor G ρ₁₂.I₁₂ I₃).obj + (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂)).obj X₃).isColimitCofanMapObj ρ₁₂.q j + let c₁₂' := fun (i : ρ₁₂.q ⁻¹' {j}) => (G.flip.obj (X₃ i.1.2)).mapCocone (c₁₂ i.1.1) + have hc₁₂' : ∀ i, IsColimit (c₁₂' i) := fun i => isColimitOfPreserves _ (h₁₂ i.1.1) + let Z := (((mapTrifunctor (bifunctorComp₁₂ F₁₂ G) I₁ I₂ I₃).obj X₁).obj X₂).obj X₃ + let p' : I₁ × I₂ × I₃ → ρ₁₂.I₁₂ × I₃ := fun ⟨i₁, i₂, i₃⟩ => ⟨ρ₁₂.p ⟨i₁, i₂⟩, i₃⟩ + let e : ∀ (i₁₂ : ρ₁₂.I₁₂) (i₃ : I₃), p' ⁻¹' {(i₁₂, i₃)} ≃ ρ₁₂.p ⁻¹' {i₁₂} := fun i₁₂ i₃ => + { toFun := fun ⟨⟨i₁, i₂, i₃'⟩, hi⟩ => ⟨⟨i₁, i₂⟩, by aesop⟩ + invFun := fun ⟨⟨i₁, i₂⟩, hi⟩ => ⟨⟨i₁, i₂, i₃⟩, by aesop⟩ + left_inv := fun ⟨⟨i₁, i₂, i₃'⟩, hi⟩ => by + obtain rfl : i₃ = i₃' := by aesop + rfl + right_inv := fun _ => rfl } + let c₁₂'' : ∀ (i : ρ₁₂.q ⁻¹' {j}), CofanMapObjFun Z p' (i.1.1, i.1.2) := + fun ⟨⟨i₁₂, i₃⟩, hi⟩ => by + refine' (Cocones.precompose (Iso.hom _)).obj ((Cocones.whiskeringEquivalence + (Discrete.equivalence (e i₁₂ i₃))).functor.obj (c₁₂' ⟨⟨i₁₂, i₃⟩, hi⟩)) + refine' (Discrete.natIso (fun ⟨⟨i₁, i₂, i₃'⟩, hi⟩ => + (G.obj ((F₁₂.obj (X₁ i₁)).obj (X₂ i₂))).mapIso (eqToIso _))) + obtain rfl : i₃' = i₃ := congr_arg _root_.Prod.snd hi + rfl + have h₁₂'' : ∀ i, IsColimit (c₁₂'' i) := fun _ => + (IsColimit.precomposeHomEquiv _ _).symm (IsColimit.whiskerEquivalenceEquiv _ (hc₁₂' _)) + refine' IsColimit.ofIsoColimit (isColimitCofanMapObjComp Z p' ρ₁₂.q r ρ₁₂.hpq j + (fun ⟨i₁₂, i₃⟩ h => c₁₂'' ⟨⟨i₁₂, i₃⟩, h⟩) (fun ⟨i₁₂, i₃⟩ h => h₁₂'' ⟨⟨i₁₂, i₃⟩, h⟩) c hc) + (Cocones.ext (Iso.refl _) (fun ⟨⟨i₁, i₂, i₃⟩, h⟩ => _)) + dsimp [Cofan.inj] + rw [comp_id, Functor.map_id, id_comp] + rfl + +variable {F₁₂ G ρ₁₂ X₁ X₂ X₃} + +lemma HasGoodTrifunctor₁₂Obj.hasMap : + HasMap ((((mapTrifunctor (bifunctorComp₁₂ F₁₂ G) I₁ I₂ I₃).obj X₁).obj X₂).obj X₃) r := + fun j => ⟨_, isColimitCofan₃MapBifunctor₁₂BifunctorMapObj F₁₂ G ρ₁₂ X₁ X₂ X₃ j⟩ + +variable (F₁₂ G ρ₁₂ X₁ X₂ X₃) + +/-- The action on graded objects of a trifunctor obtained by composition of two +bifunctors can be computed as a composition of the actions of these two bifunctors. -/ +noncomputable def mapBifunctorComp₁₂MapObjIso + [HasMap ((((mapTrifunctor (bifunctorComp₁₂ F₁₂ G) I₁ I₂ I₃).obj X₁).obj X₂).obj X₃) r] : + mapTrifunctorMapObj (bifunctorComp₁₂ F₁₂ G) r X₁ X₂ X₃ ≅ + mapBifunctorMapObj G ρ₁₂.q (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂) X₃ := + isoMk _ _ (fun j => (CofanMapObjFun.iso + (isColimitCofan₃MapBifunctor₁₂BifunctorMapObj F₁₂ G ρ₁₂ X₁ X₂ X₃ j)).symm) + +end + end GradedObject end CategoryTheory From 2e77db724ec3c18e95393fa911ca65e3ab56c94d Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Wed, 27 Dec 2023 08:00:25 +0000 Subject: [PATCH 235/353] feat: cardinality of `Subfield.closure` (#8942) Also generalize results about the cardinality of WType to be universe polymorphic. [Zulip discussion](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Cardinality.20of.20division.20ring.20generated.20by.20.2E.2E.2E/near/406991528) about the approach - [x] depends on: #8941 Co-authored-by: Junyan Xu --- Mathlib.lean | 1 + Mathlib/Data/W/Cardinal.lean | 52 +++++++++----- Mathlib/SetTheory/Cardinal/Subfield.lean | 86 ++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 17 deletions(-) create mode 100644 Mathlib/SetTheory/Cardinal/Subfield.lean diff --git a/Mathlib.lean b/Mathlib.lean index 1d36225342aa6..1215fa99bc489 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3216,6 +3216,7 @@ import Mathlib.SetTheory.Cardinal.Divisibility import Mathlib.SetTheory.Cardinal.Finite import Mathlib.SetTheory.Cardinal.Ordinal import Mathlib.SetTheory.Cardinal.SchroederBernstein +import Mathlib.SetTheory.Cardinal.Subfield import Mathlib.SetTheory.Cardinal.UnivLE import Mathlib.SetTheory.Game.Basic import Mathlib.SetTheory.Game.Birthday diff --git a/Mathlib/Data/W/Cardinal.lean b/Mathlib/Data/W/Cardinal.lean index 272e6b542f1ac..778e4d549294d 100644 --- a/Mathlib/Data/W/Cardinal.lean +++ b/Mathlib/Data/W/Cardinal.lean @@ -25,9 +25,9 @@ W, W type, cardinal, first order -/ -universe u +universe u v -variable {α : Type u} {β : α → Type u} +variable {α : Type u} {β : α → Type v} noncomputable section @@ -38,47 +38,65 @@ open Cardinal -- porting note: `W` is a special name, exceptionally in upper case in Lean3 set_option linter.uppercaseLean3 false -theorem cardinal_mk_eq_sum : #(WType β) = sum (fun a : α => #(WType β) ^ #(β a)) := by - simp only [Cardinal.power_def, ← Cardinal.mk_sigma] - exact mk_congr (equivSigma β) -#align W_type.cardinal_mk_eq_sum WType.cardinal_mk_eq_sum +theorem cardinal_mk_eq_sum' : #(WType β) = sum (fun a : α => #(WType β) ^ lift.{u} #(β a)) := + (mk_congr <| equivSigma β).trans <| by + simp_rw [mk_sigma, mk_arrow]; rw [lift_id'.{v, u}, lift_umax.{v, u}] /-- `#(WType β)` is the least cardinal `κ` such that `sum (λ a : α, κ ^ #(β a)) ≤ κ` -/ -theorem cardinal_mk_le_of_le {κ : Cardinal.{u}} (hκ : (sum fun a : α => κ ^ #(β a)) ≤ κ) : +theorem cardinal_mk_le_of_le' {κ : Cardinal.{max u v}} + (hκ : (sum fun a : α => κ ^ lift.{u} #(β a)) ≤ κ) : #(WType β) ≤ κ := by induction' κ using Cardinal.inductionOn with γ - simp only [Cardinal.power_def, ← Cardinal.mk_sigma, Cardinal.le_def] at hκ + simp_rw [← lift_umax.{v, u}] at hκ + nth_rewrite 1 [← lift_id'.{v, u} #γ] at hκ + simp_rw [← mk_arrow, ← mk_sigma, le_def] at hκ cases' hκ with hκ exact Cardinal.mk_le_of_injective (elim_injective _ hκ.1 hκ.2) -#align W_type.cardinal_mk_le_of_le WType.cardinal_mk_le_of_le /-- If, for any `a : α`, `β a` is finite, then the cardinality of `WType β` is at most the maximum of the cardinality of `α` and `ℵ₀` -/ -theorem cardinal_mk_le_max_aleph0_of_finite [∀ a, Finite (β a)] : #(WType β) ≤ max #α ℵ₀ := +theorem cardinal_mk_le_max_aleph0_of_finite' [∀ a, Finite (β a)] : + #(WType β) ≤ max (lift.{v} #α) ℵ₀ := (isEmpty_or_nonempty α).elim (by intro h rw [Cardinal.mk_eq_zero (WType β)] exact zero_le _) fun hn => - let m := max #α ℵ₀ - cardinal_mk_le_of_le <| + let m := max (lift.{v} #α) ℵ₀ + cardinal_mk_le_of_le' <| calc - (Cardinal.sum fun a => m ^ #(β a)) ≤ #α * ⨆ a, m ^ #(β a) := Cardinal.sum_le_iSup _ - _ ≤ m * ⨆ a, m ^ #(β a) := mul_le_mul' (le_max_left _ _) le_rfl + (Cardinal.sum fun a => m ^ lift.{u} #(β a)) ≤ lift.{v} #α * ⨆ a, m ^ lift.{u} #(β a) := + Cardinal.sum_le_iSup_lift _ + _ ≤ m * ⨆ a, m ^ lift.{u} #(β a) := mul_le_mul' (le_max_left _ _) le_rfl _ = m := - mul_eq_left.{u} (le_max_right _ _) + mul_eq_left (le_max_right _ _) (ciSup_le' fun i => pow_le (le_max_right _ _) (lt_aleph0_of_finite _)) <| pos_iff_ne_zero.1 <| Order.succ_le_iff.1 (by rw [succ_zero] obtain ⟨a⟩ : Nonempty α := hn - refine' le_trans _ (le_ciSup (bddAbove_range.{u, u} _) a) + refine' le_trans _ (le_ciSup (bddAbove_range.{_, v} _) a) rw [← power_zero] exact power_le_power_left (pos_iff_ne_zero.1 (aleph0_pos.trans_le (le_max_right _ _))) (zero_le _)) -#align W_type.cardinal_mk_le_max_aleph_0_of_finite WType.cardinal_mk_le_max_aleph0_of_finite + +variable {β : α → Type u} + +theorem cardinal_mk_eq_sum : #(WType β) = sum (fun a : α => #(WType β) ^ #(β a)) := + cardinal_mk_eq_sum'.trans <| by simp_rw [lift_id] +#align W_type.cardinal_mk_eq_sum WType.cardinal_mk_eq_sum + +/-- `#(WType β)` is the least cardinal `κ` such that `sum (λ a : α, κ ^ #(β a)) ≤ κ` -/ +theorem cardinal_mk_le_of_le {κ : Cardinal.{u}} (hκ : (sum fun a : α => κ ^ #(β a)) ≤ κ) : + #(WType β) ≤ κ := cardinal_mk_le_of_le' <| by simp_rw [lift_id]; exact hκ +#align W_type.cardinal_mk_le_of_le WType.cardinal_mk_le_of_le + +/-- If, for any `a : α`, `β a` is finite, then the cardinality of `WType β` + is at most the maximum of the cardinality of `α` and `ℵ₀` -/ +theorem cardinal_mk_le_max_aleph0_of_finite [∀ a, Finite (β a)] : #(WType β) ≤ max #α ℵ₀ := + cardinal_mk_le_max_aleph0_of_finite'.trans_eq <| by rw [lift_id] end WType diff --git a/Mathlib/SetTheory/Cardinal/Subfield.lean b/Mathlib/SetTheory/Cardinal/Subfield.lean new file mode 100644 index 0000000000000..a8b0522bf7daa --- /dev/null +++ b/Mathlib/SetTheory/Cardinal/Subfield.lean @@ -0,0 +1,86 @@ +/- +Copyright (c) 2023 Junyan Xu. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Junyan Xu +-/ +import Mathlib.Data.W.Cardinal +import Mathlib.FieldTheory.Subfield +import Mathlib.Tactic.FinCases + +/-! +# Cardinality of the division ring generated by a set + +`Subfield.cardinal_mk_closure_le_max`: the cardinality of the (sub-)division ring +generated by a set is bounded by the cardinality of the set unless it is finite. + +The method used to prove this (via `WType`) can be easily generalized to other algebraic +structures, but those cardinalites can usually be obtained by other means, using some +explicit universal objects. + +-/ + +universe u + +variable {α : Type u} (s : Set α) + +namespace Subfield + +private abbrev Operands : Fin 6 ⊕ s → Type + | .inl 0 => Bool -- add + | .inl 1 => Bool -- mul + | .inl 2 => Unit -- neg + | .inl 3 => Unit -- inv + | .inl 4 => Empty -- zero + | .inl 5 => Empty -- one + | .inr _ => Empty -- s + +variable [DivisionRing α] + +private def operate : (Σ n, Operands s n → closure s) → closure s + | ⟨.inl 0, f⟩ => f false + f true + | ⟨.inl 1, f⟩ => f false * f true + | ⟨.inl 2, f⟩ => - f () + | ⟨.inl 3, f⟩ => (f ())⁻¹ + | ⟨.inl 4, _⟩ => 0 + | ⟨.inl 5, _⟩ => 1 + | ⟨.inr a, _⟩ => ⟨a, subset_closure a.prop⟩ + +private def rangeOfWType : Subfield (closure s) where + carrier := Set.range (WType.elim _ <| operate s) + add_mem' := by rintro _ _ ⟨x, rfl⟩ ⟨y, rfl⟩; exact ⟨WType.mk (.inl 0) (Bool.rec x y), by rfl⟩ + mul_mem' := by rintro _ _ ⟨x, rfl⟩ ⟨y, rfl⟩; exact ⟨WType.mk (.inl 1) (Bool.rec x y), by rfl⟩ + neg_mem' := by rintro _ ⟨x, rfl⟩; exact ⟨WType.mk (.inl 2) fun _ ↦ x, rfl⟩ + inv_mem' := by rintro _ ⟨x, rfl⟩; exact ⟨WType.mk (.inl 3) fun _ ↦ x, rfl⟩ + zero_mem' := ⟨WType.mk (.inl 4) Empty.rec, rfl⟩ + one_mem' := ⟨WType.mk (.inl 5) Empty.rec, rfl⟩ + +private lemma rangeOfWType_eq_top : rangeOfWType s = ⊤ := top_le_iff.mp fun a _ ↦ by + rw [← SetLike.mem_coe, ← Subtype.val_injective.mem_set_image] + change ↑a ∈ map (closure s).subtype _ + refine closure_le.mpr (fun a ha ↦ ?_) a.prop + exact ⟨⟨a, subset_closure ha⟩, ⟨WType.mk (.inr ⟨a, ha⟩) Empty.rec, rfl⟩, rfl⟩ + +private lemma surjective_ofWType : Function.Surjective (WType.elim _ <| operate s) := by + rw [← Set.range_iff_surjective] + exact SetLike.coe_set_eq.mpr (rangeOfWType_eq_top s) + +open Cardinal + +lemma cardinal_mk_closure_le_max : #(closure s) ≤ max #s ℵ₀ := + (Cardinal.mk_le_of_surjective <| surjective_ofWType s).trans <| by + convert WType.cardinal_mk_le_max_aleph0_of_finite' using 1 + · rw [lift_uzero, mk_sum, lift_uzero] + have : lift.{u,0} #(Fin 6) < ℵ₀ := lift_lt_aleph0.mpr (lt_aleph0_of_finite _) + obtain h|h := lt_or_le #s ℵ₀ + · rw [max_eq_right h.le, max_eq_right] + exact (add_lt_aleph0 this h).le + · rw [max_eq_left h, add_eq_right h (this.le.trans h), max_eq_left h] + rintro (n|_) + · fin_cases n <;> infer_instance + infer_instance + +lemma cardinal_mk_closure [Infinite s] : #(closure s) = #s := + ((cardinal_mk_closure_le_max s).trans_eq <| max_eq_left <| aleph0_le_mk s).antisymm + (mk_le_mk_of_subset subset_closure) + +end Subfield From 4d78a650388371bb7fa9b6b7bfafa6324ce0952c Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 27 Dec 2023 08:00:26 +0000 Subject: [PATCH 236/353] chore(Perm/Basic): generalize `swap_smul_involutive` (#9180) Generalize `Equiv.Perm.ModSumCongr.swap_smul_involutive` to any action of `Equiv.Perm _`, move it to `Perm/Basic`. --- Mathlib/GroupTheory/Perm/Basic.lean | 11 +++++++++-- Mathlib/LinearAlgebra/Alternating/DomCoprod.lean | 9 ++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Mathlib/GroupTheory/Perm/Basic.lean b/Mathlib/GroupTheory/Perm/Basic.lean index 52537e2fe1920..0278b9e22a9cc 100644 --- a/Mathlib/GroupTheory/Perm/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Basic.lean @@ -535,13 +535,20 @@ theorem swap_apply_apply (f : Perm α) (x y : α) : swap (f x) (f y) = f * swap rw [mul_swap_eq_swap_mul, mul_inv_cancel_right] #align equiv.swap_apply_apply Equiv.swap_apply_apply +@[simp] +theorem swap_smul_self_smul [MulAction (Perm α) β] (i j : α) (x : β) : + swap i j • swap i j • x = x := by simp [smul_smul] + +theorem swap_smul_involutive [MulAction (Perm α) β] (i j : α) : + Function.Involutive (swap i j • · : β → β) := swap_smul_self_smul i j + /-- Left-multiplying a permutation with `swap i j` twice gives the original permutation. This specialization of `swap_mul_self` is useful when using cosets of permutations. -/ @[simp] -theorem swap_mul_self_mul (i j : α) (σ : Perm α) : Equiv.swap i j * (Equiv.swap i j * σ) = σ := by - rw [← mul_assoc, swap_mul_self, one_mul] +theorem swap_mul_self_mul (i j : α) (σ : Perm α) : Equiv.swap i j * (Equiv.swap i j * σ) = σ := + swap_smul_self_smul i j σ #align equiv.swap_mul_self_mul Equiv.swap_mul_self_mul /-- Right-multiplying a permutation with `swap i j` twice gives the original permutation. diff --git a/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean b/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean index 6ed4f8b1fedd1..0641f65782f22 100644 --- a/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean +++ b/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean @@ -32,12 +32,7 @@ abbrev ModSumCongr (α β : Type*) := _ ⧸ (Equiv.Perm.sumCongrHom α β).range #align equiv.perm.mod_sum_congr Equiv.Perm.ModSumCongr -theorem ModSumCongr.swap_smul_involutive {α β : Type*} [DecidableEq (Sum α β)] (i j : Sum α β) : - Function.Involutive (SMul.smul (Equiv.swap i j) : ModSumCongr α β → ModSumCongr α β) := - fun σ => by - refine Quotient.inductionOn' σ fun σ => ?_ - exact _root_.congr_arg Quotient.mk'' (Equiv.swap_mul_involutive i j σ) -#align equiv.perm.mod_sum_congr.swap_smul_involutive Equiv.Perm.ModSumCongr.swap_smul_involutive +#align equiv.perm.mod_sum_congr.swap_smul_involutive Equiv.swap_smul_involutive end Equiv.Perm @@ -171,7 +166,7 @@ def domCoprod (a : Mᵢ [Λ^ιa]→ₗ[R'] N₁) (b : Mᵢ [Λ^ιb]→ₗ[R'] N (fun σ _ => domCoprod.summand_add_swap_smul_eq_zero a b σ hv hij) (fun σ _ => mt <| domCoprod.summand_eq_zero_of_smul_invariant a b σ hv hij) (fun σ _ => Finset.mem_univ _) fun σ _ => - Equiv.Perm.ModSumCongr.swap_smul_involutive i j σ } + Equiv.swap_smul_involutive i j σ } #align alternating_map.dom_coprod AlternatingMap.domCoprod #align alternating_map.dom_coprod_apply AlternatingMap.domCoprod_apply From 7a0da1d7291b44cf9df4ab5b07480c56b4913701 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Wed, 27 Dec 2023 08:00:28 +0000 Subject: [PATCH 237/353] test: `induction'` error conditions when `generalizing` (#9194) --- test/cases.lean | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/cases.lean b/test/cases.lean index 815a57dc4671f..0bdfe5b32aaf1 100644 --- a/test/cases.lean +++ b/test/cases.lean @@ -126,3 +126,16 @@ example (a b : ℕ) (h : a + b = a) : b = 0 := by rw [Nat.succ_add, Nat.succ.injEq] at h apply hd assumption + +/-- error: unnecessary 'generalizing' argument, variable 'a' is generalized automatically -/ +#guard_msgs in +example (n : ℕ) (a : Fin n) : True := by + induction' n generalizing a + +/-- +error: variable cannot be generalized because target depends on it + m +-/ +#guard_msgs in +example (m : ℕ) : True := by + induction' m generalizing m From df4f6559badf5938d551ef4f0f282031be6034ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 27 Dec 2023 08:00:29 +0000 Subject: [PATCH 238/353] feat: Finite supremum over a product (#9223) From LeanCamCombi --- Mathlib/Data/Finset/Lattice.lean | 68 +++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/Mathlib/Data/Finset/Lattice.lean b/Mathlib/Data/Finset/Lattice.lean index e70596fc8e45e..b4396a748263a 100644 --- a/Mathlib/Data/Finset/Lattice.lean +++ b/Mathlib/Data/Finset/Lattice.lean @@ -102,11 +102,9 @@ protected theorem sup_le_iff {a : α} : s.sup f ≤ a ↔ ∀ b ∈ s, f b ≤ a exact ⟨fun k b hb => k _ _ hb rfl, fun k a' b hb h => h ▸ k _ hb⟩ #align finset.sup_le_iff Finset.sup_le_iff -alias ⟨_, sup_le⟩ := Finset.sup_le_iff +protected alias ⟨_, sup_le⟩ := Finset.sup_le_iff #align finset.sup_le Finset.sup_le --- Porting note: removed `attribute [protected] sup_le` - theorem sup_const_le : (s.sup fun _ => a) ≤ a := Finset.sup_le fun _ _ => le_rfl #align finset.sup_const_le Finset.sup_const_le @@ -173,6 +171,20 @@ theorem sup_product_right (s : Finset β) (t : Finset γ) (f : β × γ → α) rw [sup_product_left, Finset.sup_comm] #align finset.sup_product_right Finset.sup_product_right +section Prod +variable {ι κ α β : Type*} [SemilatticeSup α] [SemilatticeSup β] [OrderBot α] [OrderBot β] + {s : Finset ι} {t : Finset κ} + +@[simp] lemma sup_prodMap (hs : s.Nonempty) (ht : t.Nonempty) (f : ι → α) (g : κ → β) : + sup (s ×ˢ t) (Prod.map f g) = (sup s f, sup t g) := + eq_of_forall_ge_iff fun i ↦ by + obtain ⟨a, ha⟩ := hs + obtain ⟨b, hb⟩ := ht + simp only [Prod.map, Finset.sup_le_iff, mem_product, and_imp, Prod.forall, Prod.le_def] + exact ⟨fun h ↦ ⟨fun i hi ↦ (h _ _ hi hb).1, fun j hj ↦ (h _ _ ha hj).2⟩, by aesop⟩ + +end Prod + @[simp] theorem sup_erase_bot [DecidableEq α] (s : Finset α) : (s.erase ⊥).sup id = s.sup id := by refine' (sup_mono (s.erase_subset _)).antisymm (Finset.sup_le_iff.2 fun a ha => _) @@ -365,11 +377,9 @@ theorem _root_.map_finset_inf [SemilatticeInf β] [OrderTop β] [InfTopHomClass @Finset.sup_le_iff αᵒᵈ _ _ _ _ _ _ #align finset.le_inf_iff Finset.le_inf_iff -alias ⟨_, le_inf⟩ := Finset.le_inf_iff +protected alias ⟨_, le_inf⟩ := Finset.le_inf_iff #align finset.le_inf Finset.le_inf --- Porting note: removed attribute [protected] le_inf - theorem le_inf_const_le : a ≤ s.inf fun _ => a := Finset.le_inf fun _ _ => le_rfl #align finset.le_inf_const_le Finset.le_inf_const_le @@ -427,6 +437,16 @@ theorem inf_product_right (s : Finset β) (t : Finset γ) (f : β × γ → α) @sup_product_right αᵒᵈ _ _ _ _ _ _ _ #align finset.inf_product_right Finset.inf_product_right +section Prod +variable {ι κ α β : Type*} [SemilatticeInf α] [SemilatticeInf β] [OrderTop α] [OrderTop β] + {s : Finset ι} {t : Finset κ} + +@[simp] lemma inf_prodMap (hs : s.Nonempty) (ht : t.Nonempty) (f : ι → α) (g : κ → β) : + inf (s ×ˢ t) (Prod.map f g) = (inf s f, inf t g) := + sup_prodMap (α := αᵒᵈ) (β := βᵒᵈ) hs ht _ _ + +end Prod + @[simp] theorem inf_erase_top [DecidableEq α] (s : Finset α) : (s.erase ⊤).inf id = s.inf id := @sup_erase_bot αᵒᵈ _ _ _ _ @@ -847,6 +867,26 @@ theorem sup'_product_right {t : Finset γ} (hs : s.Nonempty) (ht : t.Nonempty) ( rw [sup'_product_left, Finset.sup'_comm] #align finset.sup'_product_right Finset.sup'_product_right +section Prod +variable {ι κ α β : Type*} [SemilatticeSup α] [SemilatticeSup β] {s : Finset ι} {t : Finset κ} + +/-- See also `Finset.sup'_prodMap`. -/ +lemma prodMk_sup'_sup' (hs : s.Nonempty) (ht : t.Nonempty) (f : ι → α) (g : κ → β) : + (sup' s hs f, sup' t ht g) = sup' (s ×ˢ t) (hs.product ht) (Prod.map f g) := + eq_of_forall_ge_iff fun i ↦ by + obtain ⟨a, ha⟩ := hs + obtain ⟨b, hb⟩ := ht + simp only [Prod.map, sup'_le_iff, mem_product, and_imp, Prod.forall, Prod.le_def] + exact ⟨by aesop, fun h ↦ ⟨fun i hi ↦ (h _ _ hi hb).1, fun j hj ↦ (h _ _ ha hj).2⟩⟩ + +/-- See also `Finset.prodMk_sup'_sup'`. -/ +-- @[simp] -- TODO: Why does `Prod_map` simplify the LHS? +lemma sup'_prodMap (hst : (s ×ˢ t).Nonempty) (f : ι → α) (g : κ → β) : + sup' (s ×ˢ t) hst (Prod.map f g) = (sup' s hst.fst f, sup' t hst.snd g) := + (prodMk_sup'_sup' _ _ _ _).symm + +end Prod + theorem comp_sup'_eq_sup'_comp [SemilatticeSup γ] {s : Finset β} (H : s.Nonempty) {f : β → α} (g : α → γ) (g_sup : ∀ x y, g (x ⊔ y) = g x ⊔ g y) : g (s.sup' H f) = s.sup' H (g ∘ f) := by rw [← WithBot.coe_eq_coe, coe_sup'] @@ -1005,6 +1045,22 @@ theorem inf'_product_right {t : Finset γ} (hs : s.Nonempty) (ht : t.Nonempty) ( @sup'_product_right αᵒᵈ _ _ _ _ _ hs ht _ #align finset.inf'_product_right Finset.inf'_product_right +section Prod +variable {ι κ α β : Type*} [SemilatticeInf α] [SemilatticeInf β] {s : Finset ι} {t : Finset κ} + +/-- See also `Finset.inf'_prodMap`. -/ +lemma prodMk_inf'_inf' (hs : s.Nonempty) (ht : t.Nonempty) (f : ι → α) (g : κ → β) : + (inf' s hs f, inf' t ht g) = inf' (s ×ˢ t) (hs.product ht) (Prod.map f g) := + prodMk_sup'_sup' (α := αᵒᵈ) (β := βᵒᵈ) hs ht _ _ + +/-- See also `Finset.prodMk_inf'_inf'`. -/ +-- @[simp] -- TODO: Why does `Prod_map` simplify the LHS? +lemma inf'_prodMap (hst : (s ×ˢ t).Nonempty) (f : ι → α) (g : κ → β) : + inf' (s ×ˢ t) hst (Prod.map f g) = (inf' s hst.fst f, inf' t hst.snd g) := + (prodMk_inf'_inf' _ _ _ _).symm + +end Prod + theorem comp_inf'_eq_inf'_comp [SemilatticeInf γ] {s : Finset β} (H : s.Nonempty) {f : β → α} (g : α → γ) (g_inf : ∀ x y, g (x ⊓ y) = g x ⊓ g y) : g (s.inf' H f) = s.inf' H (g ∘ f) := comp_sup'_eq_sup'_comp (α := αᵒᵈ) (γ := γᵒᵈ) H g g_inf From 7d3d6e43b685327db5942f774dfd160e0a94f15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 27 Dec 2023 09:01:58 +0000 Subject: [PATCH 239/353] chore: Improve `Finset` lemma names (#8894) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change a few lemma names that have historically bothered me. * `Finset.card_le_of_subset` → `Finset.card_le_card` * `Multiset.card_le_of_le` → `Multiset.card_le_card` * `Multiset.card_lt_of_lt` → `Multiset.card_lt_card` * `Set.ncard_le_of_subset` → `Set.ncard_le_ncard` * `Finset.image_filter` → `Finset.filter_image` * `CompleteLattice.finset_sup_compact_of_compact` → `CompleteLattice.isCompactElement_finset_sup` --- Archive/Imo/Imo1994Q1.lean | 2 +- Archive/Imo/Imo2006Q5.lean | 6 +-- Archive/Sensitivity.lean | 2 +- .../AscendingDescendingSequences.lean | 2 +- .../SumOfPrimeReciprocalsDiverges.lean | 6 +-- Mathlib/Algebra/BigOperators/Order.lean | 2 +- Mathlib/Algebra/Module/Zlattice.lean | 2 +- Mathlib/Analysis/BoxIntegral/Basic.lean | 2 +- .../BoxIntegral/Partition/Tagged.lean | 2 +- Mathlib/Combinatorics/Additive/Energy.lean | 2 +- .../Additive/PluenneckeRuzsa.lean | 6 +-- .../Combinatorics/Additive/RuzsaCovering.lean | 2 +- .../Combinatorics/Additive/SalemSpencer.lean | 4 +- Mathlib/Combinatorics/Hall/Basic.lean | 2 +- Mathlib/Combinatorics/Hall/Finite.lean | 4 +- Mathlib/Combinatorics/Schnirelmann.lean | 8 ++-- .../SetFamily/Compression/Down.lean | 2 +- .../SetFamily/Compression/UV.lean | 6 +-- .../SetFamily/HarrisKleitman.lean | 6 +-- Mathlib/Combinatorics/SetFamily/Kleitman.lean | 6 +-- Mathlib/Combinatorics/SetFamily/LYM.lean | 6 +-- Mathlib/Combinatorics/SetFamily/Shadow.lean | 2 +- Mathlib/Combinatorics/SetFamily/Shatter.lean | 2 +- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 8 ++-- .../Combinatorics/SimpleGraph/Density.lean | 6 +-- .../SimpleGraph/Regularity/Bound.lean | 2 +- .../SimpleGraph/Regularity/Chunk.lean | 6 +-- .../SimpleGraph/Regularity/Equitabilise.lean | 6 +-- .../SimpleGraph/Regularity/Uniform.lean | 2 +- .../Combinatorics/SimpleGraph/Subgraph.lean | 4 +- Mathlib/Data/Finset/Card.lean | 31 +++++++++------ Mathlib/Data/Finset/Grade.lean | 4 +- Mathlib/Data/Finset/Image.lean | 16 +++++++- Mathlib/Data/Finset/LocallyFinite.lean | 2 +- Mathlib/Data/Finset/NAry.lean | 4 +- Mathlib/Data/Finset/Powerset.lean | 4 +- Mathlib/Data/Finset/Slice.lean | 2 +- Mathlib/Data/Finset/Sups.lean | 2 +- Mathlib/Data/Finsupp/Multiset.lean | 2 +- Mathlib/Data/Fintype/Card.lean | 2 +- Mathlib/Data/Matroid/Basic.lean | 2 +- Mathlib/Data/Matroid/IndepAxioms.lean | 4 +- Mathlib/Data/Multiset/Basic.lean | 39 ++++++++++++------- Mathlib/Data/MvPolynomial/Variables.lean | 2 +- Mathlib/Data/Nat/Choose/Sum.lean | 2 +- Mathlib/Data/Nat/Count.lean | 2 +- .../Data/Polynomial/Degree/Definitions.lean | 4 +- Mathlib/Data/Polynomial/Monomial.lean | 2 +- Mathlib/Data/Polynomial/RingDivision.lean | 4 +- Mathlib/Data/Set/Card.lean | 32 +++++++++------ Mathlib/Data/Set/Finite.lean | 4 +- Mathlib/Data/Setoid/Partition.lean | 2 +- Mathlib/FieldTheory/Adjoin.lean | 2 +- .../GroupTheory/SpecificGroups/Cyclic.lean | 2 +- Mathlib/LinearAlgebra/Lagrange.lean | 2 +- Mathlib/LinearAlgebra/LinearIndependent.lean | 2 +- Mathlib/LinearAlgebra/Multilinear/Basic.lean | 4 +- Mathlib/LinearAlgebra/Span.lean | 2 +- Mathlib/NumberTheory/Bertrand.lean | 2 +- Mathlib/NumberTheory/PrimeCounting.lean | 2 +- Mathlib/Order/CompactlyGenerated.lean | 4 +- Mathlib/Order/Partition/Finpartition.lean | 4 +- Mathlib/RingTheory/ChainOfDivisors.lean | 4 +- Mathlib/RingTheory/Finiteness.lean | 2 +- Mathlib/RingTheory/RootsOfUnity/Basic.lean | 6 +-- Mathlib/RingTheory/RootsOfUnity/Minpoly.lean | 2 +- .../SetTheory/Cardinal/CountableCover.lean | 2 +- 67 files changed, 182 insertions(+), 146 deletions(-) diff --git a/Archive/Imo/Imo1994Q1.lean b/Archive/Imo/Imo1994Q1.lean index 51ca17387c707..5cbb21987c1de 100644 --- a/Archive/Imo/Imo1994Q1.lean +++ b/Archive/Imo/Imo1994Q1.lean @@ -97,5 +97,5 @@ theorem imo1994_q1 (n : ℕ) (m : ℕ) (A : Finset ℕ) (hm : A.card = m + 1) rw [← a.strictMono.lt_iff_lt, hj] simpa using (hrange (a i) (ha i)).1 -- A set of size `k+1` embed in one of size `k`, which yields a contradiction - simpa [Fin.coe_sub, tedious] using card_le_of_subset hf + simpa [Fin.coe_sub, tedious] using card_le_card hf #align imo1994_q1 imo1994_q1 diff --git a/Archive/Imo/Imo2006Q5.lean b/Archive/Imo/Imo2006Q5.lean index f8f94c9c4b401..4df4f6ce726c8 100644 --- a/Archive/Imo/Imo2006Q5.lean +++ b/Archive/Imo/Imo2006Q5.lean @@ -145,7 +145,7 @@ theorem imo2006_q5' {P : Polynomial ℤ} (hP : 1 < P.natDegree) : exact (zero_le_one.not_lt hP).elim -- If every root of P(P(t)) - t is also a root of P(t) - t, then we're done. by_cases H : (P.comp P - X).roots.toFinset ⊆ (P - X).roots.toFinset - · exact (Finset.card_le_of_subset H).trans + · exact (Finset.card_le_card H).trans ((Multiset.toFinset_card_le _).trans ((card_roots' _).trans_eq hPX)) -- Otherwise, take a, b with P(a) = b, P(b) = a, a ≠ b. · rcases Finset.not_subset.1 H with ⟨a, ha, hab⟩ @@ -170,7 +170,7 @@ theorem imo2006_q5' {P : Polynomial ℤ} (hP : 1 < P.natDegree) : -- We claim that every root of P(P(t)) - t is a root of P(t) + t - a - b. This allows us to -- conclude the problem. suffices H' : (P.comp P - X).roots.toFinset ⊆ (P + (X : ℤ[X]) - a - b).roots.toFinset - · exact (Finset.card_le_of_subset H').trans + · exact (Finset.card_le_card H').trans ((Multiset.toFinset_card_le _).trans <| (card_roots' _).trans_eq hPab) · -- Let t be a root of P(P(t)) - t, define u = P(t). intro t ht @@ -196,7 +196,7 @@ open Imo2006Q5 /-- The general problem follows easily from the k = 2 case. -/ theorem imo2006_q5 {P : Polynomial ℤ} (hP : 1 < P.natDegree) {k : ℕ} (hk : 0 < k) : (P.comp^[k] X - X).roots.toFinset.card ≤ P.natDegree := by - refine' (Finset.card_le_of_subset fun t ht => _).trans (imo2006_q5' hP) + refine' (Finset.card_le_card fun t ht => _).trans (imo2006_q5' hP) have hP' : P.comp P - X ≠ 0 := by simpa [Nat.iterate] using Polynomial.iterate_comp_sub_X_ne hP zero_lt_two replace ht := isRoot_of_mem_roots (Multiset.mem_toFinset.1 ht) diff --git a/Archive/Sensitivity.lean b/Archive/Sensitivity.lean index 72843a130f39c..beaacbc8462f3 100644 --- a/Archive/Sensitivity.lean +++ b/Archive/Sensitivity.lean @@ -470,7 +470,7 @@ theorem huang_degree_theorem (H : Set (Q m.succ)) (hH : Card H ≥ 2 ^ m + 1) : _ ≤ Finset.card (H ∩ q.adjacent).toFinset * |ε q y| := by refine' (mul_le_mul_right H_q_pos).2 _ norm_cast - apply Finset.card_le_of_subset + apply Finset.card_le_card rw [Set.toFinset_inter] convert Finset.inter_subset_inter_right coeffs_support #align sensitivity.huang_degree_theorem Sensitivity.huang_degree_theorem diff --git a/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean b/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean index 3c88750dac1e8..c31f424e6f56d 100644 --- a/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean +++ b/Archive/Wiedijk100Theorems/AscendingDescendingSequences.lean @@ -166,7 +166,7 @@ theorem erdos_szekeres {r s n : ℕ} {f : Fin n → α} (hn : r * s < n) (hf : I -- To get our contradiction, it suffices to prove `n ≤ r * s` apply not_le_of_lt hn -- Which follows from considering the cardinalities of the subset above, since `ab` is injective. - simpa [Nat.succ_injective, card_image_of_injective, ‹Injective ab›] using card_le_of_subset this + simpa [Nat.succ_injective, card_image_of_injective, ‹Injective ab›] using card_le_card this #align theorems_100.erdos_szekeres Theorems100.erdos_szekeres end Theorems100 diff --git a/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean b/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean index 66e17dcf383cb..703bcc6354845 100644 --- a/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean +++ b/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean @@ -165,7 +165,7 @@ theorem card_le_two_pow {x k : ℕ} : -- The number of elements of `M x k` with `e + 1` squarefree is bounded by the number of subsets -- of `[1, k]`. calc - card M₁ ≤ card (image f K) := card_le_of_subset h + card M₁ ≤ card (image f K) := card_le_card h _ ≤ card K := card_image_le _ ≤ 2 ^ card (image Nat.succ (range k)) := by simp only [card_powerset]; rfl _ ≤ 2 ^ card (range k) := (pow_le_pow_right one_le_two card_image_le) @@ -200,9 +200,9 @@ theorem card_le_two_pow_mul_sqrt {x k : ℕ} : card (M x k) ≤ 2 ^ k * Nat.sqrt _ ≤ x.sqrt := Nat.sqrt_le_sqrt (Nat.succ_le_iff.mpr hm.1) · exact hm.2 p ⟨hp.1, hp.2.trans (Nat.dvd_of_pow_dvd one_le_two hbm)⟩ have h2 : card M₂ ≤ Nat.sqrt x := by - rw [← card_range (Nat.sqrt x)]; apply card_le_of_subset; simp [M] + rw [← card_range (Nat.sqrt x)]; apply card_le_card; simp [M] calc - card (M x k) ≤ card (image f K) := card_le_of_subset h1 + card (M x k) ≤ card (image f K) := card_le_card h1 _ ≤ card K := card_image_le _ = card M₁ * card M₂ := (card_product M₁ M₂) _ ≤ 2 ^ k * x.sqrt := mul_le_mul' card_le_two_pow h2 diff --git a/Mathlib/Algebra/BigOperators/Order.lean b/Mathlib/Algebra/BigOperators/Order.lean index 4df228d936023..e3f0dedb9ff23 100644 --- a/Mathlib/Algebra/BigOperators/Order.lean +++ b/Mathlib/Algebra/BigOperators/Order.lean @@ -385,7 +385,7 @@ theorem card_le_card_biUnion_add_card_fiber {s : Finset ι} {f : ι → Finset add_le_add_right ((card_le_card_biUnion (hs.subset <| filter_subset _ _) fun i hi ↦ nonempty_of_ne_empty <| (mem_filter.1 hi).2).trans <| - card_le_of_subset <| biUnion_subset_biUnion_of_subset_left _ <| filter_subset _ _) + card_le_card <| biUnion_subset_biUnion_of_subset_left _ <| filter_subset _ _) _ #align finset.card_le_card_bUnion_add_card_fiber Finset.card_le_card_biUnion_add_card_fiber diff --git a/Mathlib/Algebra/Module/Zlattice.lean b/Mathlib/Algebra/Module/Zlattice.lean index ca92331e58b2d..78231025e212e 100644 --- a/Mathlib/Algebra/Module/Zlattice.lean +++ b/Mathlib/Algebra/Module/Zlattice.lean @@ -462,7 +462,7 @@ theorem Zlattice.rank : finrank ℤ L = finrank K E := by contrapose h rw [Finset.not_nonempty_iff_eq_empty, Set.toFinset_diff, Finset.sdiff_eq_empty_iff_subset] at h - replace h := Finset.card_le_of_subset h + replace h := Finset.card_le_card h rwa [not_lt, h_card, ← topEquiv.finrank_eq, ← h_spanE, ← ht_span, finrank_span_set_eq_card _ ht_lin] -- Assume that `e ∪ {v}` is not `ℤ`-linear independent then we get the contradiction diff --git a/Mathlib/Analysis/BoxIntegral/Basic.lean b/Mathlib/Analysis/BoxIntegral/Basic.lean index 5f127649461bd..b1055deb96636 100644 --- a/Mathlib/Analysis/BoxIntegral/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Basic.lean @@ -767,7 +767,7 @@ theorem HasIntegral.of_bRiemann_eq_false_of_forall_isLittleO (hl : l.bRiemann = · rintro b - rw [← Nat.cast_two, ← Nat.cast_pow, ← nsmul_eq_mul] refine' nsmul_le_nsmul_left (hεs0 _).le _ - refine' (Finset.card_le_of_subset _).trans ((hπδ.isHenstock hlH).card_filter_tag_eq_le b) + refine' (Finset.card_le_card _).trans ((hπδ.isHenstock hlH).card_filter_tag_eq_le b) exact filter_subset_filter _ (filter_subset _ _) · rw [Finset.coe_image, Set.image_subset_iff] exact fun J hJ => (Finset.mem_filter.1 hJ).2 diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean b/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean index 1883840bba322..3cc2247862b0a 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean @@ -237,7 +237,7 @@ theorem IsHenstock.card_filter_tag_eq_le [Fintype ι] (h : π.IsHenstock) (x : calc (π.boxes.filter fun J => π.tag J = x).card ≤ (π.boxes.filter fun J : Box ι => x ∈ Box.Icc J).card := by - refine' Finset.card_le_of_subset fun J hJ => _ + refine' Finset.card_le_card fun J hJ => _ rw [Finset.mem_filter] at hJ ⊢; rcases hJ with ⟨hJ, rfl⟩ exact ⟨hJ, h J hJ⟩ _ ≤ 2 ^ Fintype.card ι := π.toPrepartition.card_filter_mem_Icc_le x diff --git a/Mathlib/Combinatorics/Additive/Energy.lean b/Mathlib/Combinatorics/Additive/Energy.lean index f74d417610f02..5bd859236121c 100644 --- a/Mathlib/Combinatorics/Additive/Energy.lean +++ b/Mathlib/Combinatorics/Additive/Energy.lean @@ -48,7 +48,7 @@ def multiplicativeEnergy (s t : Finset α) : ℕ := @[to_additive additiveEnergy_mono] theorem multiplicativeEnergy_mono (hs : s₁ ⊆ s₂) (ht : t₁ ⊆ t₂) : multiplicativeEnergy s₁ t₁ ≤ multiplicativeEnergy s₂ t₂ := - card_le_of_subset <| + card_le_card <| filter_subset_filter _ <| product_subset_product (product_subset_product hs hs) <| product_subset_product ht ht #align finset.multiplicative_energy_mono Finset.multiplicativeEnergy_mono diff --git a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean index 0b3eb306ed10f..77af26cadd1a4 100644 --- a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean +++ b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean @@ -105,7 +105,7 @@ theorem mul_pluennecke_petridis (C : Finset α) have h₃ : (A * B * C').card ≤ (A * B * C).card + (A * B).card - (A' * B).card := by rw [h₁] refine' (card_union_le _ _).trans_eq _ - rw [card_sdiff h₂, ← add_tsub_assoc_of_le (card_le_of_subset h₂), card_mul_singleton, + rw [card_sdiff h₂, ← add_tsub_assoc_of_le (card_le_card h₂), card_mul_singleton, card_mul_singleton] refine' (mul_le_mul_right' h₃ _).trans _ rw [tsub_mul, add_mul] @@ -150,7 +150,7 @@ theorem card_mul_mul_card_le_card_mul_mul_card_mul (A B C : Finset α) : rw [mul_div_right_comm, mul_comm _ B] refine' (cast_le.2 <| card_le_card_mul_left _ hU.1).trans _ refine' le_trans _ - (mul_le_mul (hUA _ hB') (cast_le.2 <| card_le_of_subset <| mul_subset_mul_right hU.2) + (mul_le_mul (hUA _ hB') (cast_le.2 <| card_le_card <| mul_subset_mul_right hU.2) (zero_le _) (zero_le _)) rw [← mul_div_right_comm, ← mul_assoc] refine' (le_div_iff <| cast_pos.2 hU.1.card_pos).2 _ @@ -229,7 +229,7 @@ theorem card_pow_div_pow_le (hA : A.Nonempty) (B : Finset α) (m n : ℕ) : rw [mul_mul_mul_comm, ← pow_add, ← mul_assoc] gcongr ((?_ ^ _) * Nat.cast ?_) * _ · exact hCA _ hA' - · exact card_le_of_subset hC.2 + · exact card_le_card hC.2 #align finset.card_pow_div_pow_le Finset.card_pow_div_pow_le #align finset.card_nsmul_sub_nsmul_le Finset.card_nsmul_sub_nsmul_le diff --git a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean index b0551f599bb24..33a24846b4381 100644 --- a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean +++ b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean @@ -37,7 +37,7 @@ theorem exists_subset_mul_div (ht : t.Nonempty) : rw [mem_filter, mem_powerset] at hu refine' ⟨u, (card_mul_iff.2 <| pairwiseDisjoint_smul_iff.1 hu.2).ge.trans - (card_le_of_subset <| mul_subset_mul_right hu.1), + (card_le_card <| mul_subset_mul_right hu.1), fun a ha ↦ _⟩ rw [mul_div_assoc] by_cases hau : a ∈ u diff --git a/Mathlib/Combinatorics/Additive/SalemSpencer.lean b/Mathlib/Combinatorics/Additive/SalemSpencer.lean index 69cbcf4078977..a59f7cb0eeb76 100644 --- a/Mathlib/Combinatorics/Additive/SalemSpencer.lean +++ b/Mathlib/Combinatorics/Additive/SalemSpencer.lean @@ -324,7 +324,7 @@ def mulRothNumber : Finset α →o ℕ := Nat.findGreatest (fun m => ∃ (t : _) (_ : t ⊆ s), t.card = m ∧ MulSalemSpencer (t : Set α)) s.card, by rintro t u htu - refine' Nat.findGreatest_mono (fun m => _) (card_le_of_subset htu) + refine' Nat.findGreatest_mono (fun m => _) (card_le_card htu) rintro ⟨v, hvt, hv⟩ exact ⟨v, hvt.trans htu, hv⟩⟩ #align mul_roth_number mulRothNumber @@ -349,7 +349,7 @@ variable {s t} {n : ℕ} @[to_additive] theorem MulSalemSpencer.le_mulRothNumber (hs : MulSalemSpencer (s : Set α)) (h : s ⊆ t) : s.card ≤ mulRothNumber t := - le_findGreatest (card_le_of_subset h) ⟨s, h, rfl, hs⟩ + le_findGreatest (card_le_card h) ⟨s, h, rfl, hs⟩ #align mul_salem_spencer.le_mul_roth_number MulSalemSpencer.le_mulRothNumber #align add_salem_spencer.le_add_roth_number AddSalemSpencer.le_addRothNumber diff --git a/Mathlib/Combinatorics/Hall/Basic.lean b/Mathlib/Combinatorics/Hall/Basic.lean index 950095a22366a..e56f1697b89b1 100644 --- a/Mathlib/Combinatorics/Hall/Basic.lean +++ b/Mathlib/Combinatorics/Hall/Basic.lean @@ -156,7 +156,7 @@ theorem Finset.all_card_le_biUnion_card_iff_exists_injective {ι : Type u} {α : · -- The reverse direction is a straightforward cardinality argument rintro ⟨f, hf₁, hf₂⟩ s rw [← Finset.card_image_of_injective s hf₁] - apply Finset.card_le_of_subset + apply Finset.card_le_card intro rw [Finset.mem_image, Finset.mem_biUnion] rintro ⟨x, hx, rfl⟩ diff --git a/Mathlib/Combinatorics/Hall/Finite.lean b/Mathlib/Combinatorics/Hall/Finite.lean index c2bff7c6070dd..ee952b778c794 100644 --- a/Mathlib/Combinatorics/Hall/Finite.lean +++ b/Mathlib/Combinatorics/Hall/Finite.lean @@ -147,7 +147,7 @@ theorem hall_cond_of_compl {ι : Type u} {t : ι → Finset α} {s : Finset ι} rw [this, hus] refine' (tsub_le_tsub_right (ht _) _).trans _ rw [← card_sdiff] - · refine' (card_le_of_subset _).trans le_rfl + · refine' (card_le_card _).trans le_rfl intro t simp only [mem_biUnion, mem_sdiff, not_exists, mem_image, and_imp, mem_union, exists_and_right, exists_imp] @@ -261,7 +261,7 @@ theorem Finset.all_card_le_biUnion_card_iff_existsInjective' {ι α : Type*} [Fi · exact HallMarriageTheorem.hall_hard_inductive · rintro ⟨f, hf₁, hf₂⟩ s rw [← card_image_of_injective s hf₁] - apply card_le_of_subset + apply card_le_card intro rw [mem_image, mem_biUnion] rintro ⟨x, hx, rfl⟩ diff --git a/Mathlib/Combinatorics/Schnirelmann.lean b/Mathlib/Combinatorics/Schnirelmann.lean index 1ee1ab2176b1c..2c286d7b988ec 100644 --- a/Mathlib/Combinatorics/Schnirelmann.lean +++ b/Mathlib/Combinatorics/Schnirelmann.lean @@ -94,7 +94,7 @@ lemma schnirelmannDensity_le_of_not_mem {k : ℕ} (hk : k ∉ A) : rw [← one_div, one_sub_div (Nat.cast_pos.2 hk').ne'] apply div_le_div_of_le (Nat.cast_nonneg _) rw [← Nat.cast_pred hk', Nat.cast_le] - suffices : (Ioc 0 k).filter (· ∈ A) ⊆ Ioo 0 k; exact (card_le_of_subset this).trans_eq (by simp) + suffices : (Ioc 0 k).filter (· ∈ A) ⊆ Ioo 0 k; exact (card_le_card this).trans_eq (by simp) rw [← Ioo_insert_right hk', filter_insert, if_neg hk] exact filter_subset _ _ @@ -106,7 +106,7 @@ lemma schnirelmannDensity_eq_zero_of_one_not_mem (h : 1 ∉ A) : schnirelmannDen lemma schnirelmannDensity_le_of_subset {B : Set ℕ} [DecidablePred (· ∈ B)] (h : A ⊆ B) : schnirelmannDensity A ≤ schnirelmannDensity B := ciInf_mono ⟨0, fun _ ⟨_, hx⟩ => hx ▸ by positivity⟩ fun _ => div_le_div_of_le (by positivity) <| - Nat.cast_le.2 <| card_le_of_subset <| monotone_filter_right _ h + Nat.cast_le.2 <| card_le_card <| monotone_filter_right _ h /-- The Schnirelmann density of `A` is `1` if and only if `A` contains all the positive naturals. -/ lemma schnirelmannDensity_eq_one_iff : schnirelmannDensity A = 1 ↔ {0}ᶜ ⊆ A := by @@ -196,7 +196,7 @@ lemma schnirelmannDensity_finset (A : Finset ℕ) : schnirelmannDensity A = 0 := use n, hn rw [div_lt_iff (Nat.cast_pos.2 hn), ← div_lt_iff' hε, Nat.cast_add_one] exact (Nat.lt_floor_add_one _).trans_le' <| div_le_div_of_le hε.le <| Nat.cast_le.2 <| - card_le_of_subset <| by simp [subset_iff] + card_le_card <| by simp [subset_iff] /-- The Schnirelmann density of any finite set is `0`. -/ lemma schnirelmannDensity_finite {A : Set ℕ} [DecidablePred (· ∈ A)] (hA : A.Finite) : @@ -243,7 +243,7 @@ lemma schnirelmannDensity_setOf_mod_eq_one {m : ℕ} (hm : m ≠ 1) : ← Nat.le_sub_iff_add_le hn, zero_lt_one] exact Nat.mul_le_of_le_div _ _ _ hy' rw [le_div_iff (Nat.cast_pos.2 hn), mul_comm, ← div_eq_mul_inv] - apply (Nat.cast_le.2 (card_le_of_subset this)).trans' + apply (Nat.cast_le.2 (card_le_card this)).trans' rw [card_image_of_injective, Nat.card_Icc, Nat.sub_zero, div_le_iff (Nat.cast_pos.2 hm'), ← Nat.cast_mul, Nat.cast_le, add_one_mul (α := ℕ)] · have := @Nat.lt_div_mul_add n.pred m hm' diff --git a/Mathlib/Combinatorics/SetFamily/Compression/Down.lean b/Mathlib/Combinatorics/SetFamily/Compression/Down.lean index b61299d7e64d6..aca1b699b68e7 100644 --- a/Mathlib/Combinatorics/SetFamily/Compression/Down.lean +++ b/Mathlib/Combinatorics/SetFamily/Compression/Down.lean @@ -282,7 +282,7 @@ theorem compression_idem (a : α) (𝒜 : Finset (Finset α)) : 𝓓 a (𝓓 a /-- Down-compressing a family doesn't change its size. -/ @[simp] theorem card_compression (a : α) (𝒜 : Finset (Finset α)) : (𝓓 a 𝒜).card = 𝒜.card := by - rw [compression, card_disjUnion, image_filter, + rw [compression, card_disjUnion, filter_image, card_image_of_injOn ((erase_injOn' _).mono fun s hs => _), ← card_disjoint_union] · conv_rhs => rw [← filter_union_filter_neg_eq (fun s => (erase s a ∈ 𝒜)) 𝒜] · exact disjoint_filter_filter_neg 𝒜 𝒜 (fun s => (erase s a ∈ 𝒜)) diff --git a/Mathlib/Combinatorics/SetFamily/Compression/UV.lean b/Mathlib/Combinatorics/SetFamily/Compression/UV.lean index f9370d6f7256d..a7dc5260daf15 100644 --- a/Mathlib/Combinatorics/SetFamily/Compression/UV.lean +++ b/Mathlib/Combinatorics/SetFamily/Compression/UV.lean @@ -205,14 +205,14 @@ theorem compress_mem_compression_of_mem_compression (ha : a ∈ 𝓒 u v s) : theorem compression_idem (u v : α) (s : Finset α) : 𝓒 u v (𝓒 u v s) = 𝓒 u v s := by have h : filter (compress u v · ∉ 𝓒 u v s) (𝓒 u v s) = ∅ := filter_false_of_mem fun a ha h ↦ h <| compress_mem_compression_of_mem_compression ha - rw [compression, image_filter, h, image_empty, ← h] + rw [compression, filter_image, h, image_empty, ← h] exact filter_union_filter_neg_eq _ (compression u v s) #align uv.compression_idem UV.compression_idem /-- Compressing a family doesn't change its size. -/ @[simp] theorem card_compression (u v : α) (s : Finset α) : (𝓒 u v s).card = s.card := by - rw [compression, card_disjoint_union compress_disjoint, image_filter, + rw [compression, card_disjoint_union compress_disjoint, filter_image, card_image_of_injOn compress_injOn, ← card_disjoint_union (disjoint_filter_filter_neg s _ _), filter_union_filter_neg_eq] #align uv.card_compression UV.card_compression @@ -427,7 +427,7 @@ Kruskal-Katona. -/ theorem card_shadow_compression_le (u v : Finset α) (huv : ∀ x ∈ u, ∃ y ∈ v, IsCompressed (u.erase x) (v.erase y) 𝒜) : (∂ (𝓒 u v 𝒜)).card ≤ (∂ 𝒜).card := - (card_le_of_subset <| shadow_compression_subset_compression_shadow _ _ huv).trans + (card_le_card <| shadow_compression_subset_compression_shadow _ _ huv).trans (card_compression _ _ _).le #align uv.card_shadow_compression_le UV.card_shadow_compression_le diff --git a/Mathlib/Combinatorics/SetFamily/HarrisKleitman.lean b/Mathlib/Combinatorics/SetFamily/HarrisKleitman.lean index 0edfa6f513ebf..653905311681f 100644 --- a/Mathlib/Combinatorics/SetFamily/HarrisKleitman.lean +++ b/Mathlib/Combinatorics/SetFamily/HarrisKleitman.lean @@ -70,8 +70,8 @@ theorem IsLowerSet.le_card_inter_finset' (h𝒜 : IsLowerSet (𝒜 : Set (Finset refine' (add_le_add_right (mul_add_mul_le_mul_add_mul - (card_le_of_subset h𝒜.memberSubfamily_subset_nonMemberSubfamily) <| - card_le_of_subset hℬ.memberSubfamily_subset_nonMemberSubfamily) + (card_le_card h𝒜.memberSubfamily_subset_nonMemberSubfamily) <| + card_le_card hℬ.memberSubfamily_subset_nonMemberSubfamily) _).trans _ rw [← two_mul, pow_succ, mul_assoc] @@ -128,7 +128,7 @@ theorem IsUpperSet.le_card_inter_finset (h𝒜 : IsUpperSet (𝒜 : Set (Finset rwa [card_compl, Fintype.card_finset, tsub_mul, le_tsub_iff_le_tsub, ← mul_tsub, ← card_sdiff (inter_subset_right _ _), sdiff_inter_self_right, sdiff_compl, _root_.inf_comm] at this - · exact mul_le_mul_left' (card_le_of_subset <| inter_subset_right _ _) _ + · exact mul_le_mul_left' (card_le_card <| inter_subset_right _ _) _ · rw [← Fintype.card_finset] exact mul_le_mul_right' (card_le_univ _) _ #align is_upper_set.le_card_inter_finset IsUpperSet.le_card_inter_finset diff --git a/Mathlib/Combinatorics/SetFamily/Kleitman.lean b/Mathlib/Combinatorics/SetFamily/Kleitman.lean index 559b18e16d228..c10270e2abd57 100644 --- a/Mathlib/Combinatorics/SetFamily/Kleitman.lean +++ b/Mathlib/Combinatorics/SetFamily/Kleitman.lean @@ -42,7 +42,7 @@ theorem Finset.card_biUnion_le_of_intersecting (s : Finset ι) (f : ι → Finse infer_instance obtain hs | hs := le_total (Fintype.card α) s.card · rw [tsub_eq_zero_of_le hs, pow_zero] - refine' (card_le_of_subset <| biUnion_subset.2 fun i hi a ha ↦ + refine' (card_le_card <| biUnion_subset.2 fun i hi a ha ↦ mem_compl.2 <| not_mem_singleton.2 <| (hf _ hi).ne_bot ha).trans_eq _ rw [card_compl, Fintype.card_finset, card_singleton] induction' s using Finset.cons_induction with i s hi ih generalizing f @@ -58,7 +58,7 @@ theorem Finset.card_biUnion_le_of_intersecting (s : Finset ι) (f : ι → Finse refine' fun j hj ↦ (hf₁ _ hj).2.2.isUpperSet' ((hf₁ _ hj).2.2.is_max_iff_card_eq.2 _) rw [Fintype.card_finset] exact (hf₁ _ hj).2.1 - refine' (card_le_of_subset <| biUnion_mono fun j hj ↦ (hf₁ _ hj).1).trans _ + refine' (card_le_card <| biUnion_mono fun j hj ↦ (hf₁ _ hj).1).trans _ nth_rw 1 [cons_eq_insert i] rw [biUnion_insert] refine' (card_mono <| @le_sup_sdiff _ _ _ <| f' i).trans ((card_union_le _ _).trans _) @@ -79,7 +79,7 @@ theorem Finset.card_biUnion_le_of_intersecting (s : Finset ι) (f : ι → Finse refine' mul_le_mul_left' _ _ refine' (add_le_add_left (ih _ (fun i hi ↦ (hf₁ _ <| subset_cons _ hi).2.2) - ((card_le_of_subset <| subset_cons _).trans hs)) _).trans _ + ((card_le_card <| subset_cons _).trans hs)) _).trans _ rw [mul_tsub, two_mul, ← pow_succ, ← add_tsub_assoc_of_le (pow_le_pow_right' (one_le_two : (1 : ℕ) ≤ 2) tsub_le_self), tsub_add_eq_add_tsub hs, card_cons, add_tsub_add_eq_tsub_right] diff --git a/Mathlib/Combinatorics/SetFamily/LYM.lean b/Mathlib/Combinatorics/SetFamily/LYM.lean index 2c98622a3067b..b29be947fbd0b 100644 --- a/Mathlib/Combinatorics/SetFamily/LYM.lean +++ b/Mathlib/Combinatorics/SetFamily/LYM.lean @@ -66,12 +66,12 @@ theorem card_mul_le_card_shadow_mul (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : let i : DecidableRel ((· ⊆ ·) : Finset α → Finset α → Prop) := fun _ _ => Classical.dec _ refine' card_mul_le_card_mul' (· ⊆ ·) (fun s hs => _) (fun s hs => _) · rw [← h𝒜 hs, ← card_image_of_injOn s.erase_injOn] - refine' card_le_of_subset _ + refine' card_le_card _ simp_rw [image_subset_iff, mem_bipartiteBelow] exact fun a ha => ⟨erase_mem_shadow hs ha, erase_subset _ _⟩ refine' le_trans _ tsub_tsub_le_tsub_add rw [← (Set.Sized.shadow h𝒜) hs, ← card_compl, ← card_image_of_injOn (insert_inj_on' _)] - refine' card_le_of_subset fun t ht => _ + refine' card_le_card fun t ht => _ -- porting note: commented out the following line -- infer_instance rw [mem_bipartiteAbove] at ht @@ -187,7 +187,7 @@ theorem le_card_falling_div_choose [Fintype α] (hk : k ≤ Fintype.card α) · simp only [tsub_zero, cast_one, cast_le, sum_singleton, div_one, choose_self, range_one, zero_eq, zero_add, range_one, ge_iff_le, sum_singleton, nonpos_iff_eq_zero, tsub_zero, choose_self, cast_one, div_one, cast_le] - exact card_le_of_subset (slice_subset_falling _ _) + exact card_le_card (slice_subset_falling _ _) rw [succ_eq_add_one] at * rw [sum_range_succ, ← slice_union_shadow_falling_succ, card_disjoint_union (IsAntichain.disjoint_slice_shadow_falling h𝒜), cast_add, _root_.add_div, diff --git a/Mathlib/Combinatorics/SetFamily/Shadow.lean b/Mathlib/Combinatorics/SetFamily/Shadow.lean index f1a348f3241c2..65c4b131cc20f 100644 --- a/Mathlib/Combinatorics/SetFamily/Shadow.lean +++ b/Mathlib/Combinatorics/SetFamily/Shadow.lean @@ -164,7 +164,7 @@ lemma _root_.Set.Sized.shadow_iterate (h𝒜 : (𝒜 : Set (Finset α)).Sized r) (∂^[k] 𝒜 : Set (Finset α)).Sized (r - k) := by simp_rw [Set.Sized, mem_coe, mem_shadow_iterate_iff_exists_sdiff] rintro t ⟨s, hs, hts, rfl⟩ - rw [card_sdiff hts, ← h𝒜 hs, Nat.sub_sub_self (card_le_of_subset hts)] + rw [card_sdiff hts, ← h𝒜 hs, Nat.sub_sub_self (card_le_card hts)] theorem sized_shadow_iff (h : ∅ ∉ 𝒜) : (∂ 𝒜 : Set (Finset α)).Sized r ↔ (𝒜 : Set (Finset α)).Sized (r + 1) := by diff --git a/Mathlib/Combinatorics/SetFamily/Shatter.lean b/Mathlib/Combinatorics/SetFamily/Shatter.lean index f2ad695c504a8..5c53b3c021c01 100644 --- a/Mathlib/Combinatorics/SetFamily/Shatter.lean +++ b/Mathlib/Combinatorics/SetFamily/Shatter.lean @@ -191,7 +191,7 @@ lemma vcDim_compress_le (a : α) (𝒜 : Finset (Finset α)) : (𝓓 a 𝒜).vcD lemma card_shatterer_le_sum_vcDim [Fintype α] : 𝒜.shatterer.card ≤ ∑ k in Iic 𝒜.vcDim, (Fintype.card α).choose k := by simp_rw [← card_univ, ← card_powersetCard] - refine (card_le_of_subset <| fun s hs ↦ mem_biUnion.2 ⟨card s, ?_⟩).trans card_biUnion_le + refine (card_le_card <| fun s hs ↦ mem_biUnion.2 ⟨card s, ?_⟩).trans card_biUnion_le exact ⟨mem_Iic.2 (mem_shatterer.1 hs).card_le_vcDim, mem_powersetCard_univ.2 rfl⟩ end Finset diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index b7ece6d9eed0b..500b7d23fdea4 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -1024,7 +1024,7 @@ theorem card_edgeFinset_top_eq_card_choose_two : /-- Any graph on `n` vertices has at most `n.choose 2` edges. -/ theorem card_edgeFinset_le_card_choose_two : G.edgeFinset.card ≤ (Fintype.card V).choose 2 := by rw [← card_edgeFinset_top_eq_card_choose_two] - exact card_le_of_subset (edgeFinset_mono le_top) + exact card_le_card (edgeFinset_mono le_top) end EdgeFinset @@ -1292,11 +1292,11 @@ theorem deleteFar_iff : refine ⟨fun h H _ hHG hH ↦ ?_, fun h s hs hG ↦ ?_⟩ · have := h (sdiff_subset G.edgeFinset H.edgeFinset) simp only [deleteEdges_sdiff_eq_of_le _ hHG, edgeFinset_mono hHG, card_sdiff, - card_le_of_subset, coe_sdiff, coe_edgeFinset, Nat.cast_sub] at this + card_le_card, coe_sdiff, coe_edgeFinset, Nat.cast_sub] at this exact this hH · classical simpa [card_sdiff hs, edgeFinset_deleteEdges, -Set.toFinset_card, Nat.cast_sub, - card_le_of_subset hs] using h (G.deleteEdges_le s) hG + card_le_card hs] using h (G.deleteEdges_le s) hG #align simple_graph.delete_far_iff SimpleGraph.deleteFar_iff alias ⟨DeleteFar.le_card_sub_card, _⟩ := deleteFar_iff @@ -1794,7 +1794,7 @@ theorem maxDegree_lt_card_verts [DecidableRel G.Adj] [Nonempty V] : theorem card_commonNeighbors_le_degree_left [DecidableRel G.Adj] (v w : V) : Fintype.card (G.commonNeighbors v w) ≤ G.degree v := by rw [← card_neighborSet_eq_degree] - exact Set.card_le_of_subset (Set.inter_subset_left _ _) + exact Set.card_le_card (Set.inter_subset_left _ _) #align simple_graph.card_common_neighbors_le_degree_left SimpleGraph.card_commonNeighbors_le_degree_left theorem card_commonNeighbors_le_degree_right [DecidableRel G.Adj] (v w : V) : diff --git a/Mathlib/Combinatorics/SimpleGraph/Density.lean b/Mathlib/Combinatorics/SimpleGraph/Density.lean index 84da478b504d2..e117a9e930cf8 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Density.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Density.lean @@ -187,7 +187,7 @@ theorem mul_edgeDensity_le_edgeDensity (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) have hst : (s₂.card : ℚ) * t₂.card ≠ 0 := by simp [hs₂.ne_empty, ht₂.ne_empty] rw [edgeDensity, edgeDensity, div_mul_div_comm, mul_comm, div_mul_div_cancel _ hst] refine' div_le_div_of_le (mod_cast (s₁.card * t₁.card).zero_le) _ - exact mod_cast card_le_of_subset (interedges_mono hs ht) + exact mod_cast card_le_card (interedges_mono hs ht) #align rel.mul_edge_density_le_edge_density Rel.mul_edgeDensity_le_edgeDensity theorem edgeDensity_sub_edgeDensity_le_one_sub_mul (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) (hs₂ : s₂.Nonempty) @@ -197,9 +197,9 @@ theorem edgeDensity_sub_edgeDensity_le_one_sub_mul (hs : s₂ ⊆ s₁) (ht : t refine' le_trans _ (mul_le_of_le_one_right _ (edgeDensity_le_one r s₂ t₂)) · rw [sub_mul, one_mul] refine' sub_nonneg_of_le (mul_le_one _ _ _) - · exact div_le_one_of_le ((@Nat.cast_le ℚ).2 (card_le_of_subset hs)) (Nat.cast_nonneg _) + · exact div_le_one_of_le ((@Nat.cast_le ℚ).2 (card_le_card hs)) (Nat.cast_nonneg _) · apply div_nonneg <;> exact mod_cast Nat.zero_le _ - · exact div_le_one_of_le ((@Nat.cast_le ℚ).2 (card_le_of_subset ht)) (Nat.cast_nonneg _) + · exact div_le_one_of_le ((@Nat.cast_le ℚ).2 (card_le_card ht)) (Nat.cast_nonneg _) #align rel.edge_density_sub_edge_density_le_one_sub_mul Rel.edgeDensity_sub_edgeDensity_le_one_sub_mul theorem abs_edgeDensity_sub_edgeDensity_le_one_sub_mul (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean index 0d5b6573704be..913cb8c960844 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean @@ -242,7 +242,7 @@ theorem add_div_le_sum_sq_div_card (hst : s ⊆ t) (f : ι → 𝕜) (d : 𝕜) d + s.card / t.card * x ^ 2 ≤ (∑ i in t, f i ^ 2) / t.card := by obtain hscard | hscard := (s.card.cast_nonneg : (0 : 𝕜) ≤ s.card).eq_or_lt · simpa [← hscard] using ht.trans sum_div_card_sq_le_sum_sq_div_card - have htcard : (0 : 𝕜) < t.card := hscard.trans_le (Nat.cast_le.2 (card_le_of_subset hst)) + have htcard : (0 : 𝕜) < t.card := hscard.trans_le (Nat.cast_le.2 (card_le_card hst)) have h₁ : x ^ 2 ≤ ((∑ i in s, f i) / s.card - (∑ i in t, f i) / t.card) ^ 2 := sq_le_sq.2 (by rwa [abs_of_nonneg hx]) have h₂ : x ^ 2 ≤ ((∑ i in s, (f i - (∑ j in t, f j) / t.card)) / s.card) ^ 2 := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean index 0b50659e47bda..f2edb74f00576 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean @@ -106,7 +106,7 @@ private theorem card_nonuniformWitness_sdiff_biUnion_star (hV : V ∈ P.parts) ( not_and, mem_sdiff, id.def, mem_sdiff] at hx ⊢ obtain ⟨⟨B, hB₁, hB₂⟩, hx⟩ := hx exact ⟨B, hB₁, hB₂, fun A hA AB => hx A hA <| AB.trans hB₁.2.1⟩ - apply (card_le_of_subset q).trans (card_biUnion_le.trans _) + apply (card_le_card q).trans (card_biUnion_le.trans _) trans ∑ _i in (atomise U <| P.nonuniformWitnesses G ε U).parts.filter fun B => B ⊆ G.nonuniformWitness ε U V ∧ B.Nonempty, m · suffices ∀ B ∈ (atomise U <| P.nonuniformWitnesses G ε U).parts, @@ -121,7 +121,7 @@ private theorem card_nonuniformWitness_sdiff_biUnion_star (hV : V ∈ P.parts) ( refine' mul_le_mul_right' _ _ have t := card_filter_atomise_le_two_pow (s := U) hX refine' t.trans (pow_le_pow_right (by norm_num) <| tsub_le_tsub_right _ _) - exact card_image_le.trans (card_le_of_subset <| filter_subset _ _) + exact card_image_le.trans (card_le_card <| filter_subset _ _) private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ P.parts) (hUV : U ≠ V) (hunif : ¬G.IsUniform ε U V) (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 5) @@ -170,7 +170,7 @@ private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ sz_positivity _ ≤ ((star hP G ε hU V).biUnion id).card := by rw [sub_le_comm, ← - cast_sub (card_le_of_subset <| biUnion_star_subset_nonuniformWitness hP G ε hU V), ← + cast_sub (card_le_card <| biUnion_star_subset_nonuniformWitness hP G ε hU V), ← card_sdiff (biUnion_star_subset_nonuniformWitness hP G ε hU V)] exact mod_cast card_nonuniformWitness_sdiff_biUnion_star hV hUV hunif diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean index 91fee035b2513..92fd8bf443629 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean @@ -89,7 +89,7 @@ theorem equitabilise_aux (hs : a * m + b * (m + 1) = s.card) : refine' ⟨R.extend ht.ne_empty sdiff_disjoint (sdiff_sup_cancel hts), _, _, _⟩ · simp only [extend_parts, mem_insert, forall_eq_or_imp, and_iff_left hR₁, htn, hn] exact ite_eq_or_eq _ _ _ - · exact fun x hx => (card_le_of_subset <| sdiff_subset _ _).trans (lt_succ_iff.1 <| h _ hx) + · exact fun x hx => (card_le_card <| sdiff_subset _ _).trans (lt_succ_iff.1 <| h _ hx) simp_rw [extend_parts, filter_insert, htn, m.succ_ne_self.symm.ite_eq_right_iff] split_ifs with ha · rw [hR₃, if_pos ha] @@ -110,13 +110,13 @@ theorem equitabilise_aux (hs : a * m + b * (m + 1) = s.card) : exact ite_eq_or_eq _ _ _ · conv in _ ∈ _ => rw [← insert_erase hu₁] simp only [and_imp, mem_insert, forall_eq_or_imp, Ne.def, extend_parts] - refine' ⟨_, fun x hx => (card_le_of_subset _).trans <| hR₂ x _⟩ + refine' ⟨_, fun x hx => (card_le_card _).trans <| hR₂ x _⟩ · simp only [filter_insert, if_pos htu, biUnion_insert, mem_erase, id.def] obtain rfl | hut := eq_or_ne u t · rw [sdiff_eq_empty_iff_subset.2 (subset_union_left _ _)] exact bot_le refine' - (card_le_of_subset fun i => _).trans + (card_le_card fun i => _).trans (hR₂ (u \ t) <| P.mem_avoid.2 ⟨u, hu₁, fun i => hut <| i.antisymm htu, rfl⟩) -- Porting note: `not_and` required because `∃ x ∈ s, p x` is defined differently simp only [not_exists, not_and, mem_biUnion, and_imp, mem_union, mem_filter, mem_sdiff, diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean index e16868c4389f3..20c3dd4db03eb 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean @@ -246,7 +246,7 @@ theorem isUniformOne : P.IsUniform G (1 : 𝕜) := by variable {P G} theorem IsUniform.mono {ε ε' : 𝕜} (hP : P.IsUniform G ε) (h : ε ≤ ε') : P.IsUniform G ε' := - ((Nat.cast_le.2 <| card_le_of_subset <| P.nonUniforms_mono G h).trans hP).trans <| by gcongr + ((Nat.cast_le.2 <| card_le_card <| P.nonUniforms_mono G h).trans hP).trans <| by gcongr #align finpartition.is_uniform.mono Finpartition.IsUniform.mono theorem isUniformOfEmpty (hP : P.parts = ∅) : P.IsUniform G ε := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index fb701994057ce..df9247de59504 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean @@ -802,12 +802,12 @@ theorem finset_card_neighborSet_eq_degree {G' : Subgraph G} {v : V} [Fintype (G' theorem degree_le (G' : Subgraph G) (v : V) [Fintype (G'.neighborSet v)] [Fintype (G.neighborSet v)] : G'.degree v ≤ G.degree v := by rw [← card_neighborSet_eq_degree] - exact Set.card_le_of_subset (G'.neighborSet_subset v) + exact Set.card_le_card (G'.neighborSet_subset v) #align simple_graph.subgraph.degree_le SimpleGraph.Subgraph.degree_le theorem degree_le' (G' G'' : Subgraph G) (h : G' ≤ G'') (v : V) [Fintype (G'.neighborSet v)] [Fintype (G''.neighborSet v)] : G'.degree v ≤ G''.degree v := - Set.card_le_of_subset (neighborSet_subset_of_subgraph h v) + Set.card_le_card (neighborSet_subset_of_subgraph h v) #align simple_graph.subgraph.degree_le' SimpleGraph.Subgraph.degree_le' @[simp] diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean index 8a0629a17e43e..25446a9b962ae 100644 --- a/Mathlib/Data/Finset/Card.lean +++ b/Mathlib/Data/Finset/Card.lean @@ -61,12 +61,12 @@ theorem card_empty : card (∅ : Finset α) = 0 := rfl #align finset.card_empty Finset.card_empty -theorem card_le_of_subset : s ⊆ t → s.card ≤ t.card := - Multiset.card_le_of_le ∘ val_le_iff.mpr -#align finset.card_le_of_subset Finset.card_le_of_subset +theorem card_le_card : s ⊆ t → s.card ≤ t.card := + Multiset.card_le_card ∘ val_le_iff.mpr +#align finset.card_le_of_subset Finset.card_le_card @[mono] -theorem card_mono : Monotone (@card α) := by apply card_le_of_subset +theorem card_mono : Monotone (@card α) := by apply card_le_card #align finset.card_mono Finset.card_mono @[simp] @@ -197,7 +197,7 @@ theorem Multiset.card_toFinset : m.toFinset.card = Multiset.card m.dedup := #align multiset.card_to_finset Multiset.card_toFinset theorem Multiset.toFinset_card_le : m.toFinset.card ≤ Multiset.card m := - card_le_of_le <| dedup_le _ + card_le_card <| dedup_le _ #align multiset.to_finset_card_le Multiset.toFinset_card_le theorem Multiset.toFinset_card_of_nodup {m : Multiset α} (h : m.Nodup) : @@ -284,7 +284,7 @@ theorem card_subtype (p : α → Prop) [DecidablePred p] (s : Finset α) : theorem card_filter_le (s : Finset α) (p : α → Prop) [DecidablePred p] : (s.filter p).card ≤ s.card := - card_le_of_subset <| filter_subset _ _ + card_le_card <| filter_subset _ _ #align finset.card_filter_le Finset.card_filter_le theorem eq_of_subset_of_card_le {s t : Finset α} (h : s ⊆ t) (h₂ : t.card ≤ s.card) : s = t := @@ -309,8 +309,7 @@ theorem filter_card_eq {p : α → Prop} [DecidablePred p] (h : (s.filter p).car exact hx.2 #align finset.filter_card_eq Finset.filter_card_eq -theorem card_lt_card (h : s ⊂ t) : s.card < t.card := - card_lt_of_lt <| val_lt_iff.2 h +nonrec lemma card_lt_card (h : s ⊂ t) : s.card < t.card := card_lt_card <| val_lt_iff.2 h #align finset.card_lt_card Finset.card_lt_card lemma card_strictMono : StrictMono (card : Finset α → ℕ) := fun _ _ ↦ card_lt_card @@ -357,7 +356,7 @@ theorem card_le_card_of_inj_on {t : Finset β} (f : α → β) (hf : ∀ a ∈ s (f_inj : ∀ a₁ ∈ s, ∀ a₂ ∈ s, f a₁ = f a₂ → a₁ = a₂) : s.card ≤ t.card := by classical calc s.card = (s.image f).card := (card_image_of_injOn f_inj).symm - _ ≤ t.card := card_le_of_subset <| image_subset_iff.2 hf + _ ≤ t.card := card_le_card <| image_subset_iff.2 hf #align finset.card_le_card_of_inj_on Finset.card_le_card_of_inj_on /-- If there are more pigeons than pigeonholes, then there are two pigeons in the same pigeonhole. @@ -460,13 +459,13 @@ theorem card_sdiff (h : s ⊆ t) : card (t \ s) = t.card - s.card := by #align finset.card_sdiff Finset.card_sdiff theorem card_sdiff_add_card_eq_card {s t : Finset α} (h : s ⊆ t) : card (t \ s) + card s = card t := - ((Nat.sub_eq_iff_eq_add (card_le_of_subset h)).mp (card_sdiff h).symm).symm + ((Nat.sub_eq_iff_eq_add (card_le_card h)).mp (card_sdiff h).symm).symm #align finset.card_sdiff_add_card_eq_card Finset.card_sdiff_add_card_eq_card theorem le_card_sdiff (s t : Finset α) : t.card - s.card ≤ card (t \ s) := calc card t - card s ≤ card t - card (s ∩ t) := - tsub_le_tsub_left (card_le_of_subset (inter_subset_left s t)) _ + tsub_le_tsub_left (card_le_card (inter_subset_left s t)) _ _ = card (t \ (s ∩ t)) := (card_sdiff (inter_subset_right s t)).symm _ ≤ card (t \ s) := by rw [sdiff_inter_self_right t s] #align finset.le_card_sdiff Finset.le_card_sdiff @@ -590,7 +589,7 @@ theorem card_le_one_iff_subset_singleton [Nonempty α] : s.card ≤ 1 ↔ ∃ x · exact ⟨x, fun y hy => by rw [card_le_one.1 H y hy x hx, mem_singleton]⟩ · rintro ⟨x, hx⟩ rw [← card_singleton x] - exact card_le_of_subset hx + exact card_le_card hx #align finset.card_le_one_iff_subset_singleton Finset.card_le_one_iff_subset_singleton lemma exists_mem_ne (hs : 1 < s.card) (a : α) : ∃ b ∈ s, b ≠ a := by @@ -779,4 +778,12 @@ theorem lt_wf {α} : WellFounded (@LT.lt (Finset α) _) := Subrelation.wf H <| InvImage.wf _ <| (Nat.lt_wfRel).2 #align finset.lt_wf Finset.lt_wf +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on 2023-12-27. +-/ + +@[deprecated] alias card_le_of_subset := card_le_card + end Finset diff --git a/Mathlib/Data/Finset/Grade.lean b/Mathlib/Data/Finset/Grade.lean index e9582a76958d0..4241c7e79f0dc 100644 --- a/Mathlib/Data/Finset/Grade.lean +++ b/Mathlib/Data/Finset/Grade.lean @@ -28,8 +28,8 @@ namespace Multiset variable {s t : Multiset α} {a : α} @[simp] lemma covby_cons (s : Multiset α) (a : α) : s ⋖ a ::ₘ s := - ⟨lt_cons_self _ _, fun t hst hts ↦ (covby_succ _).2 (card_lt_of_lt hst) $ by - simpa using card_lt_of_lt hts⟩ + ⟨lt_cons_self _ _, fun t hst hts ↦ (covby_succ _).2 (card_lt_card hst) $ by + simpa using card_lt_card hts⟩ lemma _root_.Covby.exists_multiset_cons (h : s ⋖ t) : ∃ a, a ::ₘ s = t := (lt_iff_cons_le.1 h.lt).imp fun _a ha ↦ ha.eq_of_not_lt $ h.2 $ lt_cons_self _ _ diff --git a/Mathlib/Data/Finset/Image.lean b/Mathlib/Data/Finset/Image.lean index 897a27f4cf21c..7dcd56092a49d 100644 --- a/Mathlib/Data/Finset/Image.lean +++ b/Mathlib/Data/Finset/Image.lean @@ -499,14 +499,14 @@ theorem coe_image_subset_range : ↑(s.image f) ⊆ Set.range f := _ ⊆ Set.range f := Set.image_subset_range f ↑s #align finset.coe_image_subset_range Finset.coe_image_subset_range -theorem image_filter {p : β → Prop} [DecidablePred p] : +theorem filter_image {p : β → Prop} [DecidablePred p] : (s.image f).filter p = (s.filter λ a ↦ p (f a)).image f := ext fun b => by simp only [mem_filter, mem_image, exists_prop] exact ⟨by rintro ⟨⟨x, h1, rfl⟩, h2⟩; exact ⟨x, ⟨h1, h2⟩, rfl⟩, by rintro ⟨x, ⟨h1, h2⟩, rfl⟩; exact ⟨⟨x, h1, rfl⟩, h2⟩⟩ -#align finset.image_filter Finset.image_filter +#align finset.image_filter Finset.filter_image theorem image_union [DecidableEq α] {f : α → β} (s₁ s₂ : Finset α) : (s₁ ∪ s₂).image f = s₁.image f ∪ s₂.image f := @@ -883,3 +883,15 @@ theorem finsetCongr_toEmbedding (e : α ≃ β) : #align equiv.finset_congr_to_embedding Equiv.finsetCongr_toEmbedding end Equiv + +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on 2023-12-27. +-/ + +namespace Finset + +@[deprecated] alias image_filter := filter_image + +end Finset diff --git a/Mathlib/Data/Finset/LocallyFinite.lean b/Mathlib/Data/Finset/LocallyFinite.lean index 9d9f6c0af93fe..d0bce673b2a08 100644 --- a/Mathlib/Data/Finset/LocallyFinite.lean +++ b/Mathlib/Data/Finset/LocallyFinite.lean @@ -1208,7 +1208,7 @@ lemma transGen_wcovby_of_le [Preorder α] [LocallyFiniteOrder α] {x y : α} (hx obtain ⟨z, z_mem, hz⟩ := (Ico x y).exists_maximal h_non have z_card : (Icc x z).card <(Icc x y).card := calc (Icc x z).card ≤ (Ico x y).card := - card_le_of_subset <| Icc_subset_Ico_right (mem_Ico.mp z_mem).2 + card_le_card <| Icc_subset_Ico_right (mem_Ico.mp z_mem).2 _ < (Icc x y).card := this have h₁ := transGen_wcovby_of_le (mem_Ico.mp z_mem).1 have h₂ : z ⩿ y := by diff --git a/Mathlib/Data/Finset/NAry.lean b/Mathlib/Data/Finset/NAry.lean index 8c6af01ae0c23..d631dcb51a2d0 100644 --- a/Mathlib/Data/Finset/NAry.lean +++ b/Mathlib/Data/Finset/NAry.lean @@ -255,14 +255,14 @@ theorem card_le_card_image₂_left {s : Finset α} (hs : s.Nonempty) (hf : ∀ a t.card ≤ (image₂ f s t).card := by obtain ⟨a, ha⟩ := hs rw [← card_image₂_singleton_left _ (hf a)] - exact card_le_of_subset (image₂_subset_right <| singleton_subset_iff.2 ha) + exact card_le_card (image₂_subset_right <| singleton_subset_iff.2 ha) #align finset.card_le_card_image₂_left Finset.card_le_card_image₂_left theorem card_le_card_image₂_right {t : Finset β} (ht : t.Nonempty) (hf : ∀ b, Injective fun a => f a b) : s.card ≤ (image₂ f s t).card := by obtain ⟨b, hb⟩ := ht rw [← card_image₂_singleton_right _ (hf b)] - exact card_le_of_subset (image₂_subset_left <| singleton_subset_iff.2 hb) + exact card_le_card (image₂_subset_left <| singleton_subset_iff.2 hb) #align finset.card_le_card_image₂_right Finset.card_le_card_image₂_right variable {s t} diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean index 5ab8d4832e8ab..c8d04c7b61c08 100644 --- a/Mathlib/Data/Finset/Powerset.lean +++ b/Mathlib/Data/Finset/Powerset.lean @@ -252,7 +252,7 @@ theorem powersetCard_succ_insert [DecidableEq α] {x : α} {s : Finset α} (h : powersetCard n.succ s ∪ (powersetCard n s).image (insert x) := by rw [powersetCard_eq_filter, powerset_insert, filter_union, ← powersetCard_eq_filter] congr - rw [powersetCard_eq_filter, image_filter] + rw [powersetCard_eq_filter, filter_image] congr 1 ext t simp only [mem_powerset, mem_filter, Function.comp_apply, and_congr_right_iff] @@ -299,7 +299,7 @@ theorem powerset_card_disjiUnion (s : Finset α) : refine' ext fun a => ⟨fun ha => _, fun ha => _⟩ · rw [mem_disjiUnion] exact - ⟨a.card, mem_range.mpr (Nat.lt_succ_of_le (card_le_of_subset (mem_powerset.mp ha))), + ⟨a.card, mem_range.mpr (Nat.lt_succ_of_le (card_le_card (mem_powerset.mp ha))), mem_powersetCard.mpr ⟨mem_powerset.mp ha, rfl⟩⟩ · rcases mem_disjiUnion.mp ha with ⟨i, _hi, ha⟩ exact mem_powerset.mpr (mem_powersetCard.mp ha).1 diff --git a/Mathlib/Data/Finset/Slice.lean b/Mathlib/Data/Finset/Slice.lean index 2effff586be37..d855614300ac7 100644 --- a/Mathlib/Data/Finset/Slice.lean +++ b/Mathlib/Data/Finset/Slice.lean @@ -116,7 +116,7 @@ alias ⟨_, _root_.Set.Sized.subset_powersetCard_univ⟩ := subset_powersetCard_ theorem _root_.Set.Sized.card_le (h𝒜 : (𝒜 : Set (Finset α)).Sized r) : card 𝒜 ≤ (Fintype.card α).choose r := by rw [Fintype.card, ← card_powersetCard] - exact card_le_of_subset (subset_powersetCard_univ_iff.mpr h𝒜) + exact card_le_card (subset_powersetCard_univ_iff.mpr h𝒜) #align set.sized.card_le Set.Sized.card_le end Sized diff --git a/Mathlib/Data/Finset/Sups.lean b/Mathlib/Data/Finset/Sups.lean index 585619caf3107..65234580b325c 100644 --- a/Mathlib/Data/Finset/Sups.lean +++ b/Mathlib/Data/Finset/Sups.lean @@ -500,7 +500,7 @@ theorem disjSups_subset_sups : s ○ t ⊆ s ⊻ t := by variable (s t) theorem card_disjSups_le : (s ○ t).card ≤ s.card * t.card := - (card_le_of_subset disjSups_subset_sups).trans <| card_sups_le _ _ + (card_le_card disjSups_subset_sups).trans <| card_sups_le _ _ #align finset.card_disj_sups_le Finset.card_disjSups_le variable {s s₁ s₂ t t₁ t₂} diff --git a/Mathlib/Data/Finsupp/Multiset.lean b/Mathlib/Data/Finsupp/Multiset.lean index f87a552a93157..a5d05ee98d4b2 100644 --- a/Mathlib/Data/Finsupp/Multiset.lean +++ b/Mathlib/Data/Finsupp/Multiset.lean @@ -230,7 +230,7 @@ theorem toMultiset_strictMono : StrictMono (@toMultiset ι) := theorem sum_id_lt_of_lt (m n : ι →₀ ℕ) (h : m < n) : (m.sum fun _ => id) < n.sum fun _ => id := by rw [← card_toMultiset, ← card_toMultiset] - apply Multiset.card_lt_of_lt + apply Multiset.card_lt_card exact toMultiset_strictMono h #align finsupp.sum_id_lt_of_lt Finsupp.sum_id_lt_of_lt diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index 6fbdb60869df1..7f1b2f374ef14 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -261,7 +261,7 @@ theorem Finset.card_eq_iff_eq_univ [Fintype α] (s : Finset α) : #align finset.card_eq_iff_eq_univ Finset.card_eq_iff_eq_univ theorem Finset.card_le_univ [Fintype α] (s : Finset α) : s.card ≤ Fintype.card α := - card_le_of_subset (subset_univ s) + card_le_card (subset_univ s) #align finset.card_le_univ Finset.card_le_univ theorem Finset.card_lt_univ_of_not_mem [Fintype α] {s : Finset α} {x : α} (hx : x ∉ s) : diff --git a/Mathlib/Data/Matroid/Basic.lean b/Mathlib/Data/Matroid/Basic.lean index c7054c29dc0eb..bf33d7e0425b8 100644 --- a/Mathlib/Data/Matroid/Basic.lean +++ b/Mathlib/Data/Matroid/Basic.lean @@ -660,7 +660,7 @@ instance finitary_of_finiteRk {M : Matroid α} [FiniteRk M] : Finitary M := obtain ⟨B, hB⟩ := M.exists_base obtain ⟨I₀, hI₀I, hI₀fin, hI₀card⟩ := h.exists_subset_ncard_eq (B.ncard + 1) obtain ⟨B', hB', hI₀B'⟩ := hI _ hI₀I hI₀fin - have hle := ncard_le_of_subset hI₀B' hB'.finite + have hle := ncard_le_ncard hI₀B' hB'.finite rw [hI₀card, hB'.ncard_eq_ncard_of_base hB, Nat.add_one_le_iff] at hle exact hle.ne rfl ⟩ diff --git a/Mathlib/Data/Matroid/IndepAxioms.lean b/Mathlib/Data/Matroid/IndepAxioms.lean index 8a4a71b9bb66b..798b1f380f3fd 100644 --- a/Mathlib/Data/Matroid/IndepAxioms.lean +++ b/Mathlib/Data/Matroid/IndepAxioms.lean @@ -290,7 +290,7 @@ theorem _root_.Matroid.existsMaximalSubsetProperty_of_bdd {P : Set α → Prop} refine' ⟨Y, hY, fun J ⟨hJ, hIJ, hJX⟩ (hYJ : Y ⊆ J) ↦ (_ : J ⊆ Y)⟩ have hJfin := finite_of_encard_le_coe (hP J hJ) refine' (eq_of_subset_of_ncard_le hYJ _ hJfin).symm.subset - rw [hY' J ⟨hJ, hIJ, hJX⟩ (ncard_le_of_subset hYJ hJfin)] + rw [hY' J ⟨hJ, hIJ, hJX⟩ (ncard_le_ncard hYJ hJfin)] /-- If there is an absolute upper bound on the size of an independent set, then the maximality axiom isn't needed to define a matroid by independent sets. -/ @@ -382,7 +382,7 @@ protected def ofFinite {E : Set α} (hE : E.Finite) (Indep : Set α → Prop) (hE.subset (subset_ground hI)).cast_ncard_eq] ) (indep_bdd := ⟨E.ncard, fun I hI ↦ by rw [hE.cast_ncard_eq] - exact encard_le_of_subset <| subset_ground hI ⟩) + exact encard_le_card <| subset_ground hI ⟩) (subset_ground := subset_ground) @[simp] theorem ofFinite_E {E : Set α} hE Indep indep_empty indep_subset indep_aug subset_ground : diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index 9219b6d8dd63e..08a0cb1fb359f 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -792,27 +792,27 @@ theorem card_eq_one {s : Multiset α} : card s = 1 ↔ ∃ a, s = {a} := fun ⟨_a, e⟩ => e.symm ▸ rfl⟩ #align multiset.card_eq_one Multiset.card_eq_one -theorem card_le_of_le {s t : Multiset α} (h : s ≤ t) : card s ≤ card t := +theorem card_le_card {s t : Multiset α} (h : s ≤ t) : card s ≤ card t := leInductionOn h Sublist.length_le -#align multiset.card_le_of_le Multiset.card_le_of_le +#align multiset.card_le_of_le Multiset.card_le_card @[mono] -theorem card_mono : Monotone (@card α) := fun _a _b => card_le_of_le +theorem card_mono : Monotone (@card α) := fun _a _b => card_le_card #align multiset.card_mono Multiset.card_mono theorem eq_of_le_of_card_le {s t : Multiset α} (h : s ≤ t) : card t ≤ card s → s = t := leInductionOn h fun s h₂ => congr_arg _ <| s.eq_of_length_le h₂ #align multiset.eq_of_le_of_card_le Multiset.eq_of_le_of_card_le -theorem card_lt_of_lt {s t : Multiset α} (h : s < t) : card s < card t := +theorem card_lt_card {s t : Multiset α} (h : s < t) : card s < card t := lt_of_not_ge fun h₂ => _root_.ne_of_lt h <| eq_of_le_of_card_le (le_of_lt h) h₂ -#align multiset.card_lt_of_lt Multiset.card_lt_of_lt +#align multiset.card_lt_card Multiset.card_lt_card -lemma card_strictMono : StrictMono (card : Multiset α → ℕ) := fun _ _ ↦ card_lt_of_lt +lemma card_strictMono : StrictMono (card : Multiset α → ℕ) := fun _ _ ↦ card_lt_card theorem lt_iff_cons_le {s t : Multiset α} : s < t ↔ ∃ a, a ::ₘ s ≤ t := ⟨Quotient.inductionOn₂ s t fun _l₁ _l₂ h => - Subperm.exists_of_length_lt (le_of_lt h) (card_lt_of_lt h), + Subperm.exists_of_length_lt (le_of_lt h) (card_lt_card h), fun ⟨_a, h⟩ => lt_of_lt_of_le (lt_cons_self _ _) h⟩ #align multiset.lt_iff_cons_le Multiset.lt_iff_cons_le @@ -851,7 +851,7 @@ def strongInductionOn {p : Multiset α → Sort*} (s : Multiset α) (ih : ∀ s, (ih s) fun t _h => strongInductionOn t ih termination_by _ => card s -decreasing_by exact card_lt_of_lt _h +decreasing_by exact card_lt_card _h #align multiset.strong_induction_on Multiset.strongInductionOnₓ -- Porting note: reorderd universes theorem strongInductionOn_eq {p : Multiset α → Sort*} (s : Multiset α) (H) : @@ -878,7 +878,7 @@ def strongDownwardInduction {p : Multiset α → Sort*} {n : ℕ} H s fun {t} ht _h => strongDownwardInduction H t ht termination_by _ => n - card s -decreasing_by exact (tsub_lt_tsub_iff_left_of_le ht).2 (card_lt_of_lt _h) +decreasing_by exact (tsub_lt_tsub_iff_left_of_le ht).2 (card_lt_card _h) -- Porting note: reorderd universes #align multiset.strong_downward_induction Multiset.strongDownwardInductionₓ @@ -909,7 +909,7 @@ theorem strongDownwardInductionOn_eq {p : Multiset α → Sort*} (s : Multiset /-- Another way of expressing `strongInductionOn`: the `(<)` relation is well-founded. -/ instance instWellFoundedLT : WellFoundedLT (Multiset α) := - ⟨Subrelation.wf Multiset.card_lt_of_lt (measure Multiset.card).2⟩ + ⟨Subrelation.wf Multiset.card_lt_card (measure Multiset.card).2⟩ #align multiset.is_well_founded_lt Multiset.instWellFoundedLT /-! ### `Multiset.replicate` -/ @@ -1152,11 +1152,11 @@ theorem card_erase_add_one {a : α} {s : Multiset α} : a ∈ s → card (s.eras #align multiset.card_erase_add_one Multiset.card_erase_add_one theorem card_erase_lt_of_mem {a : α} {s : Multiset α} : a ∈ s → card (s.erase a) < card s := - fun h => card_lt_of_lt (erase_lt.mpr h) + fun h => card_lt_card (erase_lt.mpr h) #align multiset.card_erase_lt_of_mem Multiset.card_erase_lt_of_mem theorem card_erase_le {a : α} {s : Multiset α} : card (s.erase a) ≤ card s := - card_le_of_le (erase_le a s) + card_le_card (erase_le a s) #align multiset.card_erase_le Multiset.card_erase_le theorem card_erase_eq_ite {a : α} {s : Multiset α} : @@ -1357,7 +1357,7 @@ theorem map_le_map {f : α → β} {s t : Multiset α} (h : s ≤ t) : map f s theorem map_lt_map {f : α → β} {s t : Multiset α} (h : s < t) : s.map f < t.map f := by refine' (map_le_map h.le).lt_of_not_le fun H => h.ne <| eq_of_le_of_card_le h.le _ rw [← s.card_map f, ← t.card_map f] - exact card_le_of_le H + exact card_le_card H #align multiset.map_lt_map Multiset.map_lt_map theorem map_mono (f : α → β) : Monotone (map f) := fun _ _ => map_le_map @@ -2159,7 +2159,7 @@ lemma card_filter_le_iff (s : Multiset α) (P : α → Prop) [DecidablePred P] ( fconstructor · intro H s' hs' s'_card by_contra! rid - have card := card_le_of_le (monotone_filter_left P hs') |>.trans H + have card := card_le_card (monotone_filter_left P hs') |>.trans H exact s'_card.not_le (filter_eq_self.mpr rid ▸ card) · contrapose! exact fun H ↦ ⟨s.filter P, filter_le _ _, H, fun a ha ↦ (mem_filter.mp ha).2⟩ @@ -2335,7 +2335,7 @@ theorem countP_sub [DecidableEq α] {s t : Multiset α} (h : t ≤ s) : #align multiset.countp_sub Multiset.countP_sub theorem countP_le_of_le {s t} (h : s ≤ t) : countP p s ≤ countP p t := by - simpa [countP_eq_card_filter] using card_le_of_le (filter_le_filter p h) + simpa [countP_eq_card_filter] using card_le_card (filter_le_filter p h) #align multiset.countp_le_of_le Multiset.countP_le_of_le @[simp] @@ -3186,4 +3186,13 @@ theorem coe_subsingletonEquiv [Subsingleton α] : rfl #align multiset.coe_subsingleton_equiv Multiset.coe_subsingletonEquiv +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on 2023-12-27. +-/ + +@[deprecated] alias card_le_of_le := card_le_card +@[deprecated] alias card_lt_of_lt := card_lt_card + end Multiset diff --git a/Mathlib/Data/MvPolynomial/Variables.lean b/Mathlib/Data/MvPolynomial/Variables.lean index f6d5e9fda4ea4..384db34fd52d0 100644 --- a/Mathlib/Data/MvPolynomial/Variables.lean +++ b/Mathlib/Data/MvPolynomial/Variables.lean @@ -606,7 +606,7 @@ theorem totalDegree_le_degrees_card (p : MvPolynomial σ R) : p.totalDegree ≤ Multiset.card p.degrees := by classical rw [totalDegree_eq] - exact Finset.sup_le fun s hs => Multiset.card_le_of_le <| Finset.le_sup hs + exact Finset.sup_le fun s hs => Multiset.card_le_card <| Finset.le_sup hs #align mv_polynomial.total_degree_le_degrees_card MvPolynomial.totalDegree_le_degrees_card theorem totalDegree_le_of_support_subset (h : p.support ⊆ q.support) : diff --git a/Mathlib/Data/Nat/Choose/Sum.lean b/Mathlib/Data/Nat/Choose/Sum.lean index 59bbde2807745..7b884dc00bfe1 100644 --- a/Mathlib/Data/Nat/Choose/Sum.lean +++ b/Mathlib/Data/Nat/Choose/Sum.lean @@ -157,7 +157,7 @@ theorem sum_powerset_apply_card {α β : Type*} [AddCommMonoid α] (f : ℕ → intro y hy rw [mem_range, Nat.lt_succ_iff] rw [mem_powerset] at hy - exact card_le_of_subset hy + exact card_le_card hy · refine' sum_congr rfl fun y _ ↦ _ rw [← card_powersetCard, ← sum_const] refine' sum_congr powersetCard_eq_filter.symm fun z hz ↦ _ diff --git a/Mathlib/Data/Nat/Count.lean b/Mathlib/Data/Nat/Count.lean index 5ae27b3fde4c8..702e92924249c 100644 --- a/Mathlib/Data/Nat/Count.lean +++ b/Mathlib/Data/Nat/Count.lean @@ -152,7 +152,7 @@ variable [DecidablePred q] theorem count_mono_left {n : ℕ} (hpq : ∀ k, p k → q k) : count p n ≤ count q n := by simp only [count_eq_card_filter_range] - exact card_le_of_subset ((range n).monotone_filter_right hpq) + exact card_le_card ((range n).monotone_filter_right hpq) #align nat.count_mono_left Nat.count_mono_left end Count diff --git a/Mathlib/Data/Polynomial/Degree/Definitions.lean b/Mathlib/Data/Polynomial/Degree/Definitions.lean index 06eadf6592a09..0c9b6bda9e3e2 100644 --- a/Mathlib/Data/Polynomial/Degree/Definitions.lean +++ b/Mathlib/Data/Polynomial/Degree/Definitions.lean @@ -486,12 +486,12 @@ theorem mem_support_C_mul_X_pow {n a : ℕ} {c : R} (h : a ∈ support (C c * X theorem card_support_C_mul_X_pow_le_one {c : R} {n : ℕ} : card (support (C c * X ^ n)) ≤ 1 := by rw [← card_singleton n] - apply card_le_of_subset (support_C_mul_X_pow' n c) + apply card_le_card (support_C_mul_X_pow' n c) #align polynomial.card_support_C_mul_X_pow_le_one Polynomial.card_support_C_mul_X_pow_le_one theorem card_supp_le_succ_natDegree (p : R[X]) : p.support.card ≤ p.natDegree + 1 := by rw [← Finset.card_range (p.natDegree + 1)] - exact Finset.card_le_of_subset supp_subset_range_natDegree_succ + exact Finset.card_le_card supp_subset_range_natDegree_succ #align polynomial.card_supp_le_succ_nat_degree Polynomial.card_supp_le_succ_natDegree theorem le_degree_of_mem_supp (a : ℕ) : a ∈ p.support → ↑a ≤ degree p := diff --git a/Mathlib/Data/Polynomial/Monomial.lean b/Mathlib/Data/Polynomial/Monomial.lean index dd9192c37aa12..1aba264263af8 100644 --- a/Mathlib/Data/Polynomial/Monomial.lean +++ b/Mathlib/Data/Polynomial/Monomial.lean @@ -53,7 +53,7 @@ theorem card_support_le_one_iff_monomial {f : R[X]} : simp [this, Ne.symm hi, coeff_monomial] · rintro ⟨n, a, rfl⟩ rw [← Finset.card_singleton n] - apply Finset.card_le_of_subset + apply Finset.card_le_card exact support_monomial' _ _ #align polynomial.card_support_le_one_iff_monomial Polynomial.card_support_le_one_iff_monomial diff --git a/Mathlib/Data/Polynomial/RingDivision.lean b/Mathlib/Data/Polynomial/RingDivision.lean index f6aec117ed4ed..813b64c838ffa 100644 --- a/Mathlib/Data/Polynomial/RingDivision.lean +++ b/Mathlib/Data/Polynomial/RingDivision.lean @@ -693,7 +693,7 @@ lemma mem_roots_iff_aeval_eq_zero (w : p ≠ 0) : x ∈ roots p ↔ aeval x p = theorem card_le_degree_of_subset_roots {p : R[X]} {Z : Finset R} (h : Z.val ⊆ p.roots) : Z.card ≤ p.natDegree := - (Multiset.card_le_of_le (Finset.val_le_iff_val_subset.2 h)).trans (Polynomial.card_roots' p) + (Multiset.card_le_card (Finset.val_le_iff_val_subset.2 h)).trans (Polynomial.card_roots' p) #align polynomial.card_le_degree_of_subset_roots Polynomial.card_le_degree_of_subset_roots theorem finite_setOf_isRoot {p : R[X]} (hp : p ≠ 0) : Set.Finite { x | IsRoot p x } := by @@ -1460,7 +1460,7 @@ theorem map_roots_le_of_injective [IsDomain A] [IsDomain B] (p : A[X]) {f : A theorem card_roots_le_map [IsDomain A] [IsDomain B] {p : A[X]} {f : A →+* B} (h : p.map f ≠ 0) : Multiset.card p.roots ≤ Multiset.card (p.map f).roots := by rw [← p.roots.card_map f] - exact Multiset.card_le_of_le (map_roots_le h) + exact Multiset.card_le_card (map_roots_le h) #align polynomial.card_roots_le_map Polynomial.card_roots_le_map theorem card_roots_le_map_of_injective [IsDomain A] [IsDomain B] {p : A[X]} {f : A →+* B} diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index dc3eb508ede59..cb503f4944cce 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -151,11 +151,11 @@ theorem encard_le_coe_iff {k : ℕ} : s.encard ≤ k ↔ s.Finite ∧ ∃ (n₀ section Lattice -theorem encard_le_of_subset (h : s ⊆ t) : s.encard ≤ t.encard := by +theorem encard_le_card (h : s ⊆ t) : s.encard ≤ t.encard := by rw [← union_diff_cancel h, encard_union_eq disjoint_sdiff_right]; exact le_self_add theorem encard_mono {α : Type*} : Monotone (encard : Set α → ℕ∞) := - fun _ _ ↦ encard_le_of_subset + fun _ _ ↦ encard_le_card theorem encard_diff_add_encard_of_subset (h : s ⊆ t) : (t \ s).encard + s.encard = t.encard := by rw [← encard_union_eq disjoint_sdiff_left, diff_union_self, union_eq_self_of_subset_right h] @@ -238,7 +238,7 @@ theorem encard_insert_le (s : Set α) (x : α) : (insert x s).encard ≤ s.encar rw [← union_singleton, ← encard_singleton x]; apply encard_union_le theorem encard_singleton_inter (s : Set α) (x : α) : ({x} ∩ s).encard ≤ 1 := by - rw [← encard_singleton x]; exact encard_le_of_subset (inter_subset_left _ _) + rw [← encard_singleton x]; exact encard_le_card (inter_subset_left _ _) theorem encard_diff_singleton_add_one (h : a ∈ s) : (s \ {a}).encard + 1 = s.encard := by @@ -395,7 +395,7 @@ theorem encard_image_le (f : α → β) (s : Set α) : (f '' s).encard ≤ s.enc obtain (h | h) := isEmpty_or_nonempty α · rw [s.eq_empty_of_isEmpty]; simp rw [← (f.invFunOn_injOn_image s).encard_image] - apply encard_le_of_subset + apply encard_le_card exact f.invFunOn_image_image_subset s theorem Finite.injOn_of_encard_image_eq (hs : s.Finite) (h : (f '' s).encard = s.encard) : @@ -412,7 +412,7 @@ theorem encard_preimage_of_injective_subset_range (hf : f.Injective) (ht : t ⊆ theorem encard_le_encard_of_injOn (hf : MapsTo f s t) (f_inj : InjOn f s) : s.encard ≤ t.encard := by - rw [← f_inj.encard_image]; apply encard_le_of_subset; rintro _ ⟨x, hx, rfl⟩; exact hf hx + rw [← f_inj.encard_image]; apply encard_le_card; rintro _ ⟨x, hx, rfl⟩; exact hf hx theorem Finite.exists_injOn_of_encard_le [Nonempty β] {s : Set α} {t : Set β} (hs : s.Finite) (hle : s.encard ≤ t.encard) : ∃ (f : α → β), s ⊆ f ⁻¹' t ∧ InjOn f s := by @@ -504,13 +504,13 @@ theorem Infinite.ncard (hs : s.Infinite) : s.ncard = 0 := by rw [← Nat.card_coe_set_eq, @Nat.card_eq_zero_of_infinite _ hs.to_subtype] #align set.infinite.ncard Set.Infinite.ncard -theorem ncard_le_of_subset (hst : s ⊆ t) (ht : t.Finite := by toFinite_tac) : +theorem ncard_le_ncard (hst : s ⊆ t) (ht : t.Finite := by toFinite_tac) : s.ncard ≤ t.ncard := by rw [← Nat.cast_le (α := ℕ∞), ht.cast_ncard_eq, (ht.subset hst).cast_ncard_eq] exact encard_mono hst -#align set.ncard_le_of_subset Set.ncard_le_of_subset +#align set.ncard_le_of_subset Set.ncard_le_ncard -theorem ncard_mono [Finite α] : @Monotone (Set α) _ _ _ ncard := fun _ _ ↦ ncard_le_of_subset +theorem ncard_mono [Finite α] : @Monotone (Set α) _ _ _ ncard := fun _ _ ↦ ncard_le_ncard #align set.ncard_mono Set.ncard_mono @[simp] theorem ncard_eq_zero (hs : s.Finite := by toFinite_tac) : @@ -617,7 +617,7 @@ theorem ncard_diff_singleton_lt_of_mem (h : a ∈ s) (hs : s.Finite := by toFini theorem ncard_diff_singleton_le (s : Set α) (a : α) : (s \ {a}).ncard ≤ s.ncard := by obtain hs | hs := s.finite_or_infinite - · apply ncard_le_of_subset (diff_subset _ _) hs + · apply ncard_le_ncard (diff_subset _ _) hs convert @zero_le ℕ _ _ exact (hs.diff (by simp : Set.Finite {a})).ncard #align set.ncard_diff_singleton_le Set.ncard_diff_singleton_le @@ -693,12 +693,12 @@ theorem fiber_ncard_ne_zero_iff_mem_image {y : β} (hs : s.Finite := by toFinite theorem ncard_inter_le_ncard_left (s t : Set α) (hs : s.Finite := by toFinite_tac) : (s ∩ t).ncard ≤ s.ncard := - ncard_le_of_subset (inter_subset_left _ _) hs + ncard_le_ncard (inter_subset_left _ _) hs #align set.ncard_inter_le_ncard_left Set.ncard_inter_le_ncard_left theorem ncard_inter_le_ncard_right (s t : Set α) (ht : t.Finite := by toFinite_tac) : (s ∩ t).ncard ≤ t.ncard := - ncard_le_of_subset (inter_subset_right _ _) ht + ncard_le_ncard (inter_subset_right _ _) ht #align set.ncard_inter_le_ncard_right Set.ncard_inter_le_ncard_right theorem eq_of_subset_of_ncard_le (h : s ⊆ t) (h' : t.ncard ≤ s.ncard) @@ -889,7 +889,7 @@ theorem ncard_diff_add_ncard (s t : Set α) (hs : s.Finite := by toFinite_tac) theorem diff_nonempty_of_ncard_lt_ncard (h : s.ncard < t.ncard) (hs : s.Finite := by toFinite_tac) : (t \ s).Nonempty := by rw [Set.nonempty_iff_ne_empty, Ne.def, diff_eq_empty] - exact fun h' ↦ h.not_le (ncard_le_of_subset h' hs) + exact fun h' ↦ h.not_le (ncard_le_ncard h' hs) #align set.diff_nonempty_of_ncard_lt_ncard Set.diff_nonempty_of_ncard_lt_ncard theorem exists_mem_not_mem_of_ncard_lt_ncard (h : s.ncard < t.ncard) @@ -1111,3 +1111,11 @@ theorem ncard_eq_three : s.ncard = 3 ↔ ∃ x y z, x ≠ y ∧ x ≠ z ∧ y #align set.ncard_eq_three Set.ncard_eq_three end ncard + +/-! +### Deprecated lemmas + +Those lemmas have been deprecated on 2023-12-27. +-/ + +@[deprecated] alias ncard_le_of_subset := ncard_le_ncard diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index 14fd58c7716c1..d12a6ae783770 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -1290,10 +1290,10 @@ theorem card_lt_card {s t : Set α} [Fintype s] [Fintype t] (h : s ⊂ t) : fun hst => (ssubset_iff_subset_ne.1 h).2 (eq_of_inclusion_surjective hst) #align set.card_lt_card Set.card_lt_card -theorem card_le_of_subset {s t : Set α} [Fintype s] [Fintype t] (hsub : s ⊆ t) : +theorem card_le_card {s t : Set α} [Fintype s] [Fintype t] (hsub : s ⊆ t) : Fintype.card s ≤ Fintype.card t := Fintype.card_le_of_injective (Set.inclusion hsub) (Set.inclusion_injective hsub) -#align set.card_le_of_subset Set.card_le_of_subset +#align set.card_le_card Set.card_le_card theorem eq_of_subset_of_card_le {s t : Set α} [Fintype s] [Fintype t] (hsub : s ⊆ t) (hcard : Fintype.card t ≤ Fintype.card s) : s = t := diff --git a/Mathlib/Data/Setoid/Partition.lean b/Mathlib/Data/Setoid/Partition.lean index 1aacd4decd9d5..f536fab4ab361 100644 --- a/Mathlib/Data/Setoid/Partition.lean +++ b/Mathlib/Data/Setoid/Partition.lean @@ -89,7 +89,7 @@ theorem finite_classes_ker {α β : Type*} [Finite β] (f : α → β) : (Setoid theorem card_classes_ker_le {α β : Type*} [Fintype β] (f : α → β) [Fintype (Setoid.ker f).classes] : Fintype.card (Setoid.ker f).classes ≤ Fintype.card β := by classical exact - le_trans (Set.card_le_of_subset (classes_ker_subset_fiber_set f)) (Fintype.card_range_le _) + le_trans (Set.card_le_card (classes_ker_subset_fiber_set f)) (Fintype.card_range_le _) #align setoid.card_classes_ker_le Setoid.card_classes_ker_le /-- Two equivalence relations are equal iff all their equivalence classes are equal. -/ diff --git a/Mathlib/FieldTheory/Adjoin.lean b/Mathlib/FieldTheory/Adjoin.lean index 893429365694b..b8beaf4641b94 100644 --- a/Mathlib/FieldTheory/Adjoin.lean +++ b/Mathlib/FieldTheory/Adjoin.lean @@ -749,7 +749,7 @@ theorem adjoin_finset_isCompactElement (S : Finset E) : IsCompactElement (adjoin F S : IntermediateField F E) := by rw [← biSup_adjoin_simple] simp_rw [Finset.mem_coe, ← Finset.sup_eq_iSup] - exact finset_sup_compact_of_compact S fun x _ => adjoin_simple_isCompactElement x + exact isCompactElement_finsetSup S fun x _ => adjoin_simple_isCompactElement x #align intermediate_field.adjoin_finset_is_compact_element IntermediateField.adjoin_finset_isCompactElement /-- Adjoining a finite subset is compact in the lattice of intermediate fields. -/ diff --git a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean index 996979b0824de..b63941b7ea2f7 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean @@ -284,7 +284,7 @@ theorem IsCyclic.card_pow_eq_one_le [DecidableEq α] [Fintype α] [IsCyclic α] calc (univ.filter fun a : α => a ^ n = 1).card ≤ (zpowers (g ^ (Fintype.card α / Nat.gcd n (Fintype.card α))) : Set α).toFinset.card := - card_le_of_subset fun x hx => + card_le_card fun x hx => let ⟨m, hm⟩ := show x ∈ Submonoid.powers g from mem_powers_iff_mem_zpowers.2 <| hg x Set.mem_toFinset.2 ⟨(m / (Fintype.card α / Nat.gcd n (Fintype.card α)) : ℕ), by diff --git a/Mathlib/LinearAlgebra/Lagrange.lean b/Mathlib/LinearAlgebra/Lagrange.lean index 7a3fffa6817cf..3435de5c2a299 100644 --- a/Mathlib/LinearAlgebra/Lagrange.lean +++ b/Mathlib/LinearAlgebra/Lagrange.lean @@ -448,7 +448,7 @@ theorem interpolate_eq_sum_interpolate_insert_sdiff (hvt : Set.InjOn v t) (hs : · simp_rw [Nat.cast_withBot, Finset.sup_lt_iff (WithBot.bot_lt_coe t.card), degree_mul] intro i hi have hs : 1 ≤ s.card := Nonempty.card_pos ⟨_, hi⟩ - have hst' : s.card ≤ t.card := card_le_of_subset hst + have hst' : s.card ≤ t.card := card_le_card hst have H : t.card = 1 + (t.card - s.card) + (s.card - 1) := by rw [add_assoc, tsub_add_tsub_cancel hst' hs, ← add_tsub_assoc_of_le (hs.trans hst'), Nat.succ_add_sub_one, zero_add] diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index e2818f02d8c9b..b10ca9e4c9e33 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -1516,7 +1516,7 @@ theorem exists_finite_card_le_of_finite_of_linearIndependent_of_span (ht : t.Fin have : s ⊆ (span K ↑ht.toFinset : Submodule K V) := by simp; assumption let ⟨u, _hust, hsu, Eq⟩ := exists_of_linearIndependent_of_finite_span hs this have : s.Finite := u.finite_toSet.subset hsu - ⟨this, by rw [← Eq]; exact Finset.card_le_of_subset <| Finset.coe_subset.mp <| by simp [hsu]⟩ + ⟨this, by rw [← Eq]; exact Finset.card_le_card <| Finset.coe_subset.mp <| by simp [hsu]⟩ #align exists_finite_card_le_of_finite_of_linear_independent_of_span exists_finite_card_le_of_finite_of_linearIndependent_of_span end Module diff --git a/Mathlib/LinearAlgebra/Multilinear/Basic.lean b/Mathlib/LinearAlgebra/Multilinear/Basic.lean index cc39a993ab2e5..6fb14148bba21 100644 --- a/Mathlib/LinearAlgebra/Multilinear/Basic.lean +++ b/Mathlib/LinearAlgebra/Multilinear/Basic.lean @@ -592,7 +592,7 @@ theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i, have Brec : (f fun i => ∑ j in B i, g i j) = ∑ r in piFinset B, f fun i => g i (r i) := by have : (∑ i, Finset.card (B i)) < ∑ i, Finset.card (A i) := by refine' - Finset.sum_lt_sum (fun i _ => Finset.card_le_of_subset (B_subset_A i)) + Finset.sum_lt_sum (fun i _ => Finset.card_le_card (B_subset_A i)) ⟨i₀, Finset.mem_univ _, _⟩ have : {j₂} ⊆ A i₀ := by simp [hj₂] simp only [Finset.card_sdiff this, Function.update_same, Finset.card_singleton] @@ -602,7 +602,7 @@ theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ i, -- Express the inductive assumption for `C` have Crec : (f fun i => ∑ j in C i, g i j) = ∑ r in piFinset C, f fun i => g i (r i) := by have : (∑ i, Finset.card (C i)) < ∑ i, Finset.card (A i) := - Finset.sum_lt_sum (fun i _ => Finset.card_le_of_subset (C_subset_A i)) + Finset.sum_lt_sum (fun i _ => Finset.card_le_card (C_subset_A i)) ⟨i₀, Finset.mem_univ _, by simp [hi₀]⟩ rw [h] at this exact IH _ this C rfl diff --git a/Mathlib/LinearAlgebra/Span.lean b/Mathlib/LinearAlgebra/Span.lean index 35003246b01aa..785b5937e9726 100644 --- a/Mathlib/LinearAlgebra/Span.lean +++ b/Mathlib/LinearAlgebra/Span.lean @@ -673,7 +673,7 @@ theorem finset_span_isCompactElement (S : Finset M) : simp only [Finset.mem_coe] rw [← Finset.sup_eq_iSup] exact - CompleteLattice.finset_sup_compact_of_compact S fun x _ => singleton_span_isCompactElement x + CompleteLattice.isCompactElement_finsetSup S fun x _ => singleton_span_isCompactElement x #align submodule.finset_span_is_compact_element Submodule.finset_span_isCompactElement /-- The span of a finite subset is compact in the lattice of submodules. -/ diff --git a/Mathlib/NumberTheory/Bertrand.lean b/Mathlib/NumberTheory/Bertrand.lean index 6423b972525a4..090713e349960 100644 --- a/Mathlib/NumberTheory/Bertrand.lean +++ b/Mathlib/NumberTheory/Bertrand.lean @@ -178,7 +178,7 @@ theorem centralBinom_le_of_no_bertrand_prime (n : ℕ) (n_big : 2 < n) · exact pow_factorization_choose_le (mul_pos two_pos n_pos) have : (Finset.Icc 1 (sqrt (2 * n))).card = sqrt (2 * n) := by rw [card_Icc, Nat.add_sub_cancel] rw [Finset.prod_const] - refine' pow_le_pow_right n2_pos ((Finset.card_le_of_subset fun x hx => _).trans this.le) + refine' pow_le_pow_right n2_pos ((Finset.card_le_card fun x hx => _).trans this.le) obtain ⟨h1, h2⟩ := Finset.mem_filter.1 hx exact Finset.mem_Icc.mpr ⟨(Finset.mem_filter.1 h1).2.one_lt.le, h2⟩ · refine' le_trans _ (primorial_le_4_pow (2 * n / 3)) diff --git a/Mathlib/NumberTheory/PrimeCounting.lean b/Mathlib/NumberTheory/PrimeCounting.lean index 9a170799f4726..3caa652f8a8c9 100644 --- a/Mathlib/NumberTheory/PrimeCounting.lean +++ b/Mathlib/NumberTheory/PrimeCounting.lean @@ -90,7 +90,7 @@ theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) : _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by rw [primeCounting', count_eq_card_filter_range] _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by - refine' add_le_add_left (card_le_of_subset _) k.primeCounting' + refine' add_le_add_left (card_le_card _) k.primeCounting' simp only [subset_iff, and_imp, mem_filter, mem_Ico] intro p succ_k_le_p p_lt_n p_prime constructor diff --git a/Mathlib/Order/CompactlyGenerated.lean b/Mathlib/Order/CompactlyGenerated.lean index 75cbde5ba46f1..8f353e1d84ec0 100644 --- a/Mathlib/Order/CompactlyGenerated.lean +++ b/Mathlib/Order/CompactlyGenerated.lean @@ -184,7 +184,7 @@ theorem IsCompactElement.directed_sSup_lt_of_lt {α : Type*} [CompleteLattice α exact hxk.ne (hxk.le.antisymm hkx) #align complete_lattice.is_compact_element.directed_Sup_lt_of_lt CompleteLattice.IsCompactElement.directed_sSup_lt_of_lt -theorem finset_sup_compact_of_compact {α β : Type*} [CompleteLattice α] {f : β → α} (s : Finset β) +theorem isCompactElement_finsetSup {α β : Type*} [CompleteLattice α] {f : β → α} (s : Finset β) (h : ∀ x ∈ s, IsCompactElement (f x)) : IsCompactElement (s.sup f) := by classical rw [isCompactElement_iff_le_of_directed_sSup_le] @@ -198,7 +198,7 @@ theorem finset_sup_compact_of_compact {α β : Type*} [CompleteLattice α] {f : rw [isCompactElement_iff_le_of_directed_sSup_le] at h specialize h d hemp hdir (le_trans (Finset.le_sup hps) hsup) simpa only [exists_prop] -#align complete_lattice.finset_sup_compact_of_compact CompleteLattice.finset_sup_compact_of_compact +#align complete_lattice.finset_sup_compact_of_compact CompleteLattice.isCompactElement_finsetSup theorem WellFounded.isSupFiniteCompact (h : WellFounded ((· > ·) : α → α → Prop)) : IsSupFiniteCompact α := fun s => by diff --git a/Mathlib/Order/Partition/Finpartition.lean b/Mathlib/Order/Partition/Finpartition.lean index c5a035ffe97dd..25c7531fdfad7 100644 --- a/Mathlib/Order/Partition/Finpartition.lean +++ b/Mathlib/Order/Partition/Finpartition.lean @@ -573,7 +573,7 @@ theorem atomise_empty (hs : s.Nonempty) : (atomise s ∅).parts = {s} := by #align finpartition.atomise_empty Finpartition.atomise_empty theorem card_atomise_le : (atomise s F).parts.card ≤ 2 ^ F.card := - (card_le_of_subset <| erase_subset _ _).trans <| Finset.card_image_le.trans (card_powerset _).le + (card_le_card <| erase_subset _ _).trans <| Finset.card_image_le.trans (card_powerset _).le #align finpartition.card_atomise_le Finpartition.card_atomise_le theorem biUnion_filter_atomise (ht : t ∈ F) (hts : t ⊆ s) : @@ -592,7 +592,7 @@ theorem card_filter_atomise_le_two_pow (ht : t ∈ F) : suffices h : ((atomise s F).parts.filter fun u ↦ u ⊆ t ∧ u.Nonempty) ⊆ (F.erase t).powerset.image fun P ↦ s.filter fun i ↦ ∀ x ∈ F, x ∈ insert t P ↔ i ∈ x - · refine' (card_le_of_subset h).trans (card_image_le.trans _) + · refine' (card_le_card h).trans (card_image_le.trans _) rw [card_powerset, card_erase_of_mem ht] rw [subset_iff] simp_rw [mem_image, mem_powerset, mem_filter, and_imp, Finset.Nonempty, exists_imp, mem_atomise, diff --git a/Mathlib/RingTheory/ChainOfDivisors.lean b/Mathlib/RingTheory/ChainOfDivisors.lean index 5651a0bff0e2c..5081cfa6e48d6 100644 --- a/Mathlib/RingTheory/ChainOfDivisors.lean +++ b/Mathlib/RingTheory/ChainOfDivisors.lean @@ -141,7 +141,7 @@ theorem card_subset_divisors_le_length_of_chain {q : Associates M} {n : ℕ} obtain ⟨i, hi⟩ := h₂.1 hr exact Finset.mem_image.2 ⟨i, Finset.mem_univ _, hi.symm⟩ rw [← Finset.card_fin (n + 1)] - exact (Finset.card_le_of_subset fun x hx => mem_image x <| hm x hx).trans Finset.card_image_le + exact (Finset.card_le_card fun x hx => mem_image x <| hm x hx).trans Finset.card_image_le #align divisor_chain.card_subset_divisors_le_length_of_chain DivisorChain.card_subset_divisors_le_length_of_chain variable [UniqueFactorizationMonoid M] @@ -194,7 +194,7 @@ theorem eq_pow_second_of_chain_of_has_chain {q : Associates M} {n : ℕ} (hn : n n + 1 = (Finset.univ : Finset (Fin (n + 1))).card := (Finset.card_fin _).symm _ = (Finset.univ.image c).card := (Finset.card_image_iff.mpr (h₁.injective.injOn _)).symm _ ≤ (Finset.univ.image fun m : Fin (i + 1) => c 1 ^ (m : ℕ)).card := - (Finset.card_le_of_subset ?_) + (Finset.card_le_card ?_) _ ≤ (Finset.univ : Finset (Fin (i + 1))).card := Finset.card_image_le _ = i + 1 := Finset.card_fin _ intro r hr diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index 1bb2b2f96eafc..afdd498853943 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -396,7 +396,7 @@ theorem fg_iff_compact (s : Submodule R M) : s.FG ↔ CompleteLattice.IsCompactE constructor · rintro ⟨t, rfl⟩ rw [span_eq_iSup_of_singleton_spans, ← supr_rw, ← Finset.sup_eq_iSup t sp] - apply CompleteLattice.finset_sup_compact_of_compact + apply CompleteLattice.isCompactElement_finsetSup exact fun n _ => singleton_span_isCompactElement n · intro h -- s is the Sup of the spans of its elements. diff --git a/Mathlib/RingTheory/RootsOfUnity/Basic.lean b/Mathlib/RingTheory/RootsOfUnity/Basic.lean index 8ec6708e83a0d..52fc80de2390f 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Basic.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Basic.lean @@ -243,7 +243,7 @@ theorem card_rootsOfUnity : Fintype.card (rootsOfUnity k R) ≤ k := calc Fintype.card (rootsOfUnity k R) = Fintype.card { x // x ∈ nthRoots k (1 : R) } := Fintype.card_congr (rootsOfUnityEquivNthRoots R k) - _ ≤ Multiset.card (nthRoots k (1 : R)).attach := (Multiset.card_le_of_le (Multiset.dedup_le _)) + _ ≤ Multiset.card (nthRoots k (1 : R)).attach := (Multiset.card_le_card (Multiset.dedup_le _)) _ = Multiset.card (nthRoots k (1 : R)) := Multiset.card_attach _ ≤ k := card_nthRoots k 1 #align card_roots_of_unity card_rootsOfUnity @@ -828,7 +828,7 @@ nonrec theorem card_nthRoots {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : · rw [not_lt] have hcard : Fintype.card { x // x ∈ nthRoots n (1 : R) } ≤ Multiset.card (nthRoots n (1 : R)).attach := - Multiset.card_le_of_le (Multiset.dedup_le _) + Multiset.card_le_card (Multiset.dedup_le _) rw [Multiset.card_attach] at hcard rw [← PNat.toPNat'_coe hpos] at hcard h ⊢ set m := Nat.toPNat' n @@ -846,7 +846,7 @@ theorem nthRoots_nodup {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : (nthRoots constructor · exact Multiset.dedup_le (nthRoots n (1 : R)) · by_contra ha - replace ha := Multiset.card_lt_of_lt ha + replace ha := Multiset.card_lt_card ha rw [card_nthRoots h] at ha have hrw : Multiset.card (nthRoots n (1 : R)).dedup = Fintype.card { x // x ∈ nthRoots n (1 : R) } := by diff --git a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean index b85cc3358a31f..72d5a359fbf3a 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean @@ -225,7 +225,7 @@ theorem totient_le_degree_minpoly : Nat.totient n ≤ (minpoly ℤ μ).natDegree -- minimal polynomial of `μ` sent to `K[X]` calc n.totient = (primitiveRoots n K).card := h.card_primitiveRoots.symm - _ ≤ P_K.roots.toFinset.card := (Finset.card_le_of_subset (is_roots_of_minpoly h)) + _ ≤ P_K.roots.toFinset.card := (Finset.card_le_card (is_roots_of_minpoly h)) _ ≤ Multiset.card P_K.roots := (Multiset.toFinset_card_le _) _ ≤ P_K.natDegree := (card_roots' _) _ ≤ P.natDegree := natDegree_map_le _ _ diff --git a/Mathlib/SetTheory/Cardinal/CountableCover.lean b/Mathlib/SetTheory/Cardinal/CountableCover.lean index 06e845fdc2e0c..0bab20e9467ec 100644 --- a/Mathlib/SetTheory/Cardinal/CountableCover.lean +++ b/Mathlib/SetTheory/Cardinal/CountableCover.lean @@ -44,7 +44,7 @@ lemma mk_subtype_le_of_countable_eventually_mem_aux {α ι : Type u} {a : Cardin let u : Finset α := (f i).toFinset have I1 : s.card ≤ u.card := by have : s ⊆ u := fun x hx ↦ by simpa only [Set.mem_toFinset] using hi x hx - exact Finset.card_le_of_subset this + exact Finset.card_le_card this have I2: (u.card : Cardinal) ≤ n := by convert h'f i; simp only [Set.toFinset_card, mk_fintype] exact I1.trans (Nat.cast_le.1 I2) From e0f4e43142a05eba5f40d216f967d3cf160be8e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 09:01:59 +0000 Subject: [PATCH 240/353] feat(Algebra/Homology): construction of the homotopy cofiber (#8969) --- Mathlib.lean | 1 + Mathlib/Algebra/Homology/Homotopy.lean | 10 + Mathlib/Algebra/Homology/HomotopyCofiber.lean | 232 ++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 Mathlib/Algebra/Homology/HomotopyCofiber.lean diff --git a/Mathlib.lean b/Mathlib.lean index 1215fa99bc489..0b0d34b987695 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -245,6 +245,7 @@ import Mathlib.Algebra.Homology.Homotopy import Mathlib.Algebra.Homology.HomotopyCategory import Mathlib.Algebra.Homology.HomotopyCategory.HomComplex import Mathlib.Algebra.Homology.HomotopyCategory.Shift +import Mathlib.Algebra.Homology.HomotopyCofiber import Mathlib.Algebra.Homology.ImageToKernel import Mathlib.Algebra.Homology.LocalCohomology import Mathlib.Algebra.Homology.Localization diff --git a/Mathlib/Algebra/Homology/Homotopy.lean b/Mathlib/Algebra/Homology/Homotopy.lean index 7d9e0e0f5f8fc..dfacef324e6ab 100644 --- a/Mathlib/Algebra/Homology/Homotopy.lean +++ b/Mathlib/Algebra/Homology/Homotopy.lean @@ -56,6 +56,11 @@ theorem dNext_eq (f : ∀ i j, C.X i ⟶ D.X j) {i i' : ι} (w : c.Rel i i') : rfl #align d_next_eq dNext_eq +lemma dNext_eq_zero (f : ∀ i j, C.X i ⟶ D.X j) (i : ι) (hi : ¬ c.Rel i (c.next i)) : + dNext i f = 0 := by + dsimp [dNext] + rw [shape _ _ _ hi, zero_comp] + @[simp 1100] theorem dNext_comp_left (f : C ⟶ D) (g : ∀ i j, D.X i ⟶ E.X j) (i : ι) : (dNext i fun i j => f.f i ≫ g i j) = f.f i ≫ dNext i g := @@ -74,6 +79,11 @@ def prevD (j : ι) : (∀ i j, C.X i ⟶ D.X j) →+ (C.X j ⟶ D.X j) := Preadditive.add_comp _ _ _ _ _ _ #align prev_d prevD +lemma prevD_eq_zero (f : ∀ i j, C.X i ⟶ D.X j) (i : ι) (hi : ¬ c.Rel (c.prev i) i) : + prevD i f = 0 := by + dsimp [prevD] + rw [shape _ _ _ hi, comp_zero] + /-- `f j (c.prev j)`. -/ def toPrev (j : ι) : (∀ i j, C.X i ⟶ D.X j) →+ (C.X j ⟶ D.xPrev j) := AddMonoidHom.mk' (fun f => f j (c.prev j)) fun _ _ => rfl diff --git a/Mathlib/Algebra/Homology/HomotopyCofiber.lean b/Mathlib/Algebra/Homology/HomotopyCofiber.lean new file mode 100644 index 0000000000000..3c4e3799651b4 --- /dev/null +++ b/Mathlib/Algebra/Homology/HomotopyCofiber.lean @@ -0,0 +1,232 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.Algebra.Homology.Homotopy + +/-! The homotopy cofiber of a morphism of homological complexes + +In this file, we construct the homotopy cofiber of a morphism `φ : F ⟶ G` +between homological complexes in `HomologicalComplex C c`. In degree `i`, +it is isomorphic to `(F.X j) ⊞ (G.X i)` if there is a `j` such that `c.Rel i j`, +and `G.X i` otherwise. (This is also known as the mapping cone of `φ`. Under +the name `CochainComplex.mappingCone`, a specific API shall be developed +for the case of cochain complexes indexed by `ℤ` (TODO).) + +When we assume `hc : ∀ j, ∃ i, c.Rel i j` (which holds in the case of chain complexes, +or cochain complexes indexed by `ℤ`), then for any homological complex `K`, +there is a bijection `HomologicalComplex.homotopyCofiber.descEquiv φ K hc` +between `homotopyCofiber φ ⟶ K` and the tuples `(α, hα)` with +`α : G ⟶ K` and `hα : Homotopy (φ ≫ α) 0` (TODO). + +We shall also study the cylinder of a homological complex `K`: this is the +homotopy cofiber of the morphism `biprod.lift (𝟙 K) (-𝟙 K) : K ⟶ K ⊞ K`. +Then, a morphism `K.cylinder ⟶ M` is determined by the data of two +morphisms `φ₀ φ₁ : K ⟶ M` and a homotopy `h : Homotopy φ₀ φ₁`, +see `cylinder.desc`. There is also a homotopy equivalence +`cylinder.homotopyEquiv K : HomotopyEquiv K.cylinder K`. From the construction of +the cylinder, we deduce the lemma `Homotopy.map_eq_of_inverts_homotopyEquivalences` +which assert that if a functor inverts homotopy equivalences, then the image of +two homotopic maps are equal (TODO). + +-/ + + +open CategoryTheory Category Limits Preadditive + +variable {C : Type*} [Category C] [Preadditive C] + +namespace HomologicalComplex + +variable {ι : Type*} {c : ComplexShape ι} {F G K : HomologicalComplex C c} (φ : F ⟶ G) + +/-- A morphism of homological complexes `φ : F ⟶ G` has a homotopy cofiber if for all +indices `i` and `j` such that `c.Rel i j`, the binary biproduct `F.X j ⊞ G.X i` exists. -/ +class HasHomotopyCofiber (φ : F ⟶ G) : Prop where + hasBinaryBiproduct (i j : ι) (hij : c.Rel i j) : HasBinaryBiproduct (F.X j) (G.X i) + +instance [HasBinaryBiproducts C] : HasHomotopyCofiber φ where + hasBinaryBiproduct _ _ _ := inferInstance + +variable [HasHomotopyCofiber φ] [DecidableRel c.Rel] + +namespace homotopyCofiber + +/-- The `X` field of the homological complex `homotopyCofiber φ`. -/ +noncomputable def X (i : ι) : C := + if hi : c.Rel i (c.next i) + then + haveI := HasHomotopyCofiber.hasBinaryBiproduct φ _ _ hi + (F.X (c.next i)) ⊞ (G.X i) + else G.X i + +/-- The canonical isomorphism `(homotopyCofiber φ).X i ≅ F.X j ⊞ G.X i` when `c.Rel i j`. -/ +noncomputable def XIsoBiprod (i j : ι) (hij : c.Rel i j) [HasBinaryBiproduct (F.X j) (G.X i)] : + X φ i ≅ F.X j ⊞ G.X i := + eqToIso (by + obtain rfl := c.next_eq' hij + apply dif_pos hij) + +/-- The canonical isomorphism `(homotopyCofiber φ).X i ≅ G.X i` when `¬ c.Rel i (c.next i)`. -/ +noncomputable def XIso (i : ι) (hi : ¬ c.Rel i (c.next i)) : + X φ i ≅ G.X i := + eqToIso (dif_neg hi) + +/-- The second projection `(homotopyCofiber φ).X i ⟶ G.X i`. -/ +noncomputable def sndX (i : ι) : X φ i ⟶ G.X i := + if hi : c.Rel i (c.next i) + then + haveI := HasHomotopyCofiber.hasBinaryBiproduct φ _ _ hi + (XIsoBiprod φ _ _ hi).hom ≫ biprod.snd + else + (XIso φ i hi).hom + +/-- The right inclusion `G.X i ⟶ (homotopyCofiber φ).X i`. -/ +noncomputable def inrX (i : ι) : G.X i ⟶ X φ i := + if hi : c.Rel i (c.next i) + then + haveI := HasHomotopyCofiber.hasBinaryBiproduct φ _ _ hi + biprod.inr ≫ (XIsoBiprod φ _ _ hi).inv + else + (XIso φ i hi).inv + +@[reassoc (attr := simp)] +lemma inrX_sndX (i : ι) : inrX φ i ≫ sndX φ i = 𝟙 _ := by + dsimp [sndX, inrX] + split_ifs with hi <;> simp + +@[reassoc] +lemma sndX_inrX (i : ι) (hi : ¬ c.Rel i (c.next i)) : + sndX φ i ≫ inrX φ i = 𝟙 _ := by + dsimp [sndX, inrX] + simp only [dif_neg hi, Iso.hom_inv_id] + +/-- The first projection `(homotopyCofiber φ).X i ⟶ F.X j` when `c.Rel i j`. -/ +noncomputable def fstX (i j : ι) (hij : c.Rel i j) : X φ i ⟶ F.X j := + haveI := HasHomotopyCofiber.hasBinaryBiproduct φ _ _ hij + (XIsoBiprod φ i j hij).hom ≫ biprod.fst + +/-- The left inclusion `F.X i ⟶ (homotopyCofiber φ).X j` when `c.Rel j i`. -/ +noncomputable def inlX (i j : ι) (hij : c.Rel j i) : F.X i ⟶ X φ j := + haveI := HasHomotopyCofiber.hasBinaryBiproduct φ _ _ hij + biprod.inl ≫ (XIsoBiprod φ j i hij).inv + +@[reassoc (attr := simp)] +lemma inlX_fstX (i j : ι ) (hij : c.Rel j i) : + inlX φ i j hij ≫ fstX φ j i hij = 𝟙 _ := by + simp [inlX, fstX] + +@[reassoc (attr := simp)] +lemma inlX_sndX (i j : ι) (hij : c.Rel j i) : + inlX φ i j hij ≫ sndX φ j = 0 := by + obtain rfl := c.next_eq' hij + simp [inlX, sndX, dif_pos hij] + +@[reassoc (attr := simp)] +lemma inrX_fstX (i j : ι) (hij : c.Rel i j) : + inrX φ i ≫ fstX φ i j hij = 0 := by + obtain rfl := c.next_eq' hij + simp [inrX, fstX, dif_pos hij] + +/-- The `d` field of the homological complex `homotopyCofiber φ`. -/ +noncomputable def d (i j : ι) : X φ i ⟶ X φ j := + if hij : c.Rel i j + then + (if hj : c.Rel j (c.next j) then -fstX φ i j hij ≫ F.d _ _ ≫ inlX φ _ _ hj else 0) + + fstX φ i j hij ≫ φ.f j ≫ inrX φ j + sndX φ i ≫ G.d i j ≫ inrX φ j + else + 0 + +lemma ext_to_X (i j : ι) (hij : c.Rel i j) {A : C} {f g : A ⟶ X φ i} + (h₁ : f ≫ fstX φ i j hij = g ≫ fstX φ i j hij) (h₂ : f ≫ sndX φ i = g ≫ sndX φ i) : + f = g := by + haveI := HasHomotopyCofiber.hasBinaryBiproduct φ _ _ hij + rw [← cancel_mono (XIsoBiprod φ i j hij).hom] + apply biprod.hom_ext + · simpa using h₁ + · obtain rfl := c.next_eq' hij + simpa [sndX, dif_pos hij] using h₂ + +lemma ext_to_X' (i : ι) (hi : ¬ c.Rel i (c.next i)) {A : C} {f g : A ⟶ X φ i} + (h : f ≫ sndX φ i = g ≫ sndX φ i) : f = g := by + rw [← cancel_mono (XIso φ i hi).hom] + simpa only [sndX, dif_neg hi] using h + +lemma ext_from_X (i j : ι) (hij : c.Rel j i) {A : C} {f g : X φ j ⟶ A} + (h₁ : inlX φ i j hij ≫ f = inlX φ i j hij ≫ g) (h₂ : inrX φ j ≫ f = inrX φ j ≫ g) : + f = g := by + haveI := HasHomotopyCofiber.hasBinaryBiproduct φ _ _ hij + rw [← cancel_epi (XIsoBiprod φ j i hij).inv] + apply biprod.hom_ext' + · simpa [inlX] using h₁ + · obtain rfl := c.next_eq' hij + simpa [inrX, dif_pos hij] using h₂ + +lemma ext_from_X' (i : ι) (hi : ¬ c.Rel i (c.next i)) {A : C} {f g : X φ i ⟶ A} + (h : inrX φ i ≫ f = inrX φ i ≫ g) : f = g := by + rw [← cancel_epi (XIso φ i hi).inv] + simpa only [inrX, dif_neg hi] using h + +@[reassoc] +lemma d_fstX (i j k : ι) (hij : c.Rel i j) (hjk : c.Rel j k) : + d φ i j ≫ fstX φ j k hjk = -fstX φ i j hij ≫ F.d j k := by + obtain rfl := c.next_eq' hjk + simp [d, dif_pos hij, dif_pos hjk] + +@[reassoc] +lemma d_sndX (i j : ι) (hij : c.Rel i j) : + d φ i j ≫ sndX φ j = fstX φ i j hij ≫ φ.f j + sndX φ i ≫ G.d i j := by + dsimp [d] + split_ifs with hij <;> simp + +@[reassoc] +lemma inlX_d (i j k : ι) (hij : c.Rel i j) (hjk : c.Rel j k) : + inlX φ j i hij ≫ d φ i j = -F.d j k ≫ inlX φ k j hjk + φ.f j ≫ inrX φ j := by + apply ext_to_X φ j k hjk + · dsimp + simp [d_fstX φ _ _ _ hij hjk] + · simp [d_sndX φ _ _ hij] + +@[reassoc] +lemma inlX_d' (i j : ι) (hij : c.Rel i j) (hj : ¬ c.Rel j (c.next j)): + inlX φ j i hij ≫ d φ i j = φ.f j ≫ inrX φ j := by + apply ext_to_X' _ _ hj + simp [d_sndX φ i j hij] + +lemma shape (i j : ι) (hij : ¬ c.Rel i j) : + d φ i j = 0 := + dif_neg hij + +@[reassoc (attr := simp)] +lemma inrX_d (i j : ι) : + inrX φ i ≫ d φ i j = G.d i j ≫ inrX φ j := by + by_cases hij : c.Rel i j + · by_cases hj : c.Rel j (c.next j) + · apply ext_to_X _ _ _ hj + · simp [d_fstX φ _ _ _ hij] + · simp [d_sndX φ _ _ hij] + · apply ext_to_X' _ _ hj + simp [d_sndX φ _ _ hij] + · rw [shape φ _ _ hij, G.shape _ _ hij, zero_comp, comp_zero] + +end homotopyCofiber + +/-- The homotopy cofiber of a morphism of homological complexes, +also known as the mapping cone. -/ +@[simps] +noncomputable def homotopyCofiber : HomologicalComplex C c where + X i := homotopyCofiber.X φ i + d i j := homotopyCofiber.d φ i j + shape i j hij := homotopyCofiber.shape φ i j hij + d_comp_d' i j k hij hjk := by + apply homotopyCofiber.ext_from_X φ j i hij + · dsimp + simp only [comp_zero, homotopyCofiber.inlX_d_assoc φ i j k hij hjk, + add_comp, assoc, homotopyCofiber.inrX_d, Hom.comm_assoc, neg_comp] + by_cases hk : c.Rel k (c.next k) + · simp [homotopyCofiber.inlX_d φ j k _ hjk hk] + · simp [homotopyCofiber.inlX_d' φ j k hjk hk] + · simp + +end HomologicalComplex From b58270e02160441b5701c9e942c5e56805c3d349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 09:02:00 +0000 Subject: [PATCH 241/353] feat(CategoryTheory/Shift): sequences of functors from a category with a shift (#9001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let `F : C ⥤ A` be a functor from a category `C` that is equipped with a shift by an additive monoid `M`. In this PR, we define a typeclass `F.ShiftSequence M` which includes the data of a sequence of functors `F.shift a : C ⥤ A` for all `a : A`. For each `a : A`, we have an isomorphism `F.isoShift a : shiftFunctor C a ⋙ F ≅ F.shift a` which satisfies some coherence relations. This will allow a better formulation of the long exact sequence attached to homological functors from a triangulated category to an abelian category. --- Mathlib.lean | 1 + .../CategoryTheory/Shift/ShiftSequence.lean | 198 ++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 Mathlib/CategoryTheory/Shift/ShiftSequence.lean diff --git a/Mathlib.lean b/Mathlib.lean index 0b0d34b987695..44b84f5d495c2 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1246,6 +1246,7 @@ import Mathlib.CategoryTheory.Shift.Localization import Mathlib.CategoryTheory.Shift.Opposite import Mathlib.CategoryTheory.Shift.Pullback import Mathlib.CategoryTheory.Shift.Quotient +import Mathlib.CategoryTheory.Shift.ShiftSequence import Mathlib.CategoryTheory.Sigma.Basic import Mathlib.CategoryTheory.Simple import Mathlib.CategoryTheory.SingleObj diff --git a/Mathlib/CategoryTheory/Shift/ShiftSequence.lean b/Mathlib/CategoryTheory/Shift/ShiftSequence.lean new file mode 100644 index 0000000000000..722ec91df0ef8 --- /dev/null +++ b/Mathlib/CategoryTheory/Shift/ShiftSequence.lean @@ -0,0 +1,198 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.CategoryTheory.Shift.CommShift + +/-! Sequences of functors from a category equipped with a shift + +Let `F : C ⥤ A` be a functor from a category `C` that is equipped with a +shift by an additive monoid `M`. In this file, we define a typeclass +`F.ShiftSequence M` which includes the data of a sequence of functors +`F.shift a : C ⥤ A` for all `a : A`. For each `a : A`, we have +an isomorphism `F.isoShift a : shiftFunctor C a ⋙ F ≅ F.shift a` which +satisfies some coherence relations. This allows to state results +(e.g. the long exact sequence of an homology functor (TODO)) using +functors `F.shift a` rather than `shiftFunctor C a ⋙ F`. The reason +for this design is that we can often choose functors `F.shift a` that +have better definitional properties than `shiftFunctor C a ⋙ F`. +For example, if `C` is the derived category (TODO) of an abelian +category `A` and `F` is the homology functor in degree `0`, then +for any `n : ℤ`, we may choose `F.shift n` to be the homology functor +in degree `n`. + +-/ + +open CategoryTheory Category ZeroObject Limits + +variable {C A : Type*} [Category C] [Category A] (F : C ⥤ A) + (M : Type*) [AddMonoid M] [HasShift C M] + +namespace CategoryTheory + +namespace Functor + +/-- A shift sequence for a functor `F : C ⥤ A` when `C` is equipped with a shift +by a monoid `M` involves a sequence of functor `sequence n : C ⥤ A` for all `n : M` +which behave like `shiftFunctor C n ⋙ F`. -/ +class ShiftSequence where + /-- a sequence of functors -/ + sequence : M → C ⥤ A + /-- `sequence 0` identifies to the given functor -/ + isoZero : sequence 0 ≅ F + /-- compatibility isomorphism with the shift -/ + shiftIso (n a a' : M) (ha' : n + a = a') : shiftFunctor C n ⋙ sequence a ≅ sequence a' + shiftIso_zero (a : M) : shiftIso 0 a a (zero_add a) = + isoWhiskerRight (shiftFunctorZero C M) _ ≪≫ leftUnitor _ + shiftIso_add : ∀ (n m a a' a'' : M) (ha' : n + a = a') (ha'' : m + a' = a''), + shiftIso (m + n) a a'' (by rw [add_assoc, ha', ha'']) = + isoWhiskerRight (shiftFunctorAdd C m n) _ ≪≫ Functor.associator _ _ _ ≪≫ + isoWhiskerLeft _ (shiftIso n a a' ha') ≪≫ shiftIso m a' a'' ha'' + +/-- The tautological shift sequence on a functor. -/ +noncomputable def ShiftSequence.tautological : ShiftSequence F M where + sequence n := shiftFunctor C n ⋙ F + isoZero := isoWhiskerRight (shiftFunctorZero C M) F ≪≫ F.rightUnitor + shiftIso n a a' ha' := (Functor.associator _ _ _).symm ≪≫ + isoWhiskerRight (shiftFunctorAdd' C n a a' ha').symm _ + shiftIso_zero a := by + dsimp + rw [shiftFunctorAdd'_zero_add] + aesop_cat + shiftIso_add n m a a' a'' ha' ha'' := by + ext X + dsimp + simp only [id_comp, ← Functor.map_comp] + congr + simpa only [← cancel_epi ((shiftFunctor C a).map ((shiftFunctorAdd C m n).hom.app X)), + shiftFunctorAdd'_eq_shiftFunctorAdd, ← Functor.map_comp_assoc, Iso.hom_inv_id_app, + Functor.map_id, id_comp] using shiftFunctorAdd'_assoc_inv_app m n a (m+n) a' a'' rfl ha' + (by rw [← ha'', ← ha', add_assoc]) X + +section + +variable {M} +variable [F.ShiftSequence M] + +/-- The shifted functors given by the shift sequence. -/ +def shift (n : M) : C ⥤ A := ShiftSequence.sequence F n + +/-- Compatibility isomorphism `shiftFunctor C n ⋙ F.shift a ≅ F.shift a'` when `n + a = a'`. -/ +def shiftIso (n a a' : M) (ha' : n + a = a') : + shiftFunctor C n ⋙ F.shift a ≅ F.shift a' := + ShiftSequence.shiftIso n a a' ha' + +@[reassoc (attr := simp 1100)] +lemma shiftIso_hom_naturality {X Y : C} (n a a' : M) (ha' : n + a = a') (f : X ⟶ Y) : + (shift F a).map (f⟦n⟧') ≫ (shiftIso F n a a' ha').hom.app Y = + (shiftIso F n a a' ha').hom.app X ≫ (shift F a').map f := + (F.shiftIso n a a' ha').hom.naturality f + +@[reassoc (attr := simp 1100)] +lemma shiftIso_inv_naturality {X Y : C} (n a a' : M) (ha' : n + a = a') (f : X ⟶ Y) : + (shift F a').map f ≫ (shiftIso F n a a' ha').inv.app Y = + (shiftIso F n a a' ha').inv.app X ≫ (shift F a).map (f⟦n⟧') := + (F.shiftIso n a a' ha').inv.naturality f + +variable (M) + +/-- The canonical isomorphism `F.shift 0 ≅ F`. -/ +def isoShiftZero : F.shift (0 : M) ≅ F := ShiftSequence.isoZero + +variable {M} + +/-- The canonical isomorphism `shiftFunctor C n ⋙ F ≅ F.shift n`. -/ +def isoShift (n : M) : shiftFunctor C n ⋙ F ≅ F.shift n := + isoWhiskerLeft _ (F.isoShiftZero M).symm ≪≫ F.shiftIso _ _ _ (add_zero n) + +@[reassoc] +lemma isoShift_hom_naturality (n : M) {X Y : C} (f : X ⟶ Y) : + F.map (f⟦n⟧') ≫ (F.isoShift n).hom.app Y = + (F.isoShift n).hom.app X ≫ (F.shift n).map f := + (F.isoShift n).hom.naturality f + +attribute [simp] isoShift_hom_naturality + +@[reassoc] +lemma isoShift_inv_naturality (n : M) {X Y : C} (f : X ⟶ Y) : + (F.shift n).map f ≫ (F.isoShift n).inv.app Y = + (F.isoShift n).inv.app X ≫ F.map (f⟦n⟧') := + (F.isoShift n).inv.naturality f + +lemma shiftIso_zero (a : M) : + F.shiftIso 0 a a (zero_add a) = + isoWhiskerRight (shiftFunctorZero C M) _ ≪≫ leftUnitor _ := + ShiftSequence.shiftIso_zero a + +@[simp] +lemma shiftIso_zero_hom_app (a : M) (X : C) : + (F.shiftIso 0 a a (zero_add a)).hom.app X = + (shift F a).map ((shiftFunctorZero C M).hom.app X) := by + simp [F.shiftIso_zero a] + +@[simp] +lemma shiftIso_zero_inv_app (a : M) (X : C) : + (F.shiftIso 0 a a (zero_add a)).inv.app X = + (shift F a).map ((shiftFunctorZero C M).inv.app X) := by + simp [F.shiftIso_zero a] + +lemma shiftIso_add (n m a a' a'' : M) (ha' : n + a = a') (ha'' : m + a' = a'') : + F.shiftIso (m + n) a a'' (by rw [add_assoc, ha', ha'']) = + isoWhiskerRight (shiftFunctorAdd C m n) _ ≪≫ Functor.associator _ _ _ ≪≫ + isoWhiskerLeft _ (F.shiftIso n a a' ha') ≪≫ F.shiftIso m a' a'' ha'' := + ShiftSequence.shiftIso_add _ _ _ _ _ _ _ + +lemma shiftIso_add_hom_app (n m a a' a'' : M) (ha' : n + a = a') (ha'' : m + a' = a'') (X : C) : + (F.shiftIso (m + n) a a'' (by rw [add_assoc, ha', ha''])).hom.app X = + (shift F a).map ((shiftFunctorAdd C m n).hom.app X) ≫ + (shiftIso F n a a' ha').hom.app ((shiftFunctor C m).obj X) ≫ + (shiftIso F m a' a'' ha'').hom.app X := by + simp [F.shiftIso_add n m a a' a'' ha' ha''] + +lemma shiftIso_add_inv_app (n m a a' a'' : M) (ha' : n + a = a') (ha'' : m + a' = a'') (X : C) : + (F.shiftIso (m + n) a a'' (by rw [add_assoc, ha', ha''])).inv.app X = + (shiftIso F m a' a'' ha'').inv.app X ≫ + (shiftIso F n a a' ha').inv.app ((shiftFunctor C m).obj X) ≫ + (shift F a).map ((shiftFunctorAdd C m n).inv.app X) := by + simp [F.shiftIso_add n m a a' a'' ha' ha''] + +lemma shiftIso_add' (n m mn : M) (hnm : m + n = mn) (a a' a'' : M) + (ha' : n + a = a') (ha'' : m + a' = a'') : + F.shiftIso mn a a'' (by rw [← hnm, ← ha'', ← ha', add_assoc]) = + isoWhiskerRight (shiftFunctorAdd' C m n _ hnm) _ ≪≫ Functor.associator _ _ _ ≪≫ + isoWhiskerLeft _ (F.shiftIso n a a' ha') ≪≫ F.shiftIso m a' a'' ha'' := by + subst hnm + rw [shiftFunctorAdd'_eq_shiftFunctorAdd, shiftIso_add] + +lemma shiftIso_add'_hom_app (n m mn : M) (hnm : m + n = mn) (a a' a'' : M) + (ha' : n + a = a') (ha'' : m + a' = a'') (X : C) : + (F.shiftIso mn a a'' (by rw [← hnm, ← ha'', ← ha', add_assoc])).hom.app X = + (shift F a).map ((shiftFunctorAdd' C m n mn hnm).hom.app X) ≫ + (shiftIso F n a a' ha').hom.app ((shiftFunctor C m).obj X) ≫ + (shiftIso F m a' a'' ha'').hom.app X := by + simp [F.shiftIso_add' n m mn hnm a a' a'' ha' ha''] + +lemma shiftIso_add'_inv_app (n m mn : M) (hnm : m + n = mn) (a a' a'' : M) + (ha' : n + a = a') (ha'' : m + a' = a'') (X : C) : + (F.shiftIso mn a a'' (by rw [← hnm, ← ha'', ← ha', add_assoc])).inv.app X = + (shiftIso F m a' a'' ha'').inv.app X ≫ + (shiftIso F n a a' ha').inv.app ((shiftFunctor C m).obj X) ≫ + (shift F a).map ((shiftFunctorAdd' C m n mn hnm).inv.app X) := by + simp [F.shiftIso_add' n m mn hnm a a' a'' ha' ha''] + +@[reassoc] +lemma shiftIso_hom_app_comp (n m mn : M) (hnm : m + n = mn) + (a a' a'' : M) (ha' : n + a = a') (ha'' : m + a' = a'') (X : C) : + (shiftIso F n a a' ha').hom.app ((shiftFunctor C m).obj X) ≫ + (shiftIso F m a' a'' ha'').hom.app X = + (shift F a).map ((shiftFunctorAdd' C m n mn hnm).inv.app X) ≫ + (F.shiftIso mn a a'' (by rw [← hnm, ← ha'', ← ha', add_assoc])).hom.app X := by + rw [F.shiftIso_add'_hom_app n m mn hnm a a' a'' ha' ha'', ← Functor.map_comp_assoc, + Iso.inv_hom_id_app, Functor.map_id, id_comp] + +end + +end Functor + +end CategoryTheory From dccbc022b76751d7b3770cdaeb767e5b78054142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Dupuis?= Date: Wed, 27 Dec 2023 09:02:01 +0000 Subject: [PATCH 242/353] feat: Completeness criterion for normed additive groups (#9117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a proof that a normed additive group is complete iff every absolutely convergent series converges in the space. This is Lemma 2.2.1 from the book "Interpolation Spaces" by Bergh and Löfström. I wasn't too sure where to put `Metric.exists_subseq_summable_dist_of_cauchySeq` -- I would be happy to move it somewhere else. Co-authored-by: Frédéric Dupuis <31101893+dupuisf@users.noreply.github.com> --- Mathlib.lean | 1 + .../Analysis/Normed/Group/Completeness.lean | 88 +++++++++++++++++++ Mathlib/Topology/MetricSpace/Cauchy.lean | 11 +++ docs/references.bib | 8 ++ 4 files changed, 108 insertions(+) create mode 100644 Mathlib/Analysis/Normed/Group/Completeness.lean diff --git a/Mathlib.lean b/Mathlib.lean index 44b84f5d495c2..f4ac51bf7b43a 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -773,6 +773,7 @@ import Mathlib.Analysis.Normed.Group.AddCircle import Mathlib.Analysis.Normed.Group.AddTorsor import Mathlib.Analysis.Normed.Group.BallSphere import Mathlib.Analysis.Normed.Group.Basic +import Mathlib.Analysis.Normed.Group.Completeness import Mathlib.Analysis.Normed.Group.Completion import Mathlib.Analysis.Normed.Group.ControlledClosure import Mathlib.Analysis.Normed.Group.Hom diff --git a/Mathlib/Analysis/Normed/Group/Completeness.lean b/Mathlib/Analysis/Normed/Group/Completeness.lean new file mode 100644 index 0000000000000..dcdd0e64096b6 --- /dev/null +++ b/Mathlib/Analysis/Normed/Group/Completeness.lean @@ -0,0 +1,88 @@ +/- +Copyright (c) 2023 Frédéric Dupuis. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Dupuis +-/ + +import Mathlib.Analysis.Normed.Group.Basic +import Mathlib.Analysis.SpecificLimits.Basic + +/-! +# Completeness of normed groups + +This file includes a completeness criterion for normed additive groups in terms of convergent +series. + +## Main results + +* `NormedAddCommGroup.completeSpace_of_summable_implies_tendsto`: A normed additive group is +complete if any absolutely convergent series converges in the space. + +## References + +* [bergh_lofstrom_1976] `completeSpace_of_summable_implies_tendsto` and + `summable_implies_tendsto_of_complete` correspond to the two directions of Lemma 2.2.1. + +## Tags + +CompleteSpace, CauchySeq +-/ + +open scoped BigOperators Topology +open Filter Finset + +section Metric + +variable {α : Type*} [PseudoMetricSpace α] + +lemma Metric.exists_subseq_summable_dist_of_cauchySeq (u : ℕ → α) (hu : CauchySeq u) : + ∃ f : ℕ → ℕ, StrictMono f ∧ Summable fun i => dist (u (f (i+1))) (u (f i)) := by + obtain ⟨f, hf₁, hf₂⟩ := + Metric.exists_subseq_bounded_of_cauchySeq u hu (fun n => (1 / (2:ℝ))^n) (fun n => by positivity) + refine ⟨f, hf₁, ?_⟩ + refine Summable.of_nonneg_of_le (fun n => by positivity) ?_ summable_geometric_two + exact fun n => le_of_lt <| hf₂ n (f (n+1)) <| hf₁.monotone (Nat.le_add_right n 1) + +end Metric + +section Normed + +variable {E : Type*} [NormedAddCommGroup E] + +/-- A normed additive group is complete if any absolutely convergent series converges in the +space. -/ +lemma NormedAddCommGroup.completeSpace_of_summable_imp_tendsto + (h : ∀ u : ℕ → E, + Summable (‖u ·‖) → ∃ a, Tendsto (fun n => ∑ i in range n, u i) atTop (𝓝 a)) : + CompleteSpace E := by + apply Metric.complete_of_cauchySeq_tendsto + intro u hu + obtain ⟨f, hf₁, hf₂⟩ := Metric.exists_subseq_summable_dist_of_cauchySeq u hu + simp only [dist_eq_norm] at hf₂ + let v n := u (f (n+1)) - u (f n) + have hv_sum : (fun n => (∑ i in range n, v i)) = fun n => u (f n) - u (f 0) := by + ext n + exact sum_range_sub (u ∘ f) n + obtain ⟨a, ha⟩ := h v hf₂ + refine ⟨a + u (f 0), ?_⟩ + refine tendsto_nhds_of_cauchySeq_of_subseq hu hf₁.tendsto_atTop ?_ + rw [hv_sum] at ha + have h₁ : Tendsto (fun n => u (f n) - u (f 0) + u (f 0)) atTop (𝓝 (a + u (f 0))) := by + refine Tendsto.add_const _ ha + simpa only [sub_add_cancel] using h₁ + +/-- In a complete normed additive group, every absolutely convergent series converges in the +space. -/ +lemma NormedAddCommGroup.summable_imp_tendsto_of_complete [CompleteSpace E] (u : ℕ → E) + (hu : Summable (‖u ·‖)) : ∃ a, Tendsto (fun n => ∑ i in range n, u i) atTop (𝓝 a) := by + refine cauchySeq_tendsto_of_complete <| cauchySeq_of_summable_dist ?_ + simp [dist_eq_norm, sum_range_succ, hu] + +/-- In a normed additive group, every absolutely convergent series converges in the +space iff the space is complete. -/ +lemma NormedAddCommGroup.summable_imp_tendsto_iff_completeSpace : + (∀ u : ℕ → E, Summable (‖u ·‖) → ∃ a, Tendsto (fun n => ∑ i in range n, u i) atTop (𝓝 a)) + ↔ CompleteSpace E := + ⟨completeSpace_of_summable_imp_tendsto, fun _ u hu => summable_imp_tendsto_of_complete u hu⟩ + +end Normed diff --git a/Mathlib/Topology/MetricSpace/Cauchy.lean b/Mathlib/Topology/MetricSpace/Cauchy.lean index 2a82221a27baf..d1eedad5cd402 100644 --- a/Mathlib/Topology/MetricSpace/Cauchy.lean +++ b/Mathlib/Topology/MetricSpace/Cauchy.lean @@ -156,4 +156,15 @@ theorem cauchySeq_iff_le_tendsto_0 {s : ℕ → α} : fun ⟨b, _, b_bound, b_lim⟩ => cauchySeq_of_le_tendsto_0 b b_bound b_lim⟩ #align cauchy_seq_iff_le_tendsto_0 cauchySeq_iff_le_tendsto_0 +lemma Metric.exists_subseq_bounded_of_cauchySeq (u : ℕ → α) (hu : CauchySeq u) (b : ℕ → ℝ) + (hb : ∀ n, 0 < b n) : + ∃ f : ℕ → ℕ, StrictMono f ∧ ∀ n, ∀ m ≥ f n, dist (u m) (u (f n)) < b n := by + rw [cauchySeq_iff] at hu + have hu' : ∀ k, ∀ᶠ (n : ℕ) in atTop, ∀ m ≥ n, dist (u m) (u n) < b k := by + intro k + rw [eventually_atTop] + obtain ⟨N, hN⟩ := hu (b k) (hb k) + exact ⟨N, fun m hm r hr => hN r (hm.trans hr) m hm⟩ + exact Filter.extraction_forall_of_eventually hu' + end CauchySeq diff --git a/docs/references.bib b/docs/references.bib index d4f649640f246..90b6a3d6c8171 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -193,6 +193,14 @@ @Book{ berger1987 edition = 1 } +@Book{ bergh_lofstrom_1976, + author = {Bergh, Jöran and Löfström, Jörgen}, + title = {Interpolation Spaces}, + publisher = {Springer Berlin}, + year = 1976, + issn = {0072-7830} +} + @Article{ bernstein1912, author = {Bernstein, S.}, year = {1912}, From bbf5f350c50ded89af97f73406104e296e4ebb66 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 27 Dec 2023 09:02:03 +0000 Subject: [PATCH 243/353] chore(Topology/FilterBasis): rename `GroupFilterBasis.prod_subset_self` (#9233) ... to `subset_mul_self` --- Mathlib/Topology/Algebra/FilterBasis.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Topology/Algebra/FilterBasis.lean b/Mathlib/Topology/Algebra/FilterBasis.lean index 8f42d54665f3f..bcff36e5d098a 100644 --- a/Mathlib/Topology/Algebra/FilterBasis.lean +++ b/Mathlib/Topology/Algebra/FilterBasis.lean @@ -140,10 +140,10 @@ instance : Inhabited (GroupFilterBasis G) := ⟨by simp⟩ @[to_additive] -theorem prod_subset_self (B : GroupFilterBasis G) {U : Set G} (h : U ∈ B) : U ⊆ U * U := +theorem subset_mul_self (B : GroupFilterBasis G) {U : Set G} (h : U ∈ B) : U ⊆ U * U := fun x x_in ↦ ⟨1, x, one h, x_in, one_mul x⟩ -#align group_filter_basis.prod_subset_self GroupFilterBasis.prod_subset_self -#align add_group_filter_basis.sum_subset_self AddGroupFilterBasis.sum_subset_self +#align group_filter_basis.prod_subset_self GroupFilterBasis.subset_mul_self +#align add_group_filter_basis.sum_subset_self AddGroupFilterBasis.subset_add_self /-- The neighborhood function of a `GroupFilterBasis`. -/ @[to_additive "The neighborhood function of an `AddGroupFilterBasis`."] @@ -190,7 +190,7 @@ theorem nhds_eq (B : GroupFilterBasis G) {x₀ : G} : @nhds G B.topology x₀ = use (fun y ↦ x * y) '' W, image_mem_map (FilterBasis.mem_filter_of_mem _ W_in) constructor · rw [image_subset_iff] at H ⊢ - exact ((B.prod_subset_self W_in).trans hW).trans H + exact ((B.subset_mul_self W_in).trans hW).trans H · rintro y ⟨t, tW, rfl⟩ rw [(B.hasBasis _).mem_iff] use W, W_in From 565cdcb266f80313b139c7939db0f289fb59ccea Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 27 Dec 2023 09:02:04 +0000 Subject: [PATCH 244/353] chore(ArithmeticFunction): add `cardFactors_zero` (#9287) * Add a `dsimp` lemma `cardFactors_zero` * Make `cardFactors_one` a `dsimp` lemma * make `cardFactors_eq_one_iff_prime` a `simp` lemma --- Mathlib/NumberTheory/ArithmeticFunction.lean | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Mathlib/NumberTheory/ArithmeticFunction.lean b/Mathlib/NumberTheory/ArithmeticFunction.lean index 06a39f065e3eb..e55fb1fa7b941 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction.lean @@ -896,10 +896,13 @@ theorem cardFactors_apply {n : ℕ} : Ω n = n.factors.length := rfl #align nat.arithmetic_function.card_factors_apply Nat.ArithmeticFunction.cardFactors_apply -@[simp] -theorem cardFactors_one : Ω 1 = 0 := by simp [cardFactors] +@[simp, nolint simpNF] -- this is a `dsimp` lemma +lemma cardFactors_zero : Ω 0 = 0 := rfl + +@[simp] theorem cardFactors_one : Ω 1 = 0 := rfl #align nat.arithmetic_function.card_factors_one Nat.ArithmeticFunction.cardFactors_one +@[simp] theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩ cases' n with n From 2380f2ad9bb517bced1d42b864ef378728bf42c5 Mon Sep 17 00:00:00 2001 From: Scott Carnahan <128885296+ScottCarnahan@users.noreply.github.com> Date: Wed, 27 Dec 2023 09:02:05 +0000 Subject: [PATCH 245/353] fix: change HahnSeries linearMap to use modules (#9297) This PR corrects what appears to be a minor oversight. We replace the scalar ring `R` with the module `V` in two spots. The proofs are unchanged. --- Mathlib/RingTheory/HahnSeries.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/RingTheory/HahnSeries.lean b/Mathlib/RingTheory/HahnSeries.lean index 4b7f1888ec2d3..a46cbdc5b51df 100644 --- a/Mathlib/RingTheory/HahnSeries.lean +++ b/Mathlib/RingTheory/HahnSeries.lean @@ -541,7 +541,7 @@ instance : Module R (HahnSeries Γ V) := /-- `single` as a linear map -/ @[simps] -def single.linearMap (a : Γ) : R →ₗ[R] HahnSeries Γ R := +def single.linearMap (a : Γ) : V →ₗ[R] HahnSeries Γ V := { single.addMonoidHom a with map_smul' := fun r s => by ext b @@ -550,7 +550,7 @@ def single.linearMap (a : Γ) : R →ₗ[R] HahnSeries Γ R := /-- `coeff g` as a linear map -/ @[simps] -def coeff.linearMap (g : Γ) : HahnSeries Γ R →ₗ[R] R := +def coeff.linearMap (g : Γ) : HahnSeries Γ V →ₗ[R] V := { coeff.addMonoidHom g with map_smul' := fun _ _ => rfl } #align hahn_series.coeff.linear_map HahnSeries.coeff.linearMap From e0ae51d25eacfec17c4fe4bfd5d5de3f359ee8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 27 Dec 2023 09:02:06 +0000 Subject: [PATCH 246/353] =?UTF-8?q?chore:=20Rename=20monotonicity=20of=20`?= =?UTF-8?q?=E2=80=A2`=20lemmas=20in=20modules=20(#9302)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the names of the lemmas moved in #9241 to match the naming convention. --- Mathlib/Algebra/Order/Module/Defs.lean | 79 ++++++++++++--------- Mathlib/Algebra/Order/Module/Pointwise.lean | 8 +-- Mathlib/Data/Real/Pointwise.lean | 4 +- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/Mathlib/Algebra/Order/Module/Defs.lean b/Mathlib/Algebra/Order/Module/Defs.lean index 0c711f3e82847..9ef6ffe4e513c 100644 --- a/Mathlib/Algebra/Order/Module/Defs.lean +++ b/Mathlib/Algebra/Order/Module/Defs.lean @@ -104,6 +104,8 @@ This file acts as a substitute for `Mathlib.Algebra.Order.SMul`. We now need to * rethink `OrderedSMul` -/ +open OrderDual + variable (α β : Type*) section Defs @@ -814,13 +816,13 @@ variable [OrderedAddCommGroup β] [Module α β] section PosSMulMono variable [PosSMulMono α β] -lemma smul_le_smul_of_nonpos (h : b₁ ≤ b₂) (ha : a ≤ 0) : a • b₂ ≤ a • b₁ := by +lemma smul_le_smul_of_nonpos_left (h : b₁ ≤ b₂) (ha : a ≤ 0) : a • b₂ ≤ a • b₁ := by rw [← neg_neg a, neg_smul, neg_smul (-a), neg_le_neg_iff] exact smul_le_smul_of_nonneg_left h (neg_nonneg_of_nonpos ha) -#align smul_le_smul_of_nonpos smul_le_smul_of_nonpos +#align smul_le_smul_of_nonpos smul_le_smul_of_nonpos_left -lemma antitone_smul_left (ha : a ≤ 0) : Antitone (SMul.smul a : β → β) := - fun _ _ h => smul_le_smul_of_nonpos h ha +lemma antitone_smul_left (ha : a ≤ 0) : Antitone ((a • ·) : β → β) := + fun _ _ h ↦ smul_le_smul_of_nonpos_left h ha #align antitone_smul_left antitone_smul_left instance PosSMulMono.toSMulPosMono : SMulPosMono α β where @@ -831,14 +833,14 @@ end PosSMulMono section PosSMulStrictMono variable [PosSMulStrictMono α β] -lemma smul_lt_smul_of_neg (hb : b₁ < b₂) (ha : a < 0) : a • b₂ < a • b₁ := by +lemma smul_lt_smul_of_neg_left (hb : b₁ < b₂) (ha : a < 0) : a • b₂ < a • b₁ := by rw [← neg_neg a, neg_smul, neg_smul (-a), neg_lt_neg_iff] exact smul_lt_smul_of_pos_left hb (neg_pos_of_neg ha) -#align smul_lt_smul_of_neg smul_lt_smul_of_neg +#align smul_lt_smul_of_neg smul_lt_smul_of_neg_left -lemma strict_anti_smul_left (ha : a < 0) : StrictAnti (SMul.smul a : β → β) := - fun _ _ h => smul_lt_smul_of_neg h ha -#align strict_anti_smul_left strict_anti_smul_left +lemma strictAnti_smul_left (ha : a < 0) : StrictAnti ((a • ·) : β → β) := + fun _ _ h ↦ smul_lt_smul_of_neg_left h ha +#align strict_anti_smul_left strictAnti_smul_left instance PosSMulStrictMono.toSMulPosStrictMono : SMulPosStrictMono α β where elim _b hb a₁ a₂ ha := by rw [← sub_pos, ← sub_smul]; exact smul_pos (sub_pos.2 ha) hb @@ -860,30 +862,30 @@ lemma smul_nonneg_of_nonpos_of_nonpos [SMulPosMono α β] (ha : a ≤ 0) (hb : b smul_nonpos_of_nonpos_of_nonneg (β := βᵒᵈ) ha hb #align smul_nonneg_of_nonpos_of_nonpos smul_nonneg_of_nonpos_of_nonpos -lemma smul_le_smul_iff_of_neg [PosSMulMono α β] [PosSMulReflectLE α β] (ha : a < 0) : +lemma smul_le_smul_iff_of_neg_left [PosSMulMono α β] [PosSMulReflectLE α β] (ha : a < 0) : a • b₁ ≤ a • b₂ ↔ b₂ ≤ b₁ := by rw [← neg_neg a, neg_smul, neg_smul (-a), neg_le_neg_iff] exact smul_le_smul_iff_of_pos_left (neg_pos_of_neg ha) -#align smul_le_smul_iff_of_neg smul_le_smul_iff_of_neg +#align smul_le_smul_iff_of_neg smul_le_smul_iff_of_neg_left section PosSMulStrictMono variable [PosSMulStrictMono α β] [PosSMulReflectLT α β] -lemma smul_lt_smul_iff_of_neg (ha : a < 0) : a • b₁ < a • b₂ ↔ b₂ < b₁ := by +lemma smul_lt_smul_iff_of_neg_left (ha : a < 0) : a • b₁ < a • b₂ ↔ b₂ < b₁ := by rw [← neg_neg a, neg_smul, neg_smul (-a), neg_lt_neg_iff] exact smul_lt_smul_iff_of_pos_left (neg_pos_of_neg ha) -#align smul_lt_smul_iff_of_neg smul_lt_smul_iff_of_neg +#align smul_lt_smul_iff_of_neg smul_lt_smul_iff_of_neg_left -lemma smul_pos_iff_of_neg (ha : a < 0) : 0 < a • b₁ ↔ b₁ < 0 := by - simpa only [smul_zero] using smul_lt_smul_iff_of_neg ha (b₁ := (0 : β)) -#align smul_pos_iff_of_neg smul_pos_iff_of_neg +lemma smul_pos_iff_of_neg_left (ha : a < 0) : 0 < a • b ↔ b < 0 := by + simpa only [smul_zero] using smul_lt_smul_iff_of_neg_left ha (b₁ := (0 : β)) +#align smul_pos_iff_of_neg smul_pos_iff_of_neg_left -alias ⟨_, smul_pos_of_neg_of_neg⟩ := smul_pos_iff_of_neg +alias ⟨_, smul_pos_of_neg_of_neg⟩ := smul_pos_iff_of_neg_left #align smul_pos_of_neg_of_neg smul_pos_of_neg_of_neg -lemma smul_neg_iff_of_neg (ha : a < 0) : a • b₁ < 0 ↔ 0 < b₁ := by - simpa only [smul_zero] using smul_lt_smul_iff_of_neg ha (b₂ := (0 : β)) -#align smul_neg_iff_of_neg smul_neg_iff_of_neg +lemma smul_neg_iff_of_neg_left (ha : a < 0) : a • b < 0 ↔ 0 < b := by + simpa only [smul_zero] using smul_lt_smul_iff_of_neg_left ha (b₂ := (0 : β)) +#align smul_neg_iff_of_neg smul_neg_iff_of_neg_left end PosSMulStrictMono @@ -996,35 +998,32 @@ section PosSMulMono variable [PosSMulMono α β] lemma inv_smul_le_iff_of_neg (h : a < 0) : a⁻¹ • b₁ ≤ b₂ ↔ a • b₂ ≤ b₁ := by - rw [← smul_le_smul_iff_of_neg h, smul_inv_smul₀ h.ne] + rw [← smul_le_smul_iff_of_neg_left h, smul_inv_smul₀ h.ne] #align inv_smul_le_iff_of_neg inv_smul_le_iff_of_neg lemma smul_inv_le_iff_of_neg (h : a < 0) : b₁ ≤ a⁻¹ • b₂ ↔ b₂ ≤ a • b₁ := by - rw [← smul_le_smul_iff_of_neg h, smul_inv_smul₀ h.ne] + rw [← smul_le_smul_iff_of_neg_left h, smul_inv_smul₀ h.ne] +#align smul_inv_le_iff_of_neg smul_inv_le_iff_of_neg variable (β) /-- Left scalar multiplication as an order isomorphism. -/ -@[simps] -def OrderIso.smulLeftDual (ha : a < 0) : β ≃o βᵒᵈ where - toFun b₂ := OrderDual.toDual (a • b₂) - invFun b₂ := a⁻¹ • OrderDual.ofDual b₂ - left_inv := inv_smul_smul₀ ha.ne - right_inv := smul_inv_smul₀ ha.ne - map_rel_iff' := (@OrderDual.toDual_le_toDual β).trans <| smul_le_smul_iff_of_neg ha -#align order_iso.smul_left_dual OrderIso.smulLeftDual -#align smul_inv_le_iff_of_neg smul_inv_le_iff_of_neg +@[simps!] +def OrderIso.smulRightDual (ha : a < 0) : β ≃o βᵒᵈ where + toEquiv := (Equiv.smulRight ha.ne).trans toDual + map_rel_iff' := (@OrderDual.toDual_le_toDual β).trans <| smul_le_smul_iff_of_neg_left ha +#align order_iso.smul_left_dual OrderIso.smulRightDual end PosSMulMono variable [PosSMulStrictMono α β] lemma inv_smul_lt_iff_of_neg (h : a < 0) : a⁻¹ • b₁ < b₂ ↔ a • b₂ < b₁ := by - rw [← smul_lt_smul_iff_of_neg h, smul_inv_smul₀ h.ne] + rw [← smul_lt_smul_iff_of_neg_left h, smul_inv_smul₀ h.ne] #align inv_smul_lt_iff_of_neg inv_smul_lt_iff_of_neg lemma smul_inv_lt_iff_of_neg (h : a < 0) : b₁ < a⁻¹ • b₂ ↔ b₂ < a • b₁ := by - rw [← smul_lt_smul_iff_of_neg h, smul_inv_smul₀ h.ne] + rw [← smul_lt_smul_iff_of_neg_left h, smul_inv_smul₀ h.ne] #align smul_inv_lt_iff_of_neg smul_inv_lt_iff_of_neg end Field @@ -1181,7 +1180,7 @@ end Mathlib.Meta.Positivity /-! ### Deprecated lemmas -Those lemmas have been deprecated on the 2023/12/23. +Those lemmas have been deprecated on 2023-12-23. -/ @[deprecated] alias monotone_smul_left := monotone_smul_left_of_nonneg @@ -1202,3 +1201,15 @@ Those lemmas have been deprecated on the 2023/12/23. @[deprecated] alias OrderIso.smulLeft_symm_apply := OrderIso.smulRight_symm_apply @[deprecated] alias OrderIso.smulLeft_apply := OrderIso.smulRight_apply @[deprecated] alias smul_neg_iff_of_pos := smul_neg_iff_of_pos_left + +/-! +Those lemmas have been deprecated on 2023-12-27. +-/ + +@[deprecated] alias strict_anti_smul_left := strictAnti_smul_left +@[deprecated] alias smul_le_smul_of_nonpos := smul_le_smul_of_nonpos_left +@[deprecated] alias smul_lt_smul_of_neg := smul_lt_smul_of_neg_left +@[deprecated] alias smul_pos_iff_of_neg := smul_pos_iff_of_neg_left +@[deprecated] alias smul_neg_iff_of_neg := smul_neg_iff_of_neg_left +@[deprecated] alias smul_le_smul_iff_of_neg := smul_le_smul_iff_of_neg_left +@[deprecated] alias smul_lt_smul_iff_of_neg := smul_lt_smul_iff_of_neg_left diff --git a/Mathlib/Algebra/Order/Module/Pointwise.lean b/Mathlib/Algebra/Order/Module/Pointwise.lean index c0d4e0b66d4eb..3ba22fc76ca54 100644 --- a/Mathlib/Algebra/Order/Module/Pointwise.lean +++ b/Mathlib/Algebra/Order/Module/Pointwise.lean @@ -91,19 +91,19 @@ variable [LinearOrderedField α] [OrderedAddCommGroup β] [Module α β] [PosSMu {a : α} @[simp] lemma lowerBounds_smul_of_neg (ha : a < 0) : lowerBounds (a • s) = a • upperBounds s := - (OrderIso.smulLeftDual β ha).upperBounds_image + (OrderIso.smulRightDual β ha).upperBounds_image #align lower_bounds_smul_of_neg lowerBounds_smul_of_neg @[simp] lemma upperBounds_smul_of_neg (ha : a < 0) : upperBounds (a • s) = a • lowerBounds s := - (OrderIso.smulLeftDual β ha).lowerBounds_image + (OrderIso.smulRightDual β ha).lowerBounds_image #align upper_bounds_smul_of_neg upperBounds_smul_of_neg @[simp] lemma bddBelow_smul_iff_of_neg (ha : a < 0) : BddBelow (a • s) ↔ BddAbove s := - (OrderIso.smulLeftDual β ha).bddAbove_image + (OrderIso.smulRightDual β ha).bddAbove_image #align bdd_below_smul_iff_of_neg bddBelow_smul_iff_of_neg @[simp] lemma bddAbove_smul_iff_of_neg (ha : a < 0) : BddAbove (a • s) ↔ BddBelow s := - (OrderIso.smulLeftDual β ha).bddBelow_image + (OrderIso.smulRightDual β ha).bddBelow_image #align bdd_above_smul_iff_of_neg bddAbove_smul_iff_of_neg end LinearOrderedField diff --git a/Mathlib/Data/Real/Pointwise.lean b/Mathlib/Data/Real/Pointwise.lean index c5dcdbb88058e..1dd16cd89328e 100644 --- a/Mathlib/Data/Real/Pointwise.lean +++ b/Mathlib/Data/Real/Pointwise.lean @@ -79,7 +79,7 @@ theorem Real.sInf_smul_of_nonpos (ha : a ≤ 0) (s : Set ℝ) : sInf (a • s) = · rw [zero_smul_set hs, zero_smul] exact csInf_singleton 0 by_cases h : BddAbove s - · exact ((OrderIso.smulLeftDual ℝ ha').map_csSup' hs h).symm + · exact ((OrderIso.smulRightDual ℝ ha').map_csSup' hs h).symm · rw [Real.sInf_of_not_bddBelow (mt (bddBelow_smul_iff_of_neg ha').1 h), Real.sSup_of_not_bddAbove h, smul_zero] #align real.Inf_smul_of_nonpos Real.sInf_smul_of_nonpos @@ -95,7 +95,7 @@ theorem Real.sSup_smul_of_nonpos (ha : a ≤ 0) (s : Set ℝ) : sSup (a • s) = · rw [zero_smul_set hs, zero_smul] exact csSup_singleton 0 by_cases h : BddBelow s - · exact ((OrderIso.smulLeftDual ℝ ha').map_csInf' hs h).symm + · exact ((OrderIso.smulRightDual ℝ ha').map_csInf' hs h).symm · rw [Real.sSup_of_not_bddAbove (mt (bddAbove_smul_iff_of_neg ha').1 h), Real.sInf_of_not_bddBelow h, smul_zero] #align real.Sup_smul_of_nonpos Real.sSup_smul_of_nonpos From d412c821c9dd98524268d9023f528f98aff7980a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 10:11:17 +0000 Subject: [PATCH 247/353] feat(Algebra/Homology): computation of the connecting homomorphism of the homology sequence (#8771) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a variant of a lemma introduced in #8512: `ShortComplex.SnakeInput.δ_apply'` computes the connecting homomorphism of the snake lemma in a concrete categoriy `C` with a phrasing based on the functor `forget₂ C Ab` rather than `forget C`. From this, the lemma `ShortComplex.ShortExact.δ_apply` is obtained in a new file `Algebra.Homology.ConcreteCategory`: it gives a computation in terms of (co)cycles of the connecting homomorphism in homology attached to a short exact sequence of homological complexes in `C`. This PR also adds a lemma which computes "up to refinements" the connecting homomorphism of the homology sequence in general abelian categories. --- Mathlib.lean | 1 + .../Algebra/Homology/ConcreteCategory.lean | 97 +++++++++++++++++++ .../Algebra/Homology/HomologySequence.lean | 26 +++++ Mathlib/Algebra/Homology/ShortComplex/Ab.lean | 7 ++ .../ShortComplex/ConcreteCategory.lean | 47 ++++++++- .../ShortComplex/PreservesHomology.lean | 5 + .../ConcreteCategory/Basic.lean | 9 ++ 7 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 Mathlib/Algebra/Homology/ConcreteCategory.lean diff --git a/Mathlib.lean b/Mathlib.lean index f4ac51bf7b43a..cbadc395b2594 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -231,6 +231,7 @@ import Mathlib.Algebra.HierarchyDesign import Mathlib.Algebra.Homology.Additive import Mathlib.Algebra.Homology.Augment import Mathlib.Algebra.Homology.ComplexShape +import Mathlib.Algebra.Homology.ConcreteCategory import Mathlib.Algebra.Homology.DifferentialObject import Mathlib.Algebra.Homology.Exact import Mathlib.Algebra.Homology.ExactSequence diff --git a/Mathlib/Algebra/Homology/ConcreteCategory.lean b/Mathlib/Algebra/Homology/ConcreteCategory.lean new file mode 100644 index 0000000000000..97b6277794839 --- /dev/null +++ b/Mathlib/Algebra/Homology/ConcreteCategory.lean @@ -0,0 +1,97 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.Algebra.Homology.HomologySequence +import Mathlib.Algebra.Homology.ShortComplex.ConcreteCategory + +/-! +# Homology of complexes in concrete categories + +The homology of short complexes in concrete categories was studied in +`Mathlib.Algebra.Homology.ShortComplex.ConcreteCategory`. In this file, +we introduce specific definitions and lemmas for the homology +of homological complexes in concrete categories. In particular, +we give a computation of the connecting homomorphism of +the homology sequence in terms of (co)cycles. + +-/ + +open CategoryTheory + +universe v u + +variable {C : Type u} [Category.{v} C] [ConcreteCategory.{v} C] [HasForget₂ C Ab.{v}] + [Abelian C] [(forget₂ C Ab).Additive] [(forget₂ C Ab).PreservesHomology] + {ι : Type*} {c : ComplexShape ι} + +namespace HomologicalComplex + +variable (K : HomologicalComplex C c) + +/-- Constructor for cycles of a homological complex in a concrete category. -/ +noncomputable def cyclesMk {i : ι} (x : (forget₂ C Ab).obj (K.X i)) (j : ι) (hj : c.next i = j) + (hx : ((forget₂ C Ab).map (K.d i j)) x = 0) : + (forget₂ C Ab).obj (K.cycles i) := + (K.sc i).cyclesMk x (by subst hj; exact hx) + +@[simp] +lemma i_cyclesMk {i : ι} (x : (forget₂ C Ab).obj (K.X i)) (j : ι) (hj : c.next i = j) + (hx : ((forget₂ C Ab).map (K.d i j)) x = 0) : + ((forget₂ C Ab).map (K.iCycles i)) (K.cyclesMk x j hj hx) = x := by + subst hj + apply (K.sc i).i_cyclesMk + +end HomologicalComplex + +namespace CategoryTheory + +namespace ShortComplex + +namespace ShortExact + +variable {S : ShortComplex (HomologicalComplex C c)} + (hS : S.ShortExact) (i j : ι) (hij : c.Rel i j) + +lemma δ_apply' (x₃ : (forget₂ C Ab).obj (S.X₃.homology i)) + (x₂ : (forget₂ C Ab).obj (S.X₂.opcycles i)) + (x₁ : (forget₂ C Ab).obj (S.X₁.cycles j)) + (h₂ : (forget₂ C Ab).map (HomologicalComplex.opcyclesMap S.g i) x₂ = + (forget₂ C Ab).map (S.X₃.homologyι i) x₃) + (h₁ : (forget₂ C Ab).map (HomologicalComplex.cyclesMap S.f j) x₁ = + (forget₂ C Ab).map (S.X₂.opcyclesToCycles i j) x₂) : + (forget₂ C Ab).map (hS.δ i j hij) x₃ = (forget₂ C Ab).map (S.X₁.homologyπ j) x₁ := + (HomologicalComplex.HomologySequence.snakeInput hS i j hij).δ_apply' x₃ x₂ x₁ h₂ h₁ + +lemma δ_apply (x₃ : (forget₂ C Ab).obj (S.X₃.X i)) + (hx₃ : (forget₂ C Ab).map (S.X₃.d i j) x₃ = 0) + (x₂ : (forget₂ C Ab).obj (S.X₂.X i)) (hx₂ : (forget₂ C Ab).map (S.g.f i) x₂ = x₃) + (x₁ : (forget₂ C Ab).obj (S.X₁.X j)) + (hx₁ : (forget₂ C Ab).map (S.f.f j) x₁ = (forget₂ C Ab).map (S.X₂.d i j) x₂) + (k : ι) (hk : c.next j = k) : + (forget₂ C Ab).map (hS.δ i j hij) + ((forget₂ C Ab).map (S.X₃.homologyπ i) (S.X₃.cyclesMk x₃ j (c.next_eq' hij) hx₃)) = + (forget₂ C Ab).map (S.X₁.homologyπ j) (S.X₁.cyclesMk x₁ k hk (by + have := hS.mono_f + apply (Preadditive.mono_iff_injective (S.f.f k)).1 inferInstance + erw [← forget₂_comp_apply, ← HomologicalComplex.Hom.comm, forget₂_comp_apply, hx₁, + ← forget₂_comp_apply, HomologicalComplex.d_comp_d, Functor.map_zero, map_zero, + AddMonoidHom.zero_apply])) := by + refine hS.δ_apply' i j hij _ ((forget₂ C Ab).map (S.X₂.pOpcycles i) x₂) _ ?_ ?_ + · erw [← forget₂_comp_apply, ← forget₂_comp_apply, + HomologicalComplex.p_opcyclesMap, Functor.map_comp, comp_apply, + HomologicalComplex.homology_π_ι, forget₂_comp_apply, hx₂, HomologicalComplex.i_cyclesMk] + · apply (Preadditive.mono_iff_injective (S.X₂.iCycles j)).1 inferInstance + conv_lhs => + erw [← forget₂_comp_apply, HomologicalComplex.cyclesMap_i, forget₂_comp_apply, + HomologicalComplex.i_cyclesMk, hx₁] + conv_rhs => + erw [← forget₂_comp_apply, ← forget₂_comp_apply, + HomologicalComplex.pOpcycles_opcyclesToCycles_assoc, HomologicalComplex.toCycles_i] + +end ShortExact + +end ShortComplex + +end CategoryTheory diff --git a/Mathlib/Algebra/Homology/HomologySequence.lean b/Mathlib/Algebra/Homology/HomologySequence.lean index f6d4c08571308..1c673d44139b5 100644 --- a/Mathlib/Algebra/Homology/HomologySequence.lean +++ b/Mathlib/Algebra/Homology/HomologySequence.lean @@ -302,6 +302,32 @@ lemma homology_exact₂ : (ShortComplex.mk (HomologicalComplex.homologyMap S.f i lemma homology_exact₃ : (ShortComplex.mk _ _ (comp_δ hS i j hij)).Exact := (snakeInput hS i j hij).L₁'_exact +lemma δ_eq' {A : C} (x₃ : A ⟶ S.X₃.homology i) (x₂ : A ⟶ S.X₂.opcycles i) + (x₁ : A ⟶ S.X₁.cycles j) + (h₂ : x₂ ≫ HomologicalComplex.opcyclesMap S.g i = x₃ ≫ S.X₃.homologyι i) + (h₁ : x₁ ≫ HomologicalComplex.cyclesMap S.f j = x₂ ≫ S.X₂.opcyclesToCycles i j) : + x₃ ≫ hS.δ i j hij = x₁ ≫ S.X₁.homologyπ j := + (snakeInput hS i j hij).δ_eq x₃ x₂ x₁ h₂ h₁ + +lemma δ_eq {A : C} (x₃ : A ⟶ S.X₃.X i) (hx₃ : x₃ ≫ S.X₃.d i j = 0) + (x₂ : A ⟶ S.X₂.X i) (hx₂ : x₂ ≫ S.g.f i = x₃) + (x₁ : A ⟶ S.X₁.X j) (hx₁ : x₁ ≫ S.f.f j = x₂ ≫ S.X₂.d i j) + (k : ι) (hk : c.next j = k) : + S.X₃.liftCycles x₃ j (c.next_eq' hij) hx₃ ≫ S.X₃.homologyπ i ≫ hS.δ i j hij = + S.X₁.liftCycles x₁ k hk (by + have := hS.mono_f + rw [← cancel_mono (S.f.f k), assoc, ← S.f.comm, reassoc_of% hx₁, + d_comp_d, comp_zero, zero_comp]) ≫ S.X₁.homologyπ j := by + simpa only [assoc] using hS.δ_eq' i j hij (S.X₃.liftCycles x₃ j + (c.next_eq' hij) hx₃ ≫ S.X₃.homologyπ i) + (x₂ ≫ S.X₂.pOpcycles i) (S.X₁.liftCycles x₁ k hk _) + (by simp only [assoc, HomologicalComplex.p_opcyclesMap, + HomologicalComplex.homology_π_ι, + HomologicalComplex.liftCycles_i_assoc, reassoc_of% hx₂]) + (by rw [← cancel_mono (S.X₂.iCycles j), HomologicalComplex.liftCycles_comp_cyclesMap, + HomologicalComplex.liftCycles_i, assoc, assoc, opcyclesToCycles_iCycles, + HomologicalComplex.p_fromOpcycles, hx₁]) + end ShortExact end ShortComplex diff --git a/Mathlib/Algebra/Homology/ShortComplex/Ab.lean b/Mathlib/Algebra/Homology/ShortComplex/Ab.lean index 103da7c452f39..3d00fedbdac13 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/Ab.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/Ab.lean @@ -71,6 +71,13 @@ the abstract `S.cycles` of the homology API and the more concrete description as noncomputable def abCyclesIso : S.cycles ≅ AddCommGroupCat.of (AddMonoidHom.ker S.g) := S.abLeftHomologyData.cyclesIso +@[simp] +lemma abCyclesIso_inv_apply_iCycles (x : AddMonoidHom.ker S.g) : + S.iCycles (S.abCyclesIso.inv x) = x := by + dsimp only [abCyclesIso] + erw [← comp_apply, S.abLeftHomologyData.cyclesIso_inv_comp_iCycles] + rfl + /-- Given a short complex `S` of abelian groups, this is the isomorphism between the abstract `S.homology` of the homology API and the more explicit quotient of `AddMonoidHom.ker S.g` by the image of diff --git a/Mathlib/Algebra/Homology/ShortComplex/ConcreteCategory.lean b/Mathlib/Algebra/Homology/ShortComplex/ConcreteCategory.lean index a360bb51913b3..1d9489809dc7c 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/ConcreteCategory.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/ConcreteCategory.lean @@ -55,7 +55,7 @@ lemma Preadditive.mono_iff_injective' {X Y : C} (f : X ⟶ Y) : have e : forget₂ C Ab ⋙ forget Ab ≅ forget C := eqToIso (HasForget₂.forget_comp) exact Arrow.isoOfNatIso e (Arrow.mk f) -lemma Preadditive.epi_iff_injective {X Y : C} (f : X ⟶ Y) : +lemma Preadditive.epi_iff_surjective {X Y : C} (f : X ⟶ Y) : Epi f ↔ Function.Surjective ((forget₂ C Ab).map f) := by rw [← AddCommGroupCat.epi_iff_surjective] constructor @@ -65,7 +65,7 @@ lemma Preadditive.epi_iff_injective {X Y : C} (f : X ⟶ Y) : lemma Preadditive.epi_iff_surjective' {X Y : C} (f : X ⟶ Y) : Epi f ↔ Function.Surjective ((forget C).map f) := by - simp only [epi_iff_injective, ← CategoryTheory.epi_iff_surjective] + simp only [epi_iff_surjective, ← CategoryTheory.epi_iff_surjective] apply (MorphismProperty.RespectsIso.epimorphisms (Type w)).arrow_mk_iso_iff have e : forget₂ C Ab ⋙ forget Ab ≅ forget C := eqToIso (HasForget₂.forget_comp) exact Arrow.isoOfNatIso e (Arrow.mk f) @@ -91,9 +91,25 @@ lemma ShortExact.injective_f (hS : S.ShortExact) : lemma ShortExact.surjective_g (hS : S.ShortExact) : Function.Surjective ((forget₂ C Ab).map S.g) := by - rw [← Preadditive.epi_iff_injective] + rw [← Preadditive.epi_iff_surjective] exact hS.epi_g +variable (S) + +/-- Constructor for cycles of short complexes in a concrete category. -/ +noncomputable def cyclesMk [S.HasHomology] (x₂ : (forget₂ C Ab).obj S.X₂) + (hx₂ : ((forget₂ C Ab).map S.g) x₂ = 0) : + (forget₂ C Ab).obj S.cycles := + (S.mapCyclesIso (forget₂ C Ab)).hom ((ShortComplex.abCyclesIso _).inv ⟨x₂, hx₂⟩) + +@[simp] +lemma i_cyclesMk [S.HasHomology] (x₂ : (forget₂ C Ab).obj S.X₂) + (hx₂ : ((forget₂ C Ab).map S.g) x₂ = 0) : + (forget₂ C Ab).map S.iCycles (S.cyclesMk x₂ hx₂) = x₂ := by + dsimp [cyclesMk] + erw [← comp_apply, S.mapCyclesIso_hom_iCycles (forget₂ C Ab), + ← comp_apply, abCyclesIso_inv_apply_iCycles ] + end ShortComplex end preadditive @@ -136,6 +152,31 @@ lemma δ_apply (x₃ : D.L₀.X₃) (x₂ : D.L₁.X₂) (x₁ : D.L₂.X₁) rw [Functor.map_comp, types_comp_apply, eq₁] exact h₁.symm +/-- This lemma allows the computation of the connecting homomorphism +`D.δ` when `D : SnakeInput C` and `C` is a concrete category. -/ +lemma δ_apply' (x₃ : (forget₂ C Ab).obj D.L₀.X₃) + (x₂ : (forget₂ C Ab).obj D.L₁.X₂) (x₁ : (forget₂ C Ab).obj D.L₂.X₁) + (h₂ : (forget₂ C Ab).map D.L₁.g x₂ = (forget₂ C Ab).map D.v₀₁.τ₃ x₃) + (h₁ : (forget₂ C Ab).map D.L₂.f x₁ = (forget₂ C Ab).map D.v₁₂.τ₂ x₂) : + (forget₂ C Ab).map D.δ x₃ = (forget₂ C Ab).map D.v₂₃.τ₁ x₁ := by + have e : forget₂ C Ab ⋙ forget Ab ≅ forget C := eqToIso (HasForget₂.forget_comp) + apply (mono_iff_injective (e.hom.app _)).1 inferInstance + refine (congr_hom (e.hom.naturality D.δ) x₃).trans + ((D.δ_apply (e.hom.app _ x₃) (e.hom.app _ x₂) (e.hom.app _ x₁) ?_ ?_ ).trans + (congr_hom (e.hom.naturality D.v₂₃.τ₁).symm x₁)) + · refine ((congr_hom (e.hom.naturality D.L₁.g) x₂).symm.trans ?_).trans + (congr_hom (e.hom.naturality D.v₀₁.τ₃) x₃) + dsimp + rw [comp_apply, comp_apply] + erw [h₂] + rfl + · refine ((congr_hom (e.hom.naturality D.L₂.f) x₁).symm.trans ?_).trans + (congr_hom (e.hom.naturality D.v₁₂.τ₂) x₂) + dsimp + rw [comp_apply, comp_apply] + erw [h₁] + rfl + end SnakeInput end ShortComplex diff --git a/Mathlib/Algebra/Homology/ShortComplex/PreservesHomology.lean b/Mathlib/Algebra/Homology/ShortComplex/PreservesHomology.lean index d01c63f06c307..7d8b6fa9fbfb8 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/PreservesHomology.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/PreservesHomology.lean @@ -400,6 +400,11 @@ noncomputable def mapCyclesIso [S.HasLeftHomology] [F.PreservesLeftHomologyOf S] (S.map F).cycles ≅ F.obj S.cycles := (S.leftHomologyData.map F).cyclesIso +@[reassoc (attr := simp)] +lemma mapCyclesIso_hom_iCycles [S.HasLeftHomology] [F.PreservesLeftHomologyOf S] : + (S.mapCyclesIso F).hom ≫ F.map S.iCycles = (S.map F).iCycles := by + apply LeftHomologyData.cyclesIso_hom_comp_i + /-- When a functor `F` preserves the left homology of a short complex `S`, this is the canonical isomorphism `(S.map F).leftHomology ≅ F.obj S.leftHomology`. -/ noncomputable def mapLeftHomologyIso [S.HasLeftHomology] [F.PreservesLeftHomologyOf S] : diff --git a/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean b/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean index a3d280b47126b..19883fe435036 100644 --- a/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean +++ b/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean @@ -212,6 +212,15 @@ def forget₂ (C : Type u) (D : Type u') [Category.{v} C] [ConcreteCategory.{w} HasForget₂.forget₂ #align category_theory.forget₂ CategoryTheory.forget₂ +attribute [local instance] ConcreteCategory.funLike ConcreteCategory.hasCoeToSort + +lemma forget₂_comp_apply {C : Type u} {D : Type u'} [Category.{v} C] [ConcreteCategory.{w} C] + [Category.{v'} D] [ConcreteCategory.{w} D] [HasForget₂ C D] {X Y Z : C} + (f : X ⟶ Y) (g : Y ⟶ Z) (x : (forget₂ C D).obj X) : + ((forget₂ C D).map (f ≫ g) x) = + (forget₂ C D).map g ((forget₂ C D).map f x) := by + rw [Functor.map_comp, comp_apply] + instance forget₂_faithful (C : Type u) (D : Type u') [Category.{v} C] [ConcreteCategory.{w} C] [Category.{v'} D] [ConcreteCategory.{w} D] [HasForget₂ C D] : Faithful (forget₂ C D) := HasForget₂.forget_comp.faithful_of_comp From 134652679f560cbe6796265bda77ba8c641e9956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 27 Dec 2023 10:11:18 +0000 Subject: [PATCH 248/353] feat: When `a \ b = b \ a` (#9109) and other simple order lemmas From LeanAPAP and LeanCamCombi --- Mathlib/Order/BooleanAlgebra.lean | 13 ++++++++++ .../ConditionallyCompleteLattice/Basic.lean | 14 +++++----- .../ConditionallyCompleteLattice/Finset.lean | 26 ++++++++++++------- Mathlib/Order/Disjoint.lean | 8 ++++++ Mathlib/Order/Heyting/Basic.lean | 6 +++++ 5 files changed, 50 insertions(+), 17 deletions(-) diff --git a/Mathlib/Order/BooleanAlgebra.lean b/Mathlib/Order/BooleanAlgebra.lean index a2cbcd158a2ac..38649d81ed097 100644 --- a/Mathlib/Order/BooleanAlgebra.lean +++ b/Mathlib/Order/BooleanAlgebra.lean @@ -326,6 +326,11 @@ theorem le_sdiff_iff : x ≤ y \ x ↔ x = ⊥ := ⟨fun h => disjoint_self.1 (disjoint_sdiff_self_right.mono_right h), fun h => h.le.trans bot_le⟩ #align le_sdiff_iff le_sdiff_iff +@[simp] lemma sdiff_eq_right : x \ y = y ↔ x = ⊥ ∧ y = ⊥ := by + rw [disjoint_sdiff_self_left.eq_iff]; aesop + +lemma sdiff_ne_right : x \ y ≠ y ↔ x ≠ ⊥ ∨ y ≠ ⊥ := sdiff_eq_right.not.trans not_and_or + theorem sdiff_lt_sdiff_right (h : x < y) (hz : z ≤ x) : x \ z < y \ z := (sdiff_le_sdiff_right h.le).lt_of_not_le fun h' => h.not_le <| le_sdiff_sup.trans <| sup_le_of_le_sdiff_right h' hz @@ -771,6 +776,14 @@ theorem himp_le : x ⇨ y ≤ z ↔ y ≤ z ∧ Codisjoint x z := (@le_sdiff αᵒᵈ _ _ _ _).trans <| and_congr_right' $ @Codisjoint_comm _ (_) _ _ _ #align himp_le himp_le +@[simp] lemma himp_le_iff : x ⇨ y ≤ x ↔ x = ⊤ := + ⟨fun h ↦ codisjoint_self.1 $ codisjoint_himp_self_right.mono_right h, fun h ↦ le_top.trans h.ge⟩ + +@[simp] lemma himp_eq_left : x ⇨ y = x ↔ x = ⊤ ∧ y = ⊤ := by + rw [codisjoint_himp_self_left.eq_iff]; aesop + +lemma himp_ne_right : x ⇨ y ≠ x ↔ x ≠ ⊤ ∨ y ≠ ⊤ := himp_eq_left.not.trans not_and_or + end BooleanAlgebra instance Prop.booleanAlgebra : BooleanAlgebra Prop := diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean index 1b0284e324f88..179a4fbe5ceb3 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean @@ -1177,7 +1177,7 @@ In this case we have `Sup ∅ = ⊥`, so we can drop some `Nonempty`/`Set.Nonemp section ConditionallyCompleteLinearOrderBot -variable [ConditionallyCompleteLinearOrderBot α] +variable [ConditionallyCompleteLinearOrderBot α] {s : Set α} {f : ι → α} {a : α} @[simp] theorem csSup_empty : (sSup ∅ : α) = ⊥ := @@ -1223,21 +1223,21 @@ theorem le_ciSup_iff' {s : ι → α} {a : α} (h : BddAbove (range s)) : theorem le_csInf_iff'' {s : Set α} {a : α} (ne : s.Nonempty) : a ≤ sInf s ↔ ∀ b : α, b ∈ s → a ≤ b := - le_csInf_iff ⟨⊥, fun _ _ => bot_le⟩ ne + le_csInf_iff (OrderBot.bddBelow _) ne #align le_cInf_iff'' le_csInf_iff'' theorem le_ciInf_iff' [Nonempty ι] {f : ι → α} {a : α} : a ≤ iInf f ↔ ∀ i, a ≤ f i := - le_ciInf_iff ⟨⊥, fun _ _ => bot_le⟩ + le_ciInf_iff (OrderBot.bddBelow _) #align le_cinfi_iff' le_ciInf_iff' -theorem csInf_le' {s : Set α} {a : α} (h : a ∈ s) : sInf s ≤ a := - csInf_le ⟨⊥, fun _ _ => bot_le⟩ h +theorem csInf_le' (h : a ∈ s) : sInf s ≤ a := csInf_le (OrderBot.bddBelow _) h #align cInf_le' csInf_le' -theorem ciInf_le' (f : ι → α) (i : ι) : iInf f ≤ f i := - ciInf_le ⟨⊥, fun _ _ => bot_le⟩ _ +theorem ciInf_le' (f : ι → α) (i : ι) : iInf f ≤ f i := ciInf_le (OrderBot.bddBelow _) _ #align cinfi_le' ciInf_le' +lemma ciInf_le_of_le' (c : ι) : f c ≤ a → iInf f ≤ a := ciInf_le_of_le (OrderBot.bddBelow _) _ + theorem exists_lt_of_lt_csSup' {s : Set α} {a : α} (h : a < sSup s) : ∃ b ∈ s, a < b := by contrapose! h exact csSup_le' h diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index 9483de6dddd39..fca70fc653840 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -84,9 +84,9 @@ non-empty. As a result, we can translate between the two. namespace Finset +variable {ι : Type*} [ConditionallyCompleteLattice α] -theorem sup'_eq_csSup_image [ConditionallyCompleteLattice β] (s : Finset α) (H) (f : α → β) : - s.sup' H f = sSup (f '' s) := by +theorem sup'_eq_csSup_image (s : Finset ι) (H) (f : ι → α) : s.sup' H f = sSup (f '' s) := by apply le_antisymm · refine' Finset.sup'_le _ _ fun a ha => _ refine' le_csSup ⟨s.sup' H f, _⟩ ⟨a, ha, rfl⟩ @@ -97,18 +97,24 @@ theorem sup'_eq_csSup_image [ConditionallyCompleteLattice β] (s : Finset α) (H exact Finset.le_sup' _ ha #align finset.sup'_eq_cSup_image Finset.sup'_eq_csSup_image -theorem inf'_eq_csInf_image [ConditionallyCompleteLattice β] (s : Finset α) (H) (f : α → β) : - s.inf' H f = sInf (f '' s) := - @sup'_eq_csSup_image _ βᵒᵈ _ _ H _ +theorem inf'_eq_csInf_image (s : Finset ι) (hs) (f : ι → α) : s.inf' hs f = sInf (f '' s) := + sup'_eq_csSup_image (α := αᵒᵈ) _ hs _ #align finset.inf'_eq_cInf_image Finset.inf'_eq_csInf_image -theorem sup'_id_eq_csSup [ConditionallyCompleteLattice α] (s : Finset α) (H) : - s.sup' H id = sSup s := by rw [sup'_eq_csSup_image s H, Set.image_id] +theorem sup'_id_eq_csSup (s : Finset α) (hs) : s.sup' hs id = sSup s := by + rw [sup'_eq_csSup_image s hs, Set.image_id] #align finset.sup'_id_eq_cSup Finset.sup'_id_eq_csSup -theorem inf'_id_eq_csInf [ConditionallyCompleteLattice α] (s : Finset α) (H) : - s.inf' H id = sInf s := - @sup'_id_eq_csSup αᵒᵈ _ _ H +theorem inf'_id_eq_csInf (s : Finset α) (hs) : s.inf' hs id = sInf s := + sup'_id_eq_csSup (α := αᵒᵈ) _ hs #align finset.inf'_id_eq_cInf Finset.inf'_id_eq_csInf +variable [Fintype ι] [Nonempty ι] + +lemma sup'_univ_eq_ciSup (f : ι → α) : univ.sup' univ_nonempty f = ⨆ i, f i := by + simp [sup'_eq_csSup_image, iSup] + +lemma inf'_univ_eq_ciInf (f : ι → α) : univ.inf' univ_nonempty f = ⨅ i, f i := by + simp [inf'_eq_csInf_image, iInf] + end Finset diff --git a/Mathlib/Order/Disjoint.lean b/Mathlib/Order/Disjoint.lean index 34110367e5db6..f835326cd6e3a 100644 --- a/Mathlib/Order/Disjoint.lean +++ b/Mathlib/Order/Disjoint.lean @@ -101,6 +101,10 @@ theorem Disjoint.eq_bot_of_ge (hab : Disjoint a b) : b ≤ a → b = ⊥ := hab.symm.eq_bot_of_le #align disjoint.eq_bot_of_ge Disjoint.eq_bot_of_ge +lemma Disjoint.eq_iff (hab : Disjoint a b) : a = b ↔ a = ⊥ ∧ b = ⊥ := by aesop +lemma Disjoint.ne_iff (hab : Disjoint a b) : a ≠ b ↔ a ≠ ⊥ ∨ b ≠ ⊥ := + hab.eq_iff.not.trans not_and_or + end PartialOrderBot section PartialBoundedOrder @@ -285,6 +289,10 @@ theorem Codisjoint.eq_top_of_ge (hab : Codisjoint a b) : a ≤ b → b = ⊤ := hab.symm.eq_top_of_le #align codisjoint.eq_top_of_ge Codisjoint.eq_top_of_ge +lemma Codisjoint.eq_iff (hab : Codisjoint a b) : a = b ↔ a = ⊤ ∧ b = ⊤ := by aesop +lemma Codisjoint.ne_iff (hab : Codisjoint a b) : a ≠ b ↔ a ≠ ⊤ ∨ b ≠ ⊤ := + hab.eq_iff.not.trans not_and_or + end PartialOrderTop section PartialBoundedOrder diff --git a/Mathlib/Order/Heyting/Basic.lean b/Mathlib/Order/Heyting/Basic.lean index 34b277b28a9b7..4c520ce888cc6 100644 --- a/Mathlib/Order/Heyting/Basic.lean +++ b/Mathlib/Order/Heyting/Basic.lean @@ -442,6 +442,9 @@ theorem le_himp_himp : a ≤ (a ⇨ b) ⇨ b := le_himp_iff.2 inf_himp_le #align le_himp_himp le_himp_himp +@[simp] lemma himp_eq_himp_iff : b ⇨ a = a ⇨ b ↔ a = b := by simp [le_antisymm_iff] +lemma himp_ne_himp_iff : b ⇨ a ≠ a ⇨ b ↔ a ≠ b := himp_eq_himp_iff.not + theorem himp_triangle (a b c : α) : (a ⇨ b) ⊓ (b ⇨ c) ≤ a ⇨ c := by rw [le_himp_iff, inf_right_comm, ← le_himp_iff] exact himp_inf_le.trans le_himp_himp @@ -698,6 +701,9 @@ theorem sdiff_sdiff_le : a \ (a \ b) ≤ b := sdiff_le_iff.2 le_sdiff_sup #align sdiff_sdiff_le sdiff_sdiff_le +@[simp] lemma sdiff_eq_sdiff_iff : a \ b = b \ a ↔ a = b := by simp [le_antisymm_iff] +lemma sdiff_ne_sdiff_iff : a \ b ≠ b \ a ↔ a ≠ b := sdiff_eq_sdiff_iff.not + theorem sdiff_triangle (a b c : α) : a \ c ≤ a \ b ⊔ b \ c := by rw [sdiff_le_iff, sup_left_comm, ← sdiff_le_iff] exact sdiff_sdiff_le.trans le_sup_sdiff From 120ddecb5be159db3457a465faa6698d0e6169de Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Wed, 27 Dec 2023 12:26:55 +0000 Subject: [PATCH 249/353] feat: OrderIso between finite-codimensional subspaces and finite-dimensional subspaces in the dual (#9124) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Introduce the nondegenerate pairing (`(flip_)quotDualCoannihilatorToDual_injective`) between `M ⧸ W.dualCoannihilator` and `W` . If `M` is a vector space and `W` is a finite-dimensional subspace of its dual, this is a perfect pairing (`quotDualCoannihilatorToDual_bijective`), and `W` is equal to the annihilator of its coannihilator. + Use this pairing to show that `dualAnnihilator` and `dualCoannihilator` give an antitone order isomorphism `orderIsoFiniteCodimDim` between finite-codimensional subspaces in a vector space and finite-dimensional subspaces in its dual. This result can be e.g. found in Bourbaki's Algebra. For a finite-dimensional vector space, this gives an OrderIso between all subspaces and all subspaces of the dual. + Add some lemmas about the image and preimage of annihilators and coannihilators under `Dual.eval`. + Expand the docstring of `basis_finite_of_finite_spans` with comments on generalizations. - [x] depends on: #8820 Co-authored-by: Junyan Xu --- Mathlib/LinearAlgebra/Dimension.lean | 10 +- Mathlib/LinearAlgebra/Dual.lean | 133 ++++++++++++++++++++++++++- Mathlib/RingTheory/Finiteness.lean | 3 + 3 files changed, 140 insertions(+), 6 deletions(-) diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean index 32d63f47e5d47..700a622cc7a13 100644 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ b/Mathlib/LinearAlgebra/Dimension.lean @@ -362,7 +362,15 @@ theorem LinearIndependent.set_finite_of_isNoetherian [IsNoetherian R M] {s : Set -- One might hope that a finite spanning set implies that any linearly independent set is finite. -- While this is true over a division ring -- (simply because any linearly independent set can be extended to a basis), --- I'm not certain what more general statements are possible. +-- or over a ring satisfying the strong rank condition +-- (which covers all commutative rings; see `LinearIndependent.finite_of_le_span_finite`). +-- this is not true in general. +-- For example, the left ideal generated by the variables in a noncommutative polynomial ring +-- (`FreeAlgebra R ι`) in infinitely many variables (indexed by `ι`) is free +-- with an infinite basis (consisting of the variables). +-- As another example, for any commutative ring R, the ring of column-finite matrices +-- `Module.End R (ℕ →₀ R)` is isomorphic to `ℕ → Module.End R (ℕ →₀ R)` as a module over itself, +-- which also clearly contains an infinite linearly independent set. /-- Over any nontrivial ring, the existence of a finite spanning set implies that any basis is finite. -/ diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 9574160cc460d..76c0fc9ca8db4 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -62,6 +62,9 @@ The dual space of an $R$-module $M$ is the $R$-module of $R$-linear maps $M \to `LinearMap.range_dual_map_eq_dualAnnihilator_ker`. * `Submodule.dualQuotEquivDualAnnihilator` is the equivalence `Dual R (M ⧸ W) ≃ₗ[R] W.dualAnnihilator` + * `Submodule.quotDualCoannihilatorToDual` is the nondegenerate pairing + `M ⧸ W.dualCoannihilator →ₗ[R] Dual R W`. + It is an perfect pairing when `R` is a field and `W` is finite-dimensional. * Vector spaces: * `Subspace.dualAnnihilator_dualConnihilator_eq` says that the double dual annihilator, pulled back ground `Module.Dual.eval`, is the original submodule. @@ -76,6 +79,10 @@ The dual space of an $R$-module $M$ is the $R$-module of $R$-linear maps $M \to * `Module.evalEquiv` is the equivalence `V ≃ₗ[K] Dual K (Dual K V)` * `Module.mapEvalEquiv` is the order isomorphism between subspaces of `V` and subspaces of `Dual K (Dual K V)`. + * `Subspace.orderIsoFiniteCodimDim` is the antitone order isomorphism between + finite-codimensional subspaces of `V` and finite-dimensional subspaces of `Dual K V`. + * `Subspace.orderIsoFiniteDimensional` is the antitone order isomorphism between + subspaces of a finite-dimensional vector space `V` and subspaces of its dual. * `Subspace.quotDualEquivAnnihilator W` is the equivalence `(Dual K V ⧸ W.dualLift.range) ≃ₗ[K] W.dualAnnihilator`, where `W.dualLift.range` is a copy of `Dual K W` inside `Dual K V`. @@ -902,7 +909,15 @@ theorem mem_dualCoannihilator {Φ : Submodule R (Module.Dual R M)} (x : M) : simp_rw [dualCoannihilator, mem_comap, mem_dualAnnihilator, Module.Dual.eval_apply] #align submodule.mem_dual_coannihilator Submodule.mem_dualCoannihilator -theorem dualAnnihilator_gc (R M : Type*) [CommSemiring R] [AddCommMonoid M] [Module R M] : +theorem comap_dualAnnihilator (Φ : Submodule R (Module.Dual R M)) : + Φ.dualAnnihilator.comap (Module.Dual.eval R M) = Φ.dualCoannihilator := rfl + +theorem map_dualCoannihilator_le (Φ : Submodule R (Module.Dual R M)) : + Φ.dualCoannihilator.map (Module.Dual.eval R M) ≤ Φ.dualAnnihilator := + map_le_iff_le_comap.mpr (comap_dualAnnihilator Φ).le + +variable (R M) in +theorem dualAnnihilator_gc : GaloisConnection (OrderDual.toDual ∘ (dualAnnihilator : Submodule R M → Submodule R (Module.Dual R M))) (dualCoannihilator ∘ OrderDual.ofDual) := by @@ -1042,6 +1057,14 @@ theorem forall_mem_dualAnnihilator_apply_eq_zero_iff (W : Subspace K V) (v : V) rw [← SetLike.ext_iff.mp dualAnnihilator_dualCoannihilator_eq v, mem_dualCoannihilator] #align subspace.forall_mem_dual_annihilator_apply_eq_zero_iff Subspace.forall_mem_dualAnnihilator_apply_eq_zero_iff +theorem comap_dualAnnihilator_dualAnnihilator (W : Subspace K V) : + W.dualAnnihilator.dualAnnihilator.comap (Module.Dual.eval K V) = W := by + ext; rw [Iff.comm, ← forall_mem_dualAnnihilator_apply_eq_zero_iff]; simp + +theorem map_le_dualAnnihilator_dualAnnihilator (W : Subspace K V) : + W.map (Module.Dual.eval K V) ≤ W.dualAnnihilator.dualAnnihilator := + map_le_iff_le_comap.mpr (comap_dualAnnihilator_dualAnnihilator W).ge + /-- `Submodule.dualAnnihilator` and `Submodule.dualCoannihilator` form a Galois coinsertion. -/ def dualAnnihilatorGci (K V : Type*) [Field K] [AddCommGroup V] [Module K V] : GaloisCoinsertion @@ -1145,8 +1168,6 @@ section open FiniteDimensional -variable {V₁ : Type*} [AddCommGroup V₁] [Module K V₁] - instance instModuleDualFiniteDimensional [FiniteDimensional K V] : FiniteDimensional K (Module.Dual K V) := by infer_instance @@ -1154,7 +1175,7 @@ instance instModuleDualFiniteDimensional [FiniteDimensional K V] : @[simp] theorem dual_finrank_eq : finrank K (Module.Dual K V) = finrank K V := by - by_cases h : Module.Finite K V + by_cases h : FiniteDimensional K V · classical exact LinearEquiv.finrank_eq (Basis.ofVectorSpace K V).toDualEquiv.symm rw [finrank_eq_zero_of_basis_imp_false, finrank_eq_zero_of_basis_imp_false] · exact fun _ b ↦ h (Module.Finite.of_basis b) @@ -1308,7 +1329,7 @@ theorem range_dualMap_mkQ_eq (W : Submodule R M) : exists W.dualCopairing ⟨φ, hφ⟩ #align submodule.range_dual_map_mkq_eq Submodule.range_dualMap_mkQ_eq -/-- Equivalence $(M/W)^* \approx \operatorname{ann}(W)$. That is, there is a one-to-one +/-- Equivalence $(M/W)^* \cong \operatorname{ann}(W)$. That is, there is a one-to-one correspondence between the dual of `M ⧸ W` and those elements of the dual of `M` that vanish on `W`. @@ -1339,6 +1360,37 @@ theorem dualQuotEquivDualAnnihilator_symm_apply_mk (W : Submodule R M) (φ : W.d rfl #align submodule.dual_quot_equiv_dual_annihilator_symm_apply_mk Submodule.dualQuotEquivDualAnnihilator_symm_apply_mk +theorem finite_dualAnnihilator_iff {W : Submodule R M} [Free R (M ⧸ W)] : + Finite R W.dualAnnihilator ↔ Finite R (M ⧸ W) := + (Finite.equiv_iff W.dualQuotEquivDualAnnihilator.symm).trans (finite_dual_iff R) + +open LinearMap in +/-- The pairing between a submodule `W` of a dual module `Dual R M` and the quotient of +`M` by the coannihilator of `W`, which is always nondegenerate. -/ +def quotDualCoannihilatorToDual (W : Submodule R (Dual R M)) : + M ⧸ W.dualCoannihilator →ₗ[R] Dual R W := + liftQ _ (flip <| Submodule.subtype _) le_rfl + +@[simp] +theorem quotDualCoannihilatorToDual_apply (W : Submodule R (Dual R M)) (m : M) (w : W) : + W.quotDualCoannihilatorToDual (Quotient.mk m) w = w.1 m := rfl + +theorem quotDualCoannihilatorToDual_injective (W : Submodule R (Dual R M)) : + Function.Injective W.quotDualCoannihilatorToDual := + LinearMap.ker_eq_bot.mp (ker_liftQ_eq_bot _ _ _ le_rfl) + +theorem flip_quotDualCoannihilatorToDual_injective (W : Submodule R (Dual R M)) : + Function.Injective W.quotDualCoannihilatorToDual.flip := + fun _ _ he ↦ Subtype.ext <| LinearMap.ext fun m ↦ FunLike.congr_fun he ⟦m⟧ + +open LinearMap in +theorem quotDualCoannihilatorToDual_nondegenerate (W : Submodule R (Dual R M)) : + W.quotDualCoannihilatorToDual.Nondegenerate := by + rw [Nondegenerate, separatingLeft_iff_ker_eq_bot, separatingRight_iff_flip_ker_eq_bot] + letI : AddCommGroup W := inferInstance + simp_rw [ker_eq_bot] + exact ⟨W.quotDualCoannihilatorToDual_injective, W.flip_quotDualCoannihilatorToDual_injective⟩ + end Submodule namespace LinearMap @@ -1557,6 +1609,77 @@ theorem flip_bijective_iff₂ [FiniteDimensional K V₂] : Bijective B.flip ↔ end LinearMap +namespace Subspace + +variable {K V : Type*} [Field K] [AddCommGroup V] [Module K V] + +theorem quotDualCoannihilatorToDual_bijective (W : Subspace K (Dual K V)) [FiniteDimensional K W] : + Function.Bijective W.quotDualCoannihilatorToDual := + ⟨W.quotDualCoannihilatorToDual_injective, letI : AddCommGroup W := inferInstance + flip_injective_iff₂.mp W.flip_quotDualCoannihilatorToDual_injective⟩ + +theorem flip_quotDualCoannihilatorToDual_bijective (W : Subspace K (Dual K V)) + [FiniteDimensional K W] : Function.Bijective W.quotDualCoannihilatorToDual.flip := + letI : AddCommGroup W := inferInstance + flip_bijective_iff₂.mpr W.quotDualCoannihilatorToDual_bijective + +theorem dualCoannihilator_dualAnnihilator_eq {W : Subspace K (Dual K V)} [FiniteDimensional K W] : + W.dualCoannihilator.dualAnnihilator = W := + let e := (LinearEquiv.ofBijective _ W.flip_quotDualCoannihilatorToDual_bijective).trans + (Submodule.dualQuotEquivDualAnnihilator _) + letI : AddCommGroup W := inferInstance + haveI : FiniteDimensional K W.dualCoannihilator.dualAnnihilator := LinearEquiv.finiteDimensional e + (eq_of_le_of_finrank_eq W.le_dualCoannihilator_dualAnnihilator e.finrank_eq).symm + +theorem finiteDimensional_quot_dualCoannihilator_iff {W : Submodule K (Dual K V)} : + FiniteDimensional K (V ⧸ W.dualCoannihilator) ↔ FiniteDimensional K W := + ⟨fun _ ↦ FiniteDimensional.of_injective _ W.flip_quotDualCoannihilatorToDual_injective, + fun _ ↦ have := Basis.dual_finite (R := K) (M := W) + FiniteDimensional.of_injective _ W.quotDualCoannihilatorToDual_injective⟩ + +open OrderDual in +/-- For any vector space, `dualAnnihilator` and `dualCoannihilator` gives an antitone order + isomorphism between the finite-codimensional subspaces in the vector space and the + finite-dimensional subspaces in its dual. -/ +def orderIsoFiniteCodimDim : + {W : Subspace K V // FiniteDimensional K (V ⧸ W)} ≃o + {W : Subspace K (Dual K V) // FiniteDimensional K W}ᵒᵈ where + toFun W := toDual ⟨W.1.dualAnnihilator, Submodule.finite_dualAnnihilator_iff.mpr W.2⟩ + invFun W := ⟨(ofDual W).1.dualCoannihilator, + finiteDimensional_quot_dualCoannihilator_iff.mpr (ofDual W).2⟩ + left_inv _ := Subtype.ext dualAnnihilator_dualCoannihilator_eq + right_inv W := have := (ofDual W).2; Subtype.ext dualCoannihilator_dualAnnihilator_eq + map_rel_iff' := dualAnnihilator_le_dualAnnihilator_iff + +open OrderDual in +/-- For any finite-dimensional vector space, `dualAnnihilator` and `dualCoannihilator` give + an antitone order isomorphism between the subspaces in the vector space and the subspaces + in its dual. -/ +def orderIsoFiniteDimensional [FiniteDimensional K V] : + Subspace K V ≃o (Subspace K (Dual K V))ᵒᵈ where + toFun W := toDual W.dualAnnihilator + invFun W := (ofDual W).dualCoannihilator + left_inv _ := dualAnnihilator_dualCoannihilator_eq + right_inv _ := dualCoannihilator_dualAnnihilator_eq + map_rel_iff' := dualAnnihilator_le_dualAnnihilator_iff + +open Submodule in +theorem dualAnnihilator_dualAnnihilator_eq_map (W : Subspace K V) [FiniteDimensional K W] : + W.dualAnnihilator.dualAnnihilator = W.map (Dual.eval K V) := by + let e1 := (Free.chooseBasis K W).toDualEquiv ≪≫ₗ W.quotAnnihilatorEquiv.symm + haveI := e1.finiteDimensional + let e2 := (Free.chooseBasis K _).toDualEquiv ≪≫ₗ W.dualAnnihilator.dualQuotEquivDualAnnihilator + haveI := LinearEquiv.finiteDimensional (V₂ := W.dualAnnihilator.dualAnnihilator) e2 + rw [FiniteDimensional.eq_of_le_of_finrank_eq (map_le_dualAnnihilator_dualAnnihilator W)] + rw [← (equivMapOfInjective _ (eval_apply_injective K (V := V)) W).finrank_eq, e1.finrank_eq] + exact e2.finrank_eq + +theorem map_dualCoannihilator (W : Subspace K (Dual K V)) [FiniteDimensional K V] : + W.dualCoannihilator.map (Dual.eval K V) = W.dualAnnihilator := by + rw [← dualAnnihilator_dualAnnihilator_eq_map, dualCoannihilator_dualAnnihilator_eq] + +end Subspace + end FiniteDimensional end VectorSpace diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index afdd498853943..7c5b7f10269ed 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -642,6 +642,9 @@ theorem equiv [Finite R M] (e : M ≃ₗ[R] N) : Finite R N := of_surjective (e : M →ₗ[R] N) e.surjective #align module.finite.equiv Module.Finite.equiv +theorem equiv_iff (e : M ≃ₗ[R] N) : Finite R M ↔ Finite R N := + ⟨fun _ ↦ equiv e, fun _ ↦ equiv e.symm⟩ + instance ulift [Finite R M] : Finite R (ULift M) := equiv ULift.moduleEquiv.symm section Algebra From d5dea345b6194585d78709fa1f8bb362e2e5e38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Wed, 27 Dec 2023 13:14:18 +0000 Subject: [PATCH 250/353] feat(CategoryTheory): another constructor for ComposableArrows (#8541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR, given objects `obj : Fin (n + 1) → C` and `mapSucc i : obj i.castSucc ⟶ obj i.succ` (i.e. a sequence of morphisms), we construct `mkOfObjOfMapSucc obj mapSucc : ComposableArrows C n`. On objects, this constructor has good definitional properties. --- Mathlib/CategoryTheory/ComposableArrows.lean | 48 ++++++++++++++++++++ Mathlib/CategoryTheory/NatIso.lean | 19 ++++++++ 2 files changed, 67 insertions(+) diff --git a/Mathlib/CategoryTheory/ComposableArrows.lean b/Mathlib/CategoryTheory/ComposableArrows.lean index 0e9f965290538..19e67ac6f013c 100644 --- a/Mathlib/CategoryTheory/ComposableArrows.lean +++ b/Mathlib/CategoryTheory/ComposableArrows.lean @@ -825,6 +825,54 @@ lemma mk₅_surjective (X : ComposableArrows C 5) : ⟨_, _, _, _, _, _, X.map' 0 1, X.map' 1 2, X.map' 2 3, X.map' 3 4, X.map' 4 5, ext₅ rfl rfl rfl rfl rfl rfl (by simp) (by simp) (by simp) (by simp) (by simp)⟩ +/-- The `i`th arrow of `F : ComposableArrows C n`. -/ +def arrow (i : ℕ) (hi : i < n := by linarith) : + ComposableArrows C 1 := mk₁ (F.map' i (i + 1)) + +section mkOfObjOfMapSucc + +variable (obj : Fin (n + 1) → C) (mapSucc : ∀ (i : Fin n), obj i.castSucc ⟶ obj i.succ) + +lemma mkOfObjOfMapSucc_exists : ∃ (F : ComposableArrows C n) (e : ∀ i, F.obj i ≅ obj i), + ∀ (i : ℕ) (hi : i < n), mapSucc ⟨i, hi⟩ = + (e ⟨i, _⟩).inv ≫ F.map' i (i + 1) ≫ (e ⟨i + 1, _⟩).hom := by + clear F G + revert obj mapSucc + induction' n with n hn + · intro obj _ + exact ⟨mk₀ (obj 0), fun 0 => Iso.refl _, fun i hi => by simp at hi⟩ + · intro obj mapSucc + obtain ⟨F, e, h⟩ := hn (fun i => obj i.succ) (fun i => mapSucc i.succ) + refine' ⟨F.precomp (mapSucc 0 ≫ (e 0).inv), fun i => match i with + | 0 => Iso.refl _ + | ⟨i + 1, hi⟩ => e _, fun i hi => _⟩ + obtain _ | i := i + · dsimp + rw [assoc, Iso.inv_hom_id, comp_id] + erw [id_comp] + · exact h i (by linarith) + +/-- Given `obj : Fin (n + 1) → C` and `mapSucc i : obj i.castSucc ⟶ obj i.succ` +for all `i : Fin n`, this is `F : ComposableArrows C n` such that `F.obj i` is +definitionally equal to `obj i` and such that `F.map' i (i + 1) = mapSucc ⟨i, hi⟩`. -/ +noncomputable def mkOfObjOfMapSucc : ComposableArrows C n := + (mkOfObjOfMapSucc_exists obj mapSucc).choose.copyObj obj + (mkOfObjOfMapSucc_exists obj mapSucc).choose_spec.choose + +@[simp] +lemma mkOfObjOfMapSucc_obj (i : Fin (n + 1)) : + (mkOfObjOfMapSucc obj mapSucc).obj i = obj i := rfl + +lemma mkOfObjOfMapSucc_map_succ (i : ℕ) (hi : i < n := by linarith) : + (mkOfObjOfMapSucc obj mapSucc).map' i (i + 1) = mapSucc ⟨i, hi⟩ := + ((mkOfObjOfMapSucc_exists obj mapSucc).choose_spec.choose_spec i hi).symm + +lemma mkOfObjOfMapSucc_arrow (i : ℕ) (hi : i < n := by linarith) : + (mkOfObjOfMapSucc obj mapSucc).arrow i = mk₁ (mapSucc ⟨i, hi⟩) := + ext₁ rfl rfl (by simpa using mkOfObjOfMapSucc_map_succ obj mapSucc i hi) + +end mkOfObjOfMapSucc + end ComposableArrows variable {C} diff --git a/Mathlib/CategoryTheory/NatIso.lean b/Mathlib/CategoryTheory/NatIso.lean index 99378933fe169..e89b33a857385 100644 --- a/Mathlib/CategoryTheory/NatIso.lean +++ b/Mathlib/CategoryTheory/NatIso.lean @@ -264,4 +264,23 @@ theorem isIso_map_iff {F₁ F₂ : C ⥤ D} (e : F₁ ≅ F₂) {X Y : C} (f : X end NatIso +namespace Functor + +variable (F : C ⥤ D) (obj : C → D) (e : ∀ X, F.obj X ≅ obj X) + +/-- Constructor for a functor that is isomorphic to a given functor `F : C ⥤ D`, +while being definitionally equal on objects to a given map `obj : C → D` +such that for all `X : C`, we have an isomorphism `F.obj X ≅ obj X`. -/ +@[simps obj] +def copyObj : C ⥤ D where + obj := obj + map f := (e _).inv ≫ F.map f ≫ (e _).hom + +/-- The functor constructed with `copyObj` is isomorphic to the given functor. -/ +@[simps!] +def isoCopyObj : F ≅ F.copyObj obj e := + NatIso.ofComponents e (by simp [Functor.copyObj]) + +end Functor + end CategoryTheory From 6ecca6c449485237681bdd3de5bed0bb8ab9c47d Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 27 Dec 2023 13:14:19 +0000 Subject: [PATCH 251/353] feat(GroupTheory/GroupAction/Opposite): add notation for right and left actions (#8909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new notations (with `open scoped RightActions`) are: * `r •> m` as an alias for `r • m` * `m <• r` as an alias for `MulOpposite.op r • m` * `r +ᵥ> m` as an alias for `r +ᵥ m` * `m <+ᵥ r` as an alias for `AddOpposite.op r +ᵥ m` An alternative proposal was to use variants of `•` with arrows inside: * `r ⮊ m` as an alias for `r • m` * `m ⮈ r` as an alias for `MulOpposite.op r • m` but this doesn't have an obvious additive counterpart, and apparently has font issues. Zulip messages: * ["And `m <• r` would be notation for `(to_opposite r) • m`, or something like that?"](https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/left.20vs.20right.20modules.20in.20tensor.20products/near/262063344) * ["I rather like the idea of having a new piece of notation for right actions"](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Noncommutative.20ring.20things/near/390011490) * [I like your proposed notation `<•` for the right scalar action. Maybe we should even introduce `•>` as an alias for `•`](https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/ideals.20in.20non-comm.20rings/near/252156362) Co-authored-by: Yaël Dillies --- Mathlib/GroupTheory/GroupAction/Opposite.lean | 81 ++++++++++++++++++- test/right_actions.lean | 77 ++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 test/right_actions.lean diff --git a/Mathlib/GroupTheory/GroupAction/Opposite.lean b/Mathlib/GroupTheory/GroupAction/Opposite.lean index 3f14d8286dadf..57fb6de5fc37f 100644 --- a/Mathlib/GroupTheory/GroupAction/Opposite.lean +++ b/Mathlib/GroupTheory/GroupAction/Opposite.lean @@ -17,6 +17,15 @@ type, `SMul Rᵐᵒᵖ M`. Note that `MulOpposite.smul` is provided in an earlier file as it is needed to provide the `AddMonoid.nsmul` and `AddCommGroup.zsmul` fields. + +## Notation + +With `open scoped RightActions`, this provides: + +* `r •> m` as an alias for `r • m` +* `m <• r` as an alias for `MulOpposite.op r • m` +* `v +ᵥ> p` as an alias for `v +ᵥ p` +* `p <+ᵥ v` as an alias for `AddOpposite.op v +ᵥ p` -/ @@ -71,6 +80,77 @@ theorem unop_smul_eq_unop_smul_unop {R : Type*} [SMul R α] [SMul Rᵐᵒᵖ α] end MulOpposite +/-! ### Right actions + +In this section we establish `SMul αᵐᵒᵖ β` as the canonical spelling of right scalar multiplication +of `β` by `α`, and provide convienient notations. +-/ + +namespace RightActions + +/-- With `open scoped RightActions`, an alternative symbol for left actions, `r • m`. + +In lemma names this is still called `smul`. -/ +scoped notation3:74 r:75 " •> " m:74 => r • m + +/-- With `open scoped RightActions`, a shorthand for right actions, `op r • m`. + +In lemma names this is still called `op_smul`. -/ +scoped notation3:73 m:73 " <• " r:74 => MulOpposite.op r • m + +/-- With `open scoped RightActions`, an alternative symbol for left actions, `r • m`. + +In lemma names this is still called `vadd`. -/ +scoped notation3:74 r:75 " +ᵥ> " m:74 => r +ᵥ m + +/-- With `open scoped RightActions`, a shorthand for right actions, `op r +ᵥ m`. + +In lemma names this is still called `op_vadd`. -/ +scoped notation3:73 m:73 " <+ᵥ " r:74 => AddOpposite.op r +ᵥ m + +section examples +variable {α β : Type*} [SMul α β] [SMul αᵐᵒᵖ β] [VAdd α β] [VAdd αᵃᵒᵖ β] {a a₁ a₂ a₃ a₄ : α} {b : β} + +-- Left and right actions are just notation around the general `•` and `+ᵥ` notations +example : a •> b = a • b := rfl +example : b <• a = MulOpposite.op a • b := rfl + +example : a +ᵥ> b = a +ᵥ b := rfl +example : b <+ᵥ a = AddOpposite.op a +ᵥ b := rfl + +-- Left actions right-associate, right actions left-associate +example : a₁ •> a₂ •> b = a₁ •> (a₂ •> b) := rfl +example : b <• a₂ <• a₁ = (b <• a₂) <• a₁ := rfl + +example : a₁ +ᵥ> a₂ +ᵥ> b = a₁ +ᵥ> (a₂ +ᵥ> b) := rfl +example : b <+ᵥ a₂ <+ᵥ a₁ = (b <+ᵥ a₂) <+ᵥ a₁ := rfl + +-- When left and right actions coexist, they associate to the left +example : a₁ •> b <• a₂ = (a₁ •> b) <• a₂ := rfl +example : a₁ •> a₂ •> b <• a₃ <• a₄ = ((a₁ •> (a₂ •> b)) <• a₃) <• a₄ := rfl + +example : a₁ +ᵥ> b <+ᵥ a₂ = (a₁ +ᵥ> b) <+ᵥ a₂ := rfl +example : a₁ +ᵥ> a₂ +ᵥ> b <+ᵥ a₃ <+ᵥ a₄ = ((a₁ +ᵥ> (a₂ +ᵥ> b)) <+ᵥ a₃) <+ᵥ a₄ := rfl + +end examples + +end RightActions + +section +variable {α β : Type*} + +open scoped RightActions + +@[to_additive] +theorem op_smul_op_smul [Monoid α] [MulAction αᵐᵒᵖ β] (b : β) (a₁ a₂ : α) : + b <• a₁ <• a₂ = b <• (a₁ * a₂) := smul_smul _ _ _ + +@[to_additive] +theorem op_smul_mul [Monoid α] [MulAction αᵐᵒᵖ β] (b : β) (a₁ a₂ : α) : + b <• (a₁ * a₂) = b <• a₁ <• a₂ := mul_smul _ _ _ + +end section + /-! ### Actions _by_ the opposite type (right actions) In `Mul.toSMul` in another file, we define the left action `a₁ • a₂ = a₁ * a₂`. For the @@ -78,7 +158,6 @@ multiplicative opposite, we define `MulOpposite.op a₁ • a₂ = a₂ * a₁`, reversed. -/ - open MulOpposite /-- Like `Mul.toSMul`, but multiplies on the right. diff --git a/test/right_actions.lean b/test/right_actions.lean new file mode 100644 index 0000000000000..92ddf28e84121 --- /dev/null +++ b/test/right_actions.lean @@ -0,0 +1,77 @@ +import Mathlib.GroupTheory.GroupAction.Opposite + +open MulOpposite renaming op → mop +open AddOpposite renaming op → aop + +variable {α β : Type*} [SMul α β] [SMul αᵐᵒᵖ β] [VAdd α β] [VAdd αᵃᵒᵖ β] {a a₁ a₂ a₃ a₄ : α} {b : β} + +section delaborators + +section without_scope + +/-- info: a • b : β -/ +#guard_msgs in +#check a • b + +/-- info: MulOpposite.op a • b : β -/ +#guard_msgs in +#check mop a • b + +/-- info: a +ᵥ b : β -/ +#guard_msgs in +#check a +ᵥ b + +/-- info: AddOpposite.op a +ᵥ b : β -/ +#guard_msgs in +#check aop a +ᵥ b + +end without_scope + +section with_scope +open scoped RightActions + +/-- info: a •> b : β -/ +#guard_msgs in +#check a • b + +/-- info: b <• a : β -/ +#guard_msgs in +#check mop a • b + +/-- info: a +ᵥ> b : β -/ +#guard_msgs in +#check a +ᵥ b + +/-- info: b <+ᵥ a : β -/ +#guard_msgs in +#check aop a +ᵥ b + +end with_scope + +end delaborators + +open scoped RightActions + +example : a •> b = a • b := rfl +example : b <• a = mop a • b := rfl + +example : a +ᵥ> b = a +ᵥ b := rfl +example : b <+ᵥ a = aop a +ᵥ b := rfl + +-- Left actions right-associate, right actions left-associate +example : a₁ •> a₂ •> b = a₁ •> (a₂ •> b) := rfl +example : b <• a₂ <• a₁ = (b <• a₂) <• a₁ := rfl + +example : a₁ +ᵥ> a₂ +ᵥ> b = a₁ +ᵥ> (a₂ +ᵥ> b) := rfl +example : b <+ᵥ a₂ <+ᵥ a₁ = (b <+ᵥ a₂) <+ᵥ a₁ := rfl + +-- When left and right actions coexist, they associate to the left +example : a₁ •> b <• a₂ = (a₁ •> b) <• a₂ := rfl +example : a₁ •> a₂ •> b <• a₃ <• a₄ = ((a₁ •> (a₂ •> b)) <• a₃) <• a₄ := rfl + +example : a₁ +ᵥ> b <+ᵥ a₂ = (a₁ +ᵥ> b) <+ᵥ a₂ := rfl +example : a₁ +ᵥ> a₂ +ᵥ> b <+ᵥ a₃ <+ᵥ a₄ = ((a₁ +ᵥ> (a₂ +ᵥ> b)) <+ᵥ a₃) <+ᵥ a₄ := rfl + +-- association is chosen to match multiplication and addition +example {M} [Mul M] {x y z : M} : x •> y <• z = x * y * z := rfl +example {A} [Add A] {x y z : A} : x +ᵥ> y <+ᵥ z = x + y + z := rfl From 33e9813d07511f14a8fa3c694682402f51f4f5c1 Mon Sep 17 00:00:00 2001 From: Xavier Xarles Date: Wed, 27 Dec 2023 14:16:48 +0000 Subject: [PATCH 252/353] feat(RingTheory/TensorProduct): Tensor product for CommSemiring (#9125) Added the instance of TensorProduct.instCommRing. Previously we only had the `CommRing` and `Semiring` instance; this moves an existing proof to populate the intermediate instance. Co-authored-by: Xavier Xarles <56635243+XavierXarles@users.noreply.github.com> Co-authored-by: Eric Wieser --- Mathlib/RingTheory/Kaehler.lean | 6 ++--- Mathlib/RingTheory/TensorProduct.lean | 39 +++++++++++++++++---------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/Mathlib/RingTheory/Kaehler.lean b/Mathlib/RingTheory/Kaehler.lean index 1e34ef46ad200..037effaa5c06d 100644 --- a/Mathlib/RingTheory/Kaehler.lean +++ b/Mathlib/RingTheory/Kaehler.lean @@ -400,19 +400,19 @@ local instance smul_SSmod_SSmod : SMul (S ⊗[R] S ⧸ KaehlerDifferential.ideal @[nolint defLemma] local instance isScalarTower_S_right : IsScalarTower S (S ⊗[R] S ⧸ KaehlerDifferential.ideal R S ^ 2) - (S ⊗[R] S ⧸ KaehlerDifferential.ideal R S ^ 2) := IsScalarTower.right + (S ⊗[R] S ⧸ KaehlerDifferential.ideal R S ^ 2) := Ideal.Quotient.isScalarTower_right /-- A shortcut instance to prevent timing out. Hopefully to be removed in the future. -/ @[nolint defLemma] local instance isScalarTower_R_right : IsScalarTower R (S ⊗[R] S ⧸ KaehlerDifferential.ideal R S ^ 2) - (S ⊗[R] S ⧸ KaehlerDifferential.ideal R S ^ 2) := IsScalarTower.right + (S ⊗[R] S ⧸ KaehlerDifferential.ideal R S ^ 2) := Ideal.Quotient.isScalarTower_right /-- A shortcut instance to prevent timing out. Hopefully to be removed in the future. -/ @[nolint defLemma] local instance isScalarTower_SS_right : IsScalarTower (S ⊗[R] S) (S ⊗[R] S ⧸ KaehlerDifferential.ideal R S ^ 2) (S ⊗[R] S ⧸ KaehlerDifferential.ideal R S ^ 2) := - IsScalarTower.right + Ideal.Quotient.isScalarTower_right /-- A shortcut instance to prevent timing out. Hopefully to be removed in the future. -/ local instance instS : Module S (KaehlerDifferential.ideal R S).cotangentIdeal := diff --git a/Mathlib/RingTheory/TensorProduct.lean b/Mathlib/RingTheory/TensorProduct.lean index 0bda602a6d98c..fa8df04e49e0c 100644 --- a/Mathlib/RingTheory/TensorProduct.lean +++ b/Mathlib/RingTheory/TensorProduct.lean @@ -508,6 +508,30 @@ instance instNonUnitalRing : NonUnitalRing (A ⊗[R] B) where end NonUnitalRing +section CommSemiring +variable [CommSemiring R] +variable [CommSemiring A] [Algebra R A] +variable [CommSemiring B] [Algebra R B] + +instance instCommSemiring : CommSemiring (A ⊗[R] B) where + toSemiring := inferInstance + mul_comm x y := by + refine TensorProduct.induction_on x ?_ ?_ ?_ + · simp + · intro a₁ b₁ + refine TensorProduct.induction_on y ?_ ?_ ?_ + · simp + · intro a₂ b₂ + simp [mul_comm] + · intro a₂ b₂ ha hb + -- porting note: was `simp` not `rw` + rw [mul_add, add_mul, ha, hb] + · intro x₁ x₂ h₁ h₂ + -- porting note: was `simp` not `rw` + rw [mul_add, add_mul, h₁, h₂] + +end CommSemiring + section Ring variable [CommRing R] variable [Ring A] [Algebra R A] @@ -534,20 +558,7 @@ variable [CommRing B] [Algebra R B] instance instCommRing : CommRing (A ⊗[R] B) := { toRing := inferInstance - mul_comm := fun x y => by - refine TensorProduct.induction_on x ?_ ?_ ?_ - · simp - · intro a₁ b₁ - refine TensorProduct.induction_on y ?_ ?_ ?_ - · simp - · intro a₂ b₂ - simp [mul_comm] - · intro a₂ b₂ ha hb - -- porting note: was `simp` not `rw` - rw [mul_add, add_mul, ha, hb] - · intro x₁ x₂ h₁ h₂ - -- porting note: was `simp` not `rw` - rw [mul_add, add_mul, h₁, h₂] } + mul_comm := mul_comm } section RightAlgebra From 3d732b1000511237fa845d6cdcf0aaf333245e49 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Wed, 27 Dec 2023 15:22:06 +0000 Subject: [PATCH 253/353] chore: remove now-unneeded dsimp and its associated porting note (#9304) The `dsimp only` is no longer needed after #3222 adjusted the definition of `Units.ext`. --- Mathlib/Algebra/Group/Units/Hom.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Algebra/Group/Units/Hom.lean b/Mathlib/Algebra/Group/Units/Hom.lean index 53082678279c7..1860fc13f5f76 100644 --- a/Mathlib/Algebra/Group/Units/Hom.lean +++ b/Mathlib/Algebra/Group/Units/Hom.lean @@ -156,7 +156,7 @@ this map is a monoid homomorphism too. -/ is an AddMonoid homomorphism too."] def liftRight (f : M →* N) (g : M → Nˣ) (h : ∀ x, ↑(g x) = f x) : M →* Nˣ where toFun := g - map_one' := by ext; dsimp only; rw [h 1]; exact f.map_one -- Porting note: why is `dsimp` needed? + map_one' := by ext; rw [h 1]; exact f.map_one map_mul' x y := Units.ext <| by simp only [h, val_mul, f.map_mul] #align units.lift_right Units.liftRight #align add_units.lift_right AddUnits.liftRight From 49d59e74aba9f702d880a09545b9db9b3a850ef4 Mon Sep 17 00:00:00 2001 From: Arend Mellendijk Date: Wed, 27 Dec 2023 17:24:01 +0000 Subject: [PATCH 254/353] feat: define `prodPrimeFactors` as an `ArithmeticFunction` (#6662) Define the arithmetic function $n \mapsto \prod_{p \mid n} f(p)$. This PR further proves that it's multiplicative and relates it to Dirichlet convolution. Finally it proves two identities that can be applied in a context where you're not working exclusively with `ArithmeticFunction`s This construction was mentioned on [zulip](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/finite.20product.20of.20infinite.20sums/near/379577022) Co-authored-by: Arend Mellendijk --- Mathlib/Data/Nat/Squarefree.lean | 7 ++ Mathlib/NumberTheory/ArithmeticFunction.lean | 89 +++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index 10fe9df266569..c24c4e80bf022 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -428,6 +428,13 @@ lemma prod_primeFactors_invOn_squarefree : {s | ∀ p ∈ s, p.Prime} {n | Squarefree n} := ⟨fun _s ↦ primeFactors_prod, fun _n ↦ prod_primeFactors_of_squarefree⟩ +theorem prod_primeFactors_sdiff_of_squarefree {n : ℕ} (hn : Squarefree n) {t : Finset ℕ} + (ht : t ⊆ n.primeFactors) : + ∏ a in (n.primeFactors \ t), a = n / ∏ a in t, a := by + refine symm $ Nat.div_eq_of_eq_mul_left (Finset.prod_pos + fun p hp => (prime_of_mem_factors (List.mem_toFinset.mp (ht hp))).pos) ?_ + rw [Finset.prod_sdiff ht, prod_primeFactors_of_squarefree hn] + end Nat -- Porting note: comment out NormNum tactic, to be moved to another file. diff --git a/Mathlib/NumberTheory/ArithmeticFunction.lean b/Mathlib/NumberTheory/ArithmeticFunction.lean index e55fb1fa7b941..606b2c417a74e 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction.lean @@ -47,8 +47,12 @@ to form the Dirichlet ring. * `prod_eq_iff_prod_pow_moebius_eq_on_of_nonzero` for functions to a `CommGroupWithZero` ## Notation -The arithmetic functions `ζ` and `σ` have Greek letter names, which are localized notation in -the namespace `ArithmeticFunction`. +All notation is localized in the namespace `ArithmeticFunction`. + +The arithmetic functions `ζ`, `σ`, `ω`, `Ω` and `μ` have Greek letter names. + +The arithmetic function $$n \mapsto \prod_{p \mid n} f(p)$$ is given custom notation +`∏ᵖ p ∣ n, f p` when applied to `n`. ## Tags arithmetic functions, dirichlet convolution, divisors @@ -590,6 +594,31 @@ theorem pdiv_zeta [DivisionSemiring R] (f : ArithmeticFunction R) : end Pdiv +section ProdPrimeFactors + +/-- The map $n \mapsto \prod_{p \mid n} f(p)$ as an arithmetic function -/ +def prodPrimeFactors [CommMonoidWithZero R] (f : ℕ → R) : ArithmeticFunction R where + toFun d := if d = 0 then 0 else ∏ p in d.primeFactors, f p + map_zero' := if_pos rfl + +open Std.ExtendedBinder + +/-- `∏ᵖ p ∣ n, f p` is custom notation for `prodPrimeFactors f n` -/ +scoped syntax (name := bigproddvd) "∏ᵖ " extBinder " ∣ " term ", " term:67 : term +scoped macro_rules (kind := bigproddvd) + | `(∏ᵖ $x:ident ∣ $n, $r) => `(prodPrimeFactors (fun $x ↦ $r) $n) + +@[simp] +theorem prodPrimeFactors_apply [CommMonoidWithZero R] {f: ℕ → R} {n : ℕ} (hn : n ≠ 0) : + ∏ᵖ p ∣ n, f p = ∏ p in n.primeFactors, f p := + if_neg hn + +theorem prodPrimeFactors_apply_of_ne_zero [CommMonoidWithZero R] {f : ℕ → R} {n : ℕ} + (hn : n ≠ 0) : ∏ᵖ p ∣ n, f p = ∏ p in n.primeFactors, f p := + prodPrimeFactors_apply hn + +end ProdPrimeFactors + /-- Multiplicative functions -/ def IsMultiplicative [MonoidWithZero R] (f : ArithmeticFunction R) : Prop := f 1 = 1 ∧ ∀ {m n : ℕ}, m.Coprime n → f (m * n) = f m * f n @@ -625,6 +654,18 @@ theorem map_prod {ι : Type*} [CommMonoidWithZero R] (g : ι → ℕ) {f : Nat.A exact .prod_right fun i hi => hs.2 _ hi (hi.ne_of_not_mem has).symm #align nat.arithmetic_function.is_multiplicative.map_prod Nat.ArithmeticFunction.IsMultiplicative.map_prod +theorem map_prod_of_prime [CommSemiring R] {f : ArithmeticFunction R} + (h_mult : ArithmeticFunction.IsMultiplicative f) + (t : Finset ℕ) (ht : ∀ p ∈ t, p.Prime) : + f (∏ a in t, a) = ∏ a : ℕ in t, f a := + map_prod _ h_mult t fun x hx y hy hxy => (coprime_primes (ht x hx) (ht y hy)).mpr hxy + +theorem map_prod_of_subset_primeFactors [CommSemiring R] {f : ArithmeticFunction R} + (h_mult : ArithmeticFunction.IsMultiplicative f) (l : ℕ) + (t : Finset ℕ) (ht : t ⊆ l.primeFactors) : + f (∏ a in t, a) = ∏ a : ℕ in t, f a := + map_prod_of_prime h_mult t fun _ a => prime_of_mem_primeFactors (ht a) + theorem nat_cast {f : ArithmeticFunction ℕ} [Semiring R] (h : f.IsMultiplicative) : IsMultiplicative (f : ArithmeticFunction R) := -- porting note: was `by simp [cop, h]` @@ -754,6 +795,29 @@ theorem eq_iff_eq_on_prime_powers [CommMonoidWithZero R] (f : ArithmeticFunction exact Finset.prod_congr rfl fun p hp ↦ h p _ (Nat.prime_of_mem_primeFactors hp) #align nat.arithmetic_function.is_multiplicative.eq_iff_eq_on_prime_powers Nat.ArithmeticFunction.IsMultiplicative.eq_iff_eq_on_prime_powers +theorem prodPrimeFactors [CommMonoidWithZero R] (f : ℕ → R) : + IsMultiplicative (prodPrimeFactors f) := by + rw [iff_ne_zero] + refine ⟨prodPrimeFactors_apply one_ne_zero, ?_⟩ + intro x y hx hy hxy + have hxy₀: x*y ≠ 0 := by exact Nat.mul_ne_zero hx hy + rw [prodPrimeFactors_apply hxy₀, prodPrimeFactors_apply hx, prodPrimeFactors_apply hy, + Nat.primeFactors_mul hx hy, ← Finset.prod_union hxy.disjoint_primeFactors] + +theorem prodPrimeFactors_add_of_squarefree [CommSemiring R] {f g : ArithmeticFunction R} + (hf : IsMultiplicative f) (hg : IsMultiplicative g) {n : ℕ} (hn : Squarefree n) : + ∏ᵖ p ∣ n, (f + g) p = (f * g) n := by + rw [prodPrimeFactors_apply_of_ne_zero hn.ne_zero] + simp_rw [add_apply (f:=f) (g:=g)] + rw [Finset.prod_add, mul_apply, sum_divisorsAntidiagonal (f · * g ·), + ← divisors_filter_squarefree_of_squarefree hn, sum_divisors_filter_squarefree hn.ne_zero, + factors_eq] + apply Finset.sum_congr rfl + intro t ht + erw [t.prod_val, ← prod_primeFactors_sdiff_of_squarefree hn (Finset.mem_powerset.mp ht), + hf.map_prod_of_subset_primeFactors n t (Finset.mem_powerset.mp ht), + ← hg.map_prod_of_subset_primeFactors n (_ \ t) (Finset.sdiff_subset _ t)] + theorem lcm_apply_mul_gcd_apply [CommMonoidWithZero R] {f : ArithmeticFunction R} (hf : f.IsMultiplicative) {x y : ℕ} : f (x.lcm y) * f (x.gcd y) = f x * f y := by @@ -1046,6 +1110,27 @@ theorem isMultiplicative_moebius : IsMultiplicative μ := by cardFactors_mul hn hm, pow_add] #align nat.arithmetic_function.is_multiplicative_moebius Nat.ArithmeticFunction.isMultiplicative_moebius +theorem IsMultiplicative.prodPrimeFactors_one_add_of_squarefree [CommSemiring R] + {f : ArithmeticFunction R} (h_mult : f.IsMultiplicative) {n : ℕ} (hn : Squarefree n) : + ∏ p in n.primeFactors, (1 + f p) = ∑ d in n.divisors, f d := by + trans (∏ᵖ p ∣ n, ((ζ:ArithmeticFunction R) + f) p) + · simp_rw [prodPrimeFactors_apply hn.ne_zero, add_apply, natCoe_apply] + apply Finset.prod_congr rfl; intro p hp; + rw [zeta_apply_ne (prime_of_mem_factors $ List.mem_toFinset.mp hp).ne_zero, cast_one] + rw [isMultiplicative_zeta.nat_cast.prodPrimeFactors_add_of_squarefree h_mult hn, + coe_zeta_mul_apply] + +theorem IsMultiplicative.prodPrimeFactors_one_sub_of_squarefree [CommRing R] + (f : ArithmeticFunction R) (hf : f.IsMultiplicative) {n : ℕ} (hn : Squarefree n) : + ∏ p in n.primeFactors, (1 - f p) = ∑ d in n.divisors, μ d * f d := by + trans (∏ p in n.primeFactors, (1 + (ArithmeticFunction.pmul (μ:ArithmeticFunction R) f) p)) + · apply Finset.prod_congr rfl; intro p hp + rw [pmul_apply, intCoe_apply, ArithmeticFunction.moebius_apply_prime + (prime_of_mem_factors (List.mem_toFinset.mp hp))] + ring + · rw [(isMultiplicative_moebius.int_cast.pmul hf).prodPrimeFactors_one_add_of_squarefree hn] + simp_rw [pmul_apply, intCoe_apply] + open UniqueFactorizationMonoid @[simp] From a63bd3b0873f65314b5ab1e82321fe8f7ee42fc9 Mon Sep 17 00:00:00 2001 From: damiano Date: Wed, 27 Dec 2023 18:34:45 +0000 Subject: [PATCH 255/353] feat(Tactic/ExtendDoc): add `extend_doc` command (#7446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is related to [Issue leanprover/lean4#2622](https://github.com/leanprover/lean4/issues/2622). In the file where declaration `decl` is defined, writing ```lean extend_doc decl before "I will be added as a prefix to the docs of `decl`" after "I will be added as a suffix to the docs of `decl`" ``` does what is probably clear: it extends the doc-string of `decl` by adding the string immediately following `before` at the beginning and the string immediately following`after` at the end. This is useful, for instance, when the docs of `decl` are obtained via `inherit_doc`. [Zulip discussion](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/tactic.20docstrings) By way of example, I redefine the docs over `rw`. The new doc-string is ```lean `rw` is like `rewrite` (see below), but also tries to close the goal by "cheap" (reducible) `rfl` afterwards. `rewrite [e]` applies identity `e` as a rewrite rule to the target of the main goal. If `e` is preceded by left arrow (`←` or `<-`), the rewrite is applied in the reverse direction. If `e` is a defined constant, then the equational theorems associated with `e` are used. This provides a convenient way to unfold `e`. - `rewrite [e₁, ..., eₙ]` applies the given rules sequentially. - `rewrite [e] at l` rewrites `e` at location(s) `l`, where `l` is either `*` or a list of hypotheses in the local context. In the latter case, a turnstile `⊢` or `|-` can also be used, to signify the target of the goal. Using `rw (config := {occs := .pos L}) [e]`, where `L : List Nat`, you can control which "occurrences" are rewritten. (This option applies to each rule, so usually this will only be used with a single rule.) Occurrences count from `1`. At the first occurrence, whether allowed or not, arguments of the rewrite rule `e` may be instantiated, restricting which later rewrites can be found. `{occs := .neg L}` allows skipping specified occurrences. ``` --- Mathlib.lean | 1 + Mathlib/Tactic.lean | 1 + Mathlib/Tactic/Basic.lean | 1 + Mathlib/Tactic/ExtendDoc.lean | 41 +++++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+) create mode 100644 Mathlib/Tactic/ExtendDoc.lean diff --git a/Mathlib.lean b/Mathlib.lean index cbadc395b2594..4ec03132fad86 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3293,6 +3293,7 @@ import Mathlib.Tactic.Existsi import Mathlib.Tactic.Explode import Mathlib.Tactic.Explode.Datatypes import Mathlib.Tactic.Explode.Pretty +import Mathlib.Tactic.ExtendDoc import Mathlib.Tactic.ExtractGoal import Mathlib.Tactic.ExtractLets import Mathlib.Tactic.FBinop diff --git a/Mathlib/Tactic.lean b/Mathlib/Tactic.lean index 683ef49979b5b..3449074553a7a 100644 --- a/Mathlib/Tactic.lean +++ b/Mathlib/Tactic.lean @@ -45,6 +45,7 @@ import Mathlib.Tactic.Existsi import Mathlib.Tactic.Explode import Mathlib.Tactic.Explode.Datatypes import Mathlib.Tactic.Explode.Pretty +import Mathlib.Tactic.ExtendDoc import Mathlib.Tactic.ExtractGoal import Mathlib.Tactic.ExtractLets import Mathlib.Tactic.FBinop diff --git a/Mathlib/Tactic/Basic.lean b/Mathlib/Tactic/Basic.lean index ed0d7527edb11..5a1a3f5a3ff74 100644 --- a/Mathlib/Tactic/Basic.lean +++ b/Mathlib/Tactic/Basic.lean @@ -6,6 +6,7 @@ Authors: Mario Carneiro, Kyle Miller import Lean import Std import Mathlib.Tactic.PPWithUniv +import Mathlib.Tactic.ExtendDoc set_option autoImplicit true diff --git a/Mathlib/Tactic/ExtendDoc.lean b/Mathlib/Tactic/ExtendDoc.lean new file mode 100644 index 0000000000000..1536c317c294c --- /dev/null +++ b/Mathlib/Tactic/ExtendDoc.lean @@ -0,0 +1,41 @@ +/- +Copyright (c) 2023 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Damiano Testa +-/ + +import Lean.Elab.ElabRules + +/-! +# `extend_doc` command + +In a file where declaration `decl` is defined, writing +```lean +extend_doc decl + before "I will be added as a prefix to the docs of `decl`" + after "I will be added as a suffix to the docs of `decl`" +``` + +does what is probably clear: it extends the doc-string of `decl` by adding the string of +`before` at the beginning and the string of `after` at the end. + +At least one of `before` and `after` must appear, but either one of them is optional. +-/ + +namespace Mathlib.Tactic.ExtendDocs + +/-- `extend_docs before after ` extends the +docs of `` by adding `` before and `` after. -/ +syntax "extend_docs" ident (colGt "before" str)? (colGt "after" str)? : command + +open Lean in +elab_rules : command + | `(command| extend_docs $na:ident $[before $bef:str]? $[after $aft:str]?) => do + if bef.isNone && aft.isNone then throwError "expected at least one of 'before' or 'after'" + let declName ← Elab.resolveGlobalConstNoOverloadWithInfo na + let bef := if bef.isNone then "" else (bef.get!).getString ++ "\n\n" + let aft := if aft.isNone then "" else "\n\n" ++ (aft.get!).getString + let oldDoc := (← findDocString? (← getEnv) declName).getD "" + addDocString declName <| bef ++ oldDoc ++ aft + +end Mathlib.Tactic.ExtendDocs From 98e2ce28c9b86b09f280b6a6d1513b0d138cf45a Mon Sep 17 00:00:00 2001 From: sgouezel Date: Wed, 27 Dec 2023 18:34:46 +0000 Subject: [PATCH 256/353] archive: smooth functions whose integral calculates the values of polynomials (#9138) Test case of the library suggested by Martin Hairer, see https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Hairer.20challenge/near/404836147. Co-authored-by: sgouezel Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Co-authored-by: Junyan Xu Co-authored-by: Floris van Doorn Co-authored-by: Johan Commelin --- Archive.lean | 1 + Archive/Hairer.lean | 135 +++++++++++++++++++++ Mathlib.lean | 1 + Mathlib/Analysis/Analytic/Polynomial.lean | 77 ++++++++++++ Mathlib/RingTheory/MvPolynomial/Basic.lean | 29 ++++- 5 files changed, 239 insertions(+), 4 deletions(-) create mode 100644 Archive/Hairer.lean create mode 100644 Mathlib/Analysis/Analytic/Polynomial.lean diff --git a/Archive.lean b/Archive.lean index e78b6b119b265..8e3ba11975e21 100644 --- a/Archive.lean +++ b/Archive.lean @@ -4,6 +4,7 @@ import Archive.Examples.IfNormalization.Statement import Archive.Examples.IfNormalization.WithoutAesop import Archive.Examples.MersennePrimes import Archive.Examples.PropEncodable +import Archive.Hairer import Archive.Imo.Imo1959Q1 import Archive.Imo.Imo1960Q1 import Archive.Imo.Imo1962Q1 diff --git a/Archive/Hairer.lean b/Archive/Hairer.lean new file mode 100644 index 0000000000000..1811011bedb08 --- /dev/null +++ b/Archive/Hairer.lean @@ -0,0 +1,135 @@ +/- +Copyright (c) 2023 Floris Van Doorn. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin, Sébastien Gouëzel, Patrick Massot, Ruben Van de Velde, Floris Van Doorn, +Junyan Xu +-/ +import Mathlib.Analysis.Distribution.AEEqOfIntegralContDiff +import Mathlib.RingTheory.MvPolynomial.Basic +import Mathlib.Analysis.Analytic.Polynomial +import Mathlib.Analysis.Analytic.Uniqueness +import Mathlib.Data.MvPolynomial.Funext + +/-! +# Smooth functions whose integral calculates the values of polynomials + +In any space `ℝᵈ` and given any `N`, we construct a smooth function supported in the unit ball +whose integral against a multivariate polynomial `P` of total degree at most `N` is `P 0`. + +This is a test of the state of the library suggested by Martin Hairer. +-/ + +noncomputable section + +open Metric Set MeasureTheory +open MvPolynomial hiding support +open Function hiding eval + +section normed +variable {𝕜 E F : Type*} [NontriviallyNormedField 𝕜] +variable [NormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedAddCommGroup F] [NormedSpace 𝕜 F] + +variable (𝕜 E F) in +/-- The set of smooth functions supported in a set `s`, as a submodule of the space of functions. -/ +def SmoothSupportedOn (n : ℕ∞) (s : Set E) : Submodule 𝕜 (E → F) where + carrier := { f : E → F | tsupport f ⊆ s ∧ ContDiff 𝕜 n f } + add_mem' hf hg := ⟨tsupport_add.trans <| union_subset hf.1 hg.1, hf.2.add hg.2⟩ + zero_mem' := + ⟨(tsupport_eq_empty_iff.mpr rfl).subset.trans (empty_subset _), contDiff_const (c := 0)⟩ + smul_mem' r f hf := + ⟨(closure_mono <| support_smul_subset_right r f).trans hf.1, contDiff_const.smul hf.2⟩ + +namespace SmoothSupportedOn + +variable {n : ℕ∞} {s : Set E} + +instance : FunLike (SmoothSupportedOn 𝕜 E F n s) E (fun _ ↦ F) where + coe := Subtype.val + coe_injective' := Subtype.coe_injective + +@[simp] +lemma coe_mk (f : E → F) (h) : (⟨f, h⟩ : SmoothSupportedOn 𝕜 E F n s) = f := rfl + +lemma tsupport_subset (f : SmoothSupportedOn 𝕜 E F n s) : tsupport f ⊆ s := f.2.1 + +lemma support_subset (f : SmoothSupportedOn 𝕜 E F n s) : + support f ⊆ s := subset_tsupport _ |>.trans (tsupport_subset f) + +lemma contDiff (f : SmoothSupportedOn 𝕜 E F n s) : + ContDiff 𝕜 n f := f.2.2 + +theorem continuous (f : SmoothSupportedOn 𝕜 E F n s) : Continuous f := + (SmoothSupportedOn.contDiff _).continuous + +lemma hasCompactSupport [ProperSpace E] (f : SmoothSupportedOn 𝕜 E F n (closedBall 0 1)) : + HasCompactSupport f := + HasCompactSupport.of_support_subset_isCompact (isCompact_closedBall 0 1) (support_subset f) + +end SmoothSupportedOn + +end normed +open SmoothSupportedOn + +instance {R σ : Type*} [CommSemiring R] [Finite σ] (N : ℕ) : + Module.Finite R (restrictTotalDegree σ R N) := + have : Finite {n : σ →₀ ℕ | ∀ i, n i ≤ N} := by + erw [Finsupp.equivFunOnFinite.subtypeEquivOfSubtype'.finite_iff, Set.finite_coe_iff] + convert Set.Finite.pi fun _ : σ ↦ Set.finite_le_nat N using 1 + ext; rw [mem_univ_pi]; rfl + have : Finite {s : σ →₀ ℕ | s.sum (fun _ e ↦ e) ≤ N} := by + rw [Set.finite_coe_iff] at this ⊢ + exact this.subset fun n hn i ↦ (eq_or_ne (n i) 0).elim + (fun h ↦ h.trans_le N.zero_le) fun h ↦ + (Finset.single_le_sum (fun _ _ ↦ Nat.zero_le _) <| Finsupp.mem_support_iff.mpr h).trans hn + Module.Finite.of_basis (basisRestrictSupport R _) + +variable {ι : Type*} +lemma MvPolynomial.continuous_eval (p : MvPolynomial ι ℝ) : + Continuous fun x ↦ (eval x) p := by + continuity + +variable [Fintype ι] +theorem SmoothSupportedOn.integrable_eval_mul (p : MvPolynomial ι ℝ) + (f : SmoothSupportedOn ℝ (EuclideanSpace ℝ ι) ℝ ⊤ (closedBall 0 1)) : + Integrable fun (x : EuclideanSpace ℝ ι) ↦ eval x p * f x := + (p.continuous_eval.mul (SmoothSupportedOn.contDiff f).continuous).integrable_of_hasCompactSupport + (hasCompactSupport f).mul_left + +variable (ι) +/-- Interpreting a multivariate polynomial as an element of the dual of smooth functions supported +in the unit ball, via integration against Lebesgue measure. -/ +def L : MvPolynomial ι ℝ →ₗ[ℝ] + Module.Dual ℝ (SmoothSupportedOn ℝ (EuclideanSpace ℝ ι) ℝ ⊤ (closedBall 0 1)) := + have int := SmoothSupportedOn.integrable_eval_mul (ι := ι) + .mk₂ ℝ (fun p f ↦ ∫ x : EuclideanSpace ℝ ι, eval x p • f x) + (fun p₁ p₂ f ↦ by simp [add_mul, integral_add (int p₁ f) (int p₂ f)]) + (fun r p f ↦ by simp [mul_assoc, integral_mul_left]) + (fun p f₁ f₂ ↦ by simp_rw [smul_eq_mul, ← integral_add (int p _) (int p _), ← mul_add]; rfl) + fun r p f ↦ by simp_rw [← integral_smul, smul_comm r]; rfl + +lemma inj_L : Injective (L ι) := + (injective_iff_map_eq_zero _).mpr fun p hp ↦ by + have H : ∀ᵐ x : EuclideanSpace ℝ ι, x ∈ ball 0 1 → eval x p = 0 := + isOpen_ball.ae_eq_zero_of_integral_contDiff_smul_eq_zero + (by exact continuous_eval p |>.locallyIntegrable.locallyIntegrableOn _) + fun g hg _h2g g_supp ↦ by + simpa [mul_comm (g _), L] using congr($hp ⟨g, g_supp.trans ball_subset_closedBall, hg⟩) + simp_rw [MvPolynomial.funext_iff, map_zero] + refine fun x ↦ AnalyticOn.eval_linearMap (EuclideanSpace.equiv ι ℝ).toLinearMap p + |>.eqOn_zero_of_preconnected_of_eventuallyEq_zero + (preconnectedSpace_iff_univ.mp inferInstance) (z₀ := 0) trivial + (Filter.mem_of_superset (Metric.ball_mem_nhds 0 zero_lt_one) ?_) trivial + rw [← ae_restrict_iff'₀ measurableSet_ball.nullMeasurableSet] at H + apply Measure.eqOn_of_ae_eq H p.continuous_eval.continuousOn continuousOn_const + rw [isOpen_ball.interior_eq] + apply subset_closure + +lemma hairer (N : ℕ) (ι : Type*) [Fintype ι] : + ∃ (ρ : EuclideanSpace ℝ ι → ℝ), tsupport ρ ⊆ closedBall 0 1 ∧ ContDiff ℝ ⊤ ρ ∧ + ∀ (p : MvPolynomial ι ℝ), p.totalDegree ≤ N → + ∫ x : EuclideanSpace ℝ ι, eval x p • ρ x = eval 0 p := by + have := (inj_L ι).comp (restrictTotalDegree ι ℝ N).injective_subtype + rw [← LinearMap.coe_comp] at this + obtain ⟨⟨φ, supφ, difφ⟩, hφ⟩ := + LinearMap.flip_surjective_iff₁.2 this ((aeval 0).toLinearMap.comp <| Submodule.subtype _) + exact ⟨φ, supφ, difφ, fun P hP ↦ congr($hφ ⟨P, (mem_restrictTotalDegree ι N P).mpr hP⟩)⟩ diff --git a/Mathlib.lean b/Mathlib.lean index 4ec03132fad86..805f2cd153727 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -560,6 +560,7 @@ import Mathlib.Analysis.Analytic.Constructions import Mathlib.Analysis.Analytic.Inverse import Mathlib.Analysis.Analytic.IsolatedZeros import Mathlib.Analysis.Analytic.Linear +import Mathlib.Analysis.Analytic.Polynomial import Mathlib.Analysis.Analytic.RadiusLiminf import Mathlib.Analysis.Analytic.Uniqueness import Mathlib.Analysis.Asymptotics.AsymptoticEquivalent diff --git a/Mathlib/Analysis/Analytic/Polynomial.lean b/Mathlib/Analysis/Analytic/Polynomial.lean new file mode 100644 index 0000000000000..668b4502d386d --- /dev/null +++ b/Mathlib/Analysis/Analytic/Polynomial.lean @@ -0,0 +1,77 @@ +/- +Copyright (c) 2023 Junyan Xu. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Junyan Xu +-/ +import Mathlib.Analysis.Analytic.Constructions +import Mathlib.Data.Polynomial.AlgebraMap +import Mathlib.Data.MvPolynomial.Basic +import Mathlib.Topology.Algebra.Module.FiniteDimension + +/-! +# Polynomials are analytic + +This file combines the analysis and algebra libraries and shows that evaluation of a polynomial +is an analytic function. +-/ + +variable {𝕜 E A B : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E] + [CommSemiring A] {z : E} {s : Set E} + +section Polynomial +open Polynomial + +variable [NormedRing B] [NormedAlgebra 𝕜 B] [Algebra A B] {f : E → B} + +theorem AnalyticAt.aeval_polynomial (hf : AnalyticAt 𝕜 f z) (p : A[X]) : + AnalyticAt 𝕜 (fun x ↦ aeval (f x) p) z := by + refine p.induction_on (fun k ↦ ?_) (fun p q hp hq ↦ ?_) fun p i hp ↦ ?_ + · simp_rw [aeval_C]; apply analyticAt_const + · simp_rw [aeval_add]; exact hp.add hq + · convert hp.mul hf + simp_rw [pow_succ', aeval_mul, ← mul_assoc, aeval_X] + +theorem AnalyticOn.aeval_polynomial (hf : AnalyticOn 𝕜 f s) (p : A[X]) : + AnalyticOn 𝕜 (fun x ↦ aeval (f x) p) s := fun x hx ↦ (hf x hx).aeval_polynomial p + +theorem AnalyticOn.eval_polynomial {A} [NormedCommRing A] [NormedAlgebra 𝕜 A] (p : A[X]) : + AnalyticOn 𝕜 (eval · p) Set.univ := (analyticOn_id 𝕜).aeval_polynomial p + +end Polynomial + +section MvPolynomial +open MvPolynomial + +variable [NormedCommRing B] [NormedAlgebra 𝕜 B] [Algebra A B] {σ : Type*} {f : E → σ → B} + +theorem AnalyticAt.aeval_mvPolynomial (hf : ∀ i, AnalyticAt 𝕜 (f · i) z) (p : MvPolynomial σ A) : + AnalyticAt 𝕜 (fun x ↦ aeval (f x) p) z := by + apply p.induction_on (fun k ↦ ?_) (fun p q hp hq ↦ ?_) fun p i hp ↦ ?_ -- `refine` doesn't work + · simp_rw [aeval_C]; apply analyticAt_const + · simp_rw [map_add]; exact hp.add hq + · simp_rw [map_mul, aeval_X]; exact hp.mul (hf i) + +theorem AnalyticOn.aeval_mvPolynomial (hf : ∀ i, AnalyticOn 𝕜 (f · i) s) (p : MvPolynomial σ A) : + AnalyticOn 𝕜 (fun x ↦ aeval (f x) p) s := fun x hx ↦ .aeval_mvPolynomial (hf · x hx) p + +theorem AnalyticOn.eval_continuousLinearMap (f : E →L[𝕜] σ → B) (p : MvPolynomial σ B) : + AnalyticOn 𝕜 (fun x ↦ eval (f x) p) Set.univ := + fun x _ ↦ .aeval_mvPolynomial (fun i ↦ ((ContinuousLinearMap.proj i).comp f).analyticAt x) p + +theorem AnalyticOn.eval_continuousLinearMap' (f : σ → E →L[𝕜] B) (p : MvPolynomial σ B) : + AnalyticOn 𝕜 (fun x ↦ eval (f · x) p) Set.univ := + fun x _ ↦ .aeval_mvPolynomial (fun i ↦ (f i).analyticAt x) p + +variable [CompleteSpace 𝕜] [T2Space E] [FiniteDimensional 𝕜 E] + +theorem AnalyticOn.eval_linearMap (f : E →ₗ[𝕜] σ → B) (p : MvPolynomial σ B) : + AnalyticOn 𝕜 (fun x ↦ eval (f x) p) Set.univ := + AnalyticOn.eval_continuousLinearMap { f with cont := f.continuous_of_finiteDimensional } p + +theorem AnalyticOn.eval_linearMap' (f : σ → E →ₗ[𝕜] B) (p : MvPolynomial σ B) : + AnalyticOn 𝕜 (fun x ↦ eval (f · x) p) Set.univ := AnalyticOn.eval_linearMap (.pi f) p + +theorem AnalyticOn.eval_mvPolynomial [Fintype σ] (p : MvPolynomial σ 𝕜) : + AnalyticOn 𝕜 (eval · p) Set.univ := AnalyticOn.eval_linearMap (.id (R := 𝕜) (M := σ → 𝕜)) p + +end MvPolynomial diff --git a/Mathlib/RingTheory/MvPolynomial/Basic.lean b/Mathlib/RingTheory/MvPolynomial/Basic.lean index d213a595a92bb..4cfef9d815be2 100644 --- a/Mathlib/RingTheory/MvPolynomial/Basic.lean +++ b/Mathlib/RingTheory/MvPolynomial/Basic.lean @@ -76,17 +76,38 @@ end Homomorphism section Degree +variable {σ} + +/-- The submodule of polynomials that are sum of monomials in the set `s`. -/ +def restrictSupport (s : Set (σ →₀ ℕ)) : Submodule R (MvPolynomial σ R) := + Finsupp.supported _ _ s + +/-- `restrictSupport R s` has a canonical `R`-basis indexed by `s`. -/ +def basisRestrictSupport (s : Set (σ →₀ ℕ)) : Basis s R (restrictSupport R s) where + repr := Finsupp.supportedEquivFinsupp s + +theorem restrictSupport_mono {s t : Set (σ →₀ ℕ)} (h : s ⊆ t) : + restrictSupport R s ≤ restrictSupport R t := Finsupp.supported_mono h + +variable (σ) + /-- The submodule of polynomials of total degree less than or equal to `m`.-/ -def restrictTotalDegree : Submodule R (MvPolynomial σ R) := - Finsupp.supported _ _ { n | (n.sum fun _ e => e) ≤ m } +def restrictTotalDegree (m : ℕ) : Submodule R (MvPolynomial σ R) := + restrictSupport R { n | (n.sum fun _ e => e) ≤ m } #align mv_polynomial.restrict_total_degree MvPolynomial.restrictTotalDegree /-- The submodule of polynomials such that the degree with respect to each individual variable is less than or equal to `m`.-/ def restrictDegree (m : ℕ) : Submodule R (MvPolynomial σ R) := - Finsupp.supported _ _ { n | ∀ i, n i ≤ m } + restrictSupport R { n | ∀ i, n i ≤ m } #align mv_polynomial.restrict_degree MvPolynomial.restrictDegree +theorem restrictTotalDegree_le_restrictDegree (m : ℕ) : + restrictTotalDegree σ R m ≤ restrictDegree σ R m := + restrictSupport_mono R fun n hn i ↦ (eq_or_ne (n i) 0).elim + (fun h ↦ h.trans_le m.zero_le) fun h ↦ + (Finset.single_le_sum (fun _ _ ↦ Nat.zero_le _) <| Finsupp.mem_support_iff.mpr h).trans hn + variable {R} theorem mem_restrictTotalDegree (p : MvPolynomial σ R) : @@ -97,7 +118,7 @@ theorem mem_restrictTotalDegree (p : MvPolynomial σ R) : theorem mem_restrictDegree (p : MvPolynomial σ R) (n : ℕ) : p ∈ restrictDegree σ R n ↔ ∀ s ∈ p.support, ∀ i, (s : σ →₀ ℕ) i ≤ n := by - rw [restrictDegree, Finsupp.mem_supported] + rw [restrictDegree, restrictSupport, Finsupp.mem_supported] rfl #align mv_polynomial.mem_restrict_degree MvPolynomial.mem_restrictDegree From ef1fdd15c5331933ac1c8155a39a32d9e9b7f1df Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Wed, 27 Dec 2023 14:00:26 -0500 Subject: [PATCH 257/353] chore: update ProofWidgets for lean4#3105 --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index 7218ee9100a9a..0348b0bdb165b 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -31,7 +31,7 @@ {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, - "rev": "bf61e90de075abfa27f638922e7aafafdce77c44", + "rev": "25eb33d3e327dea8f390d2e382dc4808cd6b74f7", "name": "proofwidgets", "manifestFile": "lake-manifest.json", "inputRev": "v0.0.24-pre2", From 71bf28895f20cab67354b414eadd645163983763 Mon Sep 17 00:00:00 2001 From: Alex Keizer Date: Wed, 27 Dec 2023 19:55:58 +0000 Subject: [PATCH 258/353] feat: add lemmas about `Fin.rev` (#8814) Co-authored-by: Yury G. Kudryashov Co-authored-by: Siddharth Bhat Co-authored-by: Tobias Grosser --- Mathlib/Data/Fin/Basic.lean | 14 ++++++ Mathlib/Data/Fin/Tuple/Basic.lean | 81 +++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/Mathlib/Data/Fin/Basic.lean b/Mathlib/Data/Fin/Basic.lean index a1d02bc80f803..c7f05f6268a35 100644 --- a/Mathlib/Data/Fin/Basic.lean +++ b/Mathlib/Data/Fin/Basic.lean @@ -347,6 +347,8 @@ theorem pos_iff_ne_zero' [NeZero n] (a : Fin n) : 0 < a ↔ a ≠ 0 := by #align fin.eq_zero_or_eq_succ Fin.eq_zero_or_eq_succ #align fin.eq_succ_of_ne_zero Fin.eq_succ_of_ne_zero +@[simp] lemma cast_eq_self (a : Fin n) : cast rfl a = a := rfl + theorem rev_involutive : Involutive (rev : Fin n → Fin n) := fun i => ext <| by dsimp only [rev] @@ -403,6 +405,10 @@ theorem revOrderIso_symm_apply (i : Fin n) : revOrderIso.symm i = OrderDual.toDu rfl #align fin.rev_order_iso_symm_apply Fin.revOrderIso_symm_apply +theorem cast_rev (i : Fin n) (h : n = m) : + cast h i.rev = (i.cast h).rev := by + subst h; simp + #align fin.last Fin.last #align fin.coe_last Fin.val_last @@ -1571,6 +1577,14 @@ theorem one_succAbove_one {n : ℕ} : (1 : Fin (n + 3)).succAbove 1 = 2 := by exact this #align fin.one_succ_above_one Fin.one_succAbove_one +lemma rev_succAbove (p : Fin (n + 1)) (i : Fin n) : + rev (succAbove p i) = succAbove (rev p) (rev i) := by + cases' lt_or_le (castSucc i) p with h h + · rw [succAbove_below _ _ h, rev_castSucc, succAbove_above] + rwa [← rev_succ, rev_le_rev] + · rw [succAbove_above _ _ h, rev_succ, succAbove_below] + rwa [← rev_succ, rev_lt_rev, lt_def, val_succ, Nat.lt_succ_iff] + end SuccAbove section PredAbove diff --git a/Mathlib/Data/Fin/Tuple/Basic.lean b/Mathlib/Data/Fin/Tuple/Basic.lean index 7a7b5d2de6ae5..fdf6c08e5b815 100644 --- a/Mathlib/Data/Fin/Tuple/Basic.lean +++ b/Mathlib/Data/Fin/Tuple/Basic.lean @@ -372,19 +372,24 @@ theorem cons_eq_append {α : Type*} (x : α) (xs : Fin n → α) : @[simp] lemma append_cast_left {n m} {α : Type*} (xs : Fin n → α) (ys : Fin m → α) (n' : ℕ) (h : n' = n) : Fin.append (xs ∘ Fin.cast h) ys = Fin.append xs ys ∘ (Fin.cast <| by rw [h]) := by - subst h - funext i - simp (config := {unfoldPartialApp := true}) only [Fin.append, Fin.addCases, comp_def, Fin.cast, - Fin.coe_castLT, Fin.subNat_mk, Fin.natAdd_mk, ge_iff_le, eq_rec_constant, Fin.eta, Eq.ndrec, - id_eq, eq_mpr_eq_cast, cast_eq] + subst h; simp @[simp] lemma append_cast_right {n m} {α : Type*} (xs : Fin n → α) (ys : Fin m → α) (m' : ℕ) (h : m' = m) : Fin.append xs (ys ∘ Fin.cast h) = Fin.append xs ys ∘ (Fin.cast <| by rw [h]) := by - subst h - funext i - simp only [append, addCases, cast, subNat_mk, natAdd_mk, Fin.eta, ge_iff_le, comp_apply, - eq_rec_constant] + subst h; simp + +lemma append_rev {m n} {α : Type*} (xs : Fin m → α) (ys : Fin n → α) (i : Fin (m + n)) : + append xs ys (rev i) = append (ys ∘ rev) (xs ∘ rev) (cast (add_comm _ _) i) := by + rcases rev_surjective i with ⟨i, rfl⟩ + rw [rev_rev] + induction i using Fin.addCases + · simp [rev_castAdd] + · simp [cast_rev, rev_addNat] + +lemma append_comp_rev {m n} {α : Type*} (xs : Fin m → α) (ys : Fin n → α) : + append xs ys ∘ rev = append (ys ∘ rev) (xs ∘ rev) ∘ cast (add_comm _ _) := + funext <| append_rev xs ys end Append @@ -439,6 +444,9 @@ theorem repeat_add {α : Type*} (a : Fin n → α) (m₁ m₂ : ℕ) : Fin.repea · simp [modNat, Nat.add_mod] #align fin.repeat_add Fin.repeat_add +proof_wanted repeat_comp_rev {α} (a : Fin n → α) : + (Fin.repeat m a) ∘ Fin.rev = Fin.repeat m (a ∘ Fin.rev) + end Repeat end Tuple @@ -658,6 +666,34 @@ theorem append_right_cons {n m} {α : Type*} (xs : Fin n → α) (y : α) (ys : Fin.append (Fin.snoc xs y) ys ∘ Fin.cast (Nat.succ_add_eq_add_succ ..).symm := by rw [append_left_snoc]; rfl +theorem append_cons {α} (a : α) (as : Fin n → α) (bs : Fin m → α) : + Fin.append (cons a as) bs + = cons a (Fin.append as bs) ∘ (Fin.cast <| Nat.add_right_comm n 1 m) := by + funext i + rcases i with ⟨i, -⟩ + simp only [append, addCases, cons, castLT, cast, comp_apply] + cases' i with i + · simp + · split_ifs with h + · have : i < n := Nat.lt_of_succ_lt_succ h + simp [addCases, this] + · have : ¬i < n := Nat.not_le.mpr <| Nat.lt_succ.mp <| Nat.not_le.mp h + simp [addCases, this] + +theorem append_snoc {α} (as : Fin n → α) (bs : Fin m → α) (b : α) : + Fin.append as (snoc bs b) = snoc (Fin.append as bs) b := by + funext i + rcases i with ⟨i, isLt⟩ + simp only [append, addCases, castLT, cast_mk, subNat_mk, natAdd_mk, cast, ge_iff_le, snoc._eq_1, + cast_eq, eq_rec_constant, Nat.add_eq, Nat.add_zero, castLT_mk] + split_ifs with lt_n lt_add sub_lt nlt_add lt_add <;> (try rfl) + · have := Nat.lt_add_right m lt_n + contradiction + · obtain rfl := Nat.eq_of_le_of_lt_succ (Nat.not_lt.mp nlt_add) isLt + simp [Nat.add_comm n m] at sub_lt + · have := Nat.sub_lt_left_of_lt_add (Nat.not_lt.mp lt_n) lt_add + contradiction + theorem comp_init {α : Type*} {β : Type*} (g : α → β) (q : Fin n.succ → α) : g ∘ init q = init (g ∘ q) := by ext j @@ -816,6 +852,33 @@ theorem insertNth_zero_right [∀ j, Zero (α j)] (i : Fin (n + 1)) (x : α i) : insertNth_eq_iff.2 <| by simp [succAbove_ne, Pi.zero_def] #align fin.insert_nth_zero_right Fin.insertNth_zero_right +lemma insertNth_rev {α : Type*} (i : Fin (n + 1)) (a : α) (f : Fin n → α) (j : Fin (n + 1)) : + insertNth (α := fun _ ↦ α) i a f (rev j) = insertNth (α := fun _ ↦ α) i.rev a (f ∘ rev) j := by + induction j using Fin.succAboveCases; exact rev i + · simp + · simp [rev_succAbove] + +theorem insertNth_comp_rev {α} (i : Fin (n + 1)) (x : α) (p : Fin n → α) : + (Fin.insertNth i x p) ∘ Fin.rev = Fin.insertNth (Fin.rev i) x (p ∘ Fin.rev) := by + funext x + apply insertNth_rev + +theorem cons_rev {α n} (a : α) (f : Fin n → α) (i : Fin <| n + 1) : + cons (α := fun _ => α) a f i.rev = snoc (α := fun _ => α) (f ∘ Fin.rev : Fin _ → α) a i := by + simpa using insertNth_rev 0 a f i + +theorem cons_comp_rev {α n} (a : α) (f : Fin n → α) : + Fin.cons a f ∘ Fin.rev = Fin.snoc (f ∘ Fin.rev) a := by + funext i; exact cons_rev .. + +theorem snoc_rev {α n} (a : α) (f : Fin n → α) (i : Fin <| n + 1) : + snoc (α := fun _ => α) f a i.rev = cons (α := fun _ => α) a (f ∘ Fin.rev : Fin _ → α) i := by + simpa using insertNth_rev (last n) a f i + +theorem snoc_comp_rev {α n} (a : α) (f : Fin n → α) : + Fin.snoc f a ∘ Fin.rev = Fin.cons a (f ∘ Fin.rev) := + funext <| snoc_rev a f + theorem insertNth_binop (op : ∀ j, α j → α j → α j) (i : Fin (n + 1)) (x y : α i) (p q : ∀ j, α (i.succAbove j)) : (i.insertNth (op i x y) fun j ↦ op _ (p j) (q j)) = fun j ↦ From 04a04880ab1565be6b6dcf3e1f9600e2a0b1f02e Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Wed, 27 Dec 2023 19:55:59 +0000 Subject: [PATCH 259/353] =?UTF-8?q?feat(LinearAlgebra):=20the=20Erd=C5=91s?= =?UTF-8?q?-Kaplansky=20theorem=20(#9159)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dimension of an infinite dimensional dual space is equal to its cardinality. As a consequence (`linearEquiv_dual_iff_finiteDimensional`), a vector space is isomorphic to its dual iff it's finite dimensional. The [main argument](https://github.com/leanprover-community/mathlib4/pull/9159/files#diff-cb173017e1157ddc4b9f868be06c18ec2a38f8cf82e856e18d59ed49f97395d8R146) is from https://mathoverflow.net/a/168624. There is a [slicker proof](https://mathoverflow.net/a/420455/3332) in the field case but Vandermonde determinants don't work in a non-commutative ring. Resolves [TODO item](https://leanprover-community.github.io/mathlib4_docs/Mathlib/LinearAlgebra/Dual.html#TODO) posed by Julian Külshammer - [x] depends on: #8941 - [x] depends on: #8942 Co-authored-by: Junyan Xu --- Mathlib/LinearAlgebra/Dimension.lean | 7 +- Mathlib/LinearAlgebra/Dual.lean | 16 ++- Mathlib/LinearAlgebra/FreeModule/Rank.lean | 132 +++++++++++++++++++++ 3 files changed, 149 insertions(+), 6 deletions(-) diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean index 700a622cc7a13..6b7927f9d8055 100644 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ b/Mathlib/LinearAlgebra/Dimension.lean @@ -108,6 +108,9 @@ protected irreducible_def Module.rank : Cardinal := ⨆ ι : { s : Set V // LinearIndependent K ((↑) : s → V) }, (#ι.1) #align module.rank Module.rank +theorem rank_le_card : Module.rank K V ≤ #V := + (Module.rank_def _ _).trans_le (ciSup_le' fun _ ↦ mk_set_le _) + lemma nonempty_linearIndependent_set : Nonempty {s : Set V // LinearIndependent K ((↑) : s → V)} := ⟨⟨∅, linearIndependent_empty _ _⟩⟩ @@ -1672,8 +1675,8 @@ theorem rank_finset_sum_le {η} (s : Finset η) (f : η → V →ₗ[K] V') : #align linear_map.rank_finset_sum_le LinearMap.rank_finset_sum_le theorem le_rank_iff_exists_linearIndependent {c : Cardinal} {f : V →ₗ[K] V'} : - c ≤ rank f ↔ ∃ s : Set V, Cardinal.lift.{v'} #s = - Cardinal.lift.{v} c ∧ LinearIndependent K fun x : s => f x := by + c ≤ rank f ↔ ∃ s : Set V, + Cardinal.lift.{v'} #s = Cardinal.lift.{v} c ∧ LinearIndependent K (fun x : s => f x) := by rcases f.rangeRestrict.exists_rightInverse_of_surjective f.range_rangeRestrict with ⟨g, hg⟩ have fg : LeftInverse f.rangeRestrict g := LinearMap.congr_fun hg refine' ⟨fun h => _, _⟩ diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 76c0fc9ca8db4..0753e9517e6c9 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -90,10 +90,6 @@ The dual space of an $R$-module $M$ is the $R$-module of $R$-linear maps $M \to * `Subspace.dualQuotDistrib W` is an equivalence `Dual K (V₁ ⧸ W) ≃ₗ[K] Dual K V₁ ⧸ W.dualLift.range` from an arbitrary choice of splitting of `V₁`. - -## TODO - -Erdős-Kaplansky theorem about the dimension of a dual vector space in case of infinite dimension. -/ noncomputable section @@ -408,6 +404,18 @@ theorem toDualEquiv_apply (m : M) : b.toDualEquiv m = b.toDual m := rfl #align basis.to_dual_equiv_apply Basis.toDualEquiv_apply +-- Not sure whether this is true for free modules over a commutative ring +/-- A vector space over a field is isomorphic to its dual if and only if it is finite-dimensional: + a consequence of the Erdős-Kaplansky theorem. -/ +theorem linearEquiv_dual_iff_finiteDimensional [Field K] [AddCommGroup V] [Module K V] : + Nonempty (V ≃ₗ[K] Dual K V) ↔ FiniteDimensional K V := by + refine ⟨fun ⟨e⟩ ↦ ?_, fun h ↦ ⟨(Module.Free.chooseBasis K V).toDualEquiv⟩⟩ + rw [FiniteDimensional, ← Module.rank_lt_alpeh0_iff] + by_contra! + apply (lift_rank_lt_rank_dual this).ne + have := e.lift_rank_eq + rwa [lift_umax.{uV,uK}, lift_id'.{uV,uK}] at this + /-- Maps a basis for `V` to a basis for the dual space. -/ def dualBasis : Basis ι R (Dual R M) := b.map b.toDualEquiv diff --git a/Mathlib/LinearAlgebra/FreeModule/Rank.lean b/Mathlib/LinearAlgebra/FreeModule/Rank.lean index 4746ac8209811..b7c2087e963eb 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Rank.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Rank.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ import Mathlib.LinearAlgebra.Dimension +import Mathlib.SetTheory.Cardinal.Subfield #align_import linear_algebra.free_module.rank from "leanprover-community/mathlib"@"465d4301d8da5945ef1dc1b29fb34c2f2b315ac4" @@ -13,6 +14,10 @@ import Mathlib.LinearAlgebra.Dimension This file contains some extra results not in `LinearAlgebra.Dimension`. +It also contains a proof of the Erdős-Kaplansky theorem (`rank_dual_eq_card_dual_of_aleph0_le_rank`) +which says that the dimension of an infinite-dimensional dual space over a division ring +has dimension equal to its cardinality. + -/ @@ -57,6 +62,19 @@ theorem rank_finsupp_self (ι : Type w) : Module.rank R (ι →₀ R) = Cardinal theorem rank_finsupp_self' {ι : Type u} : Module.rank R (ι →₀ R) = #ι := by simp #align rank_finsupp_self' rank_finsupp_self' +variable {R M} +theorem rank_eq_cardinal_basis {ι : Type w} (b : Basis ι R M) : + Cardinal.lift.{w} (Module.rank R M) = Cardinal.lift.{v} #ι := by + apply Cardinal.lift_injective.{u} + simp_rw [Cardinal.lift_lift] + have := b.repr.lift_rank_eq + rwa [rank_finsupp_self, Cardinal.lift_lift] at this + +theorem rank_eq_cardinal_basis' {ι : Type v} (b : Basis ι R M) : Module.rank R M = #ι := + Cardinal.lift_injective.{v} (rank_eq_cardinal_basis b) + +variable (R M) + /-- The rank of the direct sum is the sum of the ranks. -/ @[simp] theorem rank_directSum {ι : Type v} (M : ι → Type w) [∀ i : ι, AddCommGroup (M i)] @@ -123,3 +141,117 @@ theorem rank_tensorProduct' (N : Type v) [AddCommGroup N] [Module R N] [Module.F #align rank_tensor_product' rank_tensorProduct' end CommRing + +section DivisionRing + +variable (K : Type u) [DivisionRing K] + +/-- Key lemma towards the Erdős-Kaplansky theorem from https://mathoverflow.net/a/168624 -/ +theorem max_aleph0_card_le_rank_fun_nat : max ℵ₀ #K ≤ Module.rank K (ℕ → K) := by + have aleph0_le : ℵ₀ ≤ Module.rank K (ℕ → K) := (rank_finsupp_self K ℕ).symm.trans_le + (Finsupp.lcoeFun.rank_le_of_injective <| by exact FunLike.coe_injective) + refine max_le aleph0_le ?_ + obtain card_K | card_K := le_or_lt #K ℵ₀ + · exact card_K.trans aleph0_le + by_contra! + obtain ⟨⟨ιK, bK⟩⟩ := Module.Free.exists_basis (R := K) (M := ℕ → K) + let L := Subfield.closure (Set.range (fun i : ιK × ℕ ↦ bK i.1 i.2)) + have hLK : #L < #K + · refine (Subfield.cardinal_mk_closure_le_max _).trans_lt + (max_lt_iff.mpr ⟨mk_range_le.trans_lt ?_, card_K⟩) + rwa [mk_prod, ← aleph0, lift_uzero, ← rank_eq_cardinal_basis' bK, mul_aleph0_eq aleph0_le] + letI := Module.compHom K (RingHom.op L.subtype) + obtain ⟨⟨ιL, bL⟩⟩ := Module.Free.exists_basis (R := Lᵐᵒᵖ) (M := K) + have card_ιL : ℵ₀ ≤ #ιL + · contrapose! hLK + haveI := @Fintype.ofFinite _ (lt_aleph0_iff_finite.mp hLK) + rw [bL.repr.toEquiv.cardinal_eq, mk_finsupp_of_fintype, + ← MulOpposite.opEquiv.cardinal_eq] at card_K ⊢ + apply power_nat_le + contrapose! card_K + exact (power_lt_aleph0 card_K <| nat_lt_aleph0 _).le + obtain ⟨e⟩ := lift_mk_le'.mp (card_ιL.trans_eq (lift_uzero #ιL).symm) + have rep_e := bK.total_repr (bL ∘ e) + rw [Finsupp.total_apply, Finsupp.sum] at rep_e + set c := bK.repr (bL ∘ e) + set s := c.support + let f i (j : s) : L := ⟨bK j i, Subfield.subset_closure ⟨(j, i), rfl⟩⟩ + have : ¬LinearIndependent Lᵐᵒᵖ f := fun h ↦ by + have := h.cardinal_lift_le_rank + rw [lift_uzero, (LinearEquiv.piCongrRight fun _ ↦ MulOpposite.opLinearEquiv Lᵐᵒᵖ).rank_eq, + rank_fun'] at this + exact (nat_lt_aleph0 _).not_le this + obtain ⟨t, g, eq0, i, hi, hgi⟩ := not_linearIndependent_iff.mp this + refine hgi (linearIndependent_iff'.mp (bL.linearIndependent.comp e e.injective) t g ?_ i hi) + clear_value c s + simp_rw [← rep_e, Finset.sum_apply, Pi.smul_apply, Finset.smul_sum] + rw [Finset.sum_comm] + refine Finset.sum_eq_zero fun i hi ↦ ?_ + replace eq0 := congr_arg L.subtype (congr_fun eq0 ⟨i, hi⟩) + rw [Finset.sum_apply, map_sum] at eq0 + have : SMulCommClass Lᵐᵒᵖ K K := ⟨fun _ _ _ ↦ mul_assoc _ _ _⟩ + simp_rw [smul_comm _ (c i), ← Finset.smul_sum] + erw [eq0, smul_zero] + +variable {K} + +open Function in +theorem rank_fun_infinite {ι : Type v} [hι : Infinite ι] : Module.rank K (ι → K) = #(ι → K) := by + obtain ⟨⟨ιK, bK⟩⟩ := Module.Free.exists_basis (R := K) (M := ι → K) + obtain ⟨e⟩ := lift_mk_le'.mp ((aleph0_le_mk_iff.mpr hι).trans_eq (lift_uzero #ι).symm) + have := LinearMap.lift_rank_le_of_injective _ <| + LinearMap.funLeft_injective_of_surjective K K _ (invFun_surjective e.injective) + rw [lift_umax.{u,v}, lift_id'.{u,v}] at this + have key := (lift_le.{v}.mpr <| max_aleph0_card_le_rank_fun_nat K).trans this + rw [lift_max, lift_aleph0, max_le_iff] at key + haveI : Infinite ιK := by + rw [← aleph0_le_mk_iff, ← rank_eq_cardinal_basis' bK]; exact key.1 + rw [bK.repr.toEquiv.cardinal_eq, mk_finsupp_lift_of_infinite, + lift_umax.{u,v}, lift_id'.{u,v}, ← rank_eq_cardinal_basis' bK, eq_comm, max_eq_left] + exact key.2 + +/-- The **Erdős-Kaplansky Theorem**: the dual of an infinite-dimensional vector space + over a division ring has dimension equal to its cardinality. -/ +theorem rank_dual_eq_card_dual_of_aleph0_le_rank' {V : Type*} [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : Module.rank Kᵐᵒᵖ (V →ₗ[K] K) = #(V →ₗ[K] K) := by + obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) + rw [rank_eq_cardinal_basis' b, aleph0_le_mk_iff] at h + have e := (b.constr Kᵐᵒᵖ (M' := K)).symm.trans + (LinearEquiv.piCongrRight fun _ ↦ MulOpposite.opLinearEquiv Kᵐᵒᵖ) + rw [e.rank_eq, e.toEquiv.cardinal_eq] + apply rank_fun_infinite + +/-- The **Erdős-Kaplansky Theorem** over a field. -/ +theorem rank_dual_eq_card_dual_of_aleph0_le_rank {K V} [Field K] [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : Module.rank K (V →ₗ[K] K) = #(V →ₗ[K] K) := by + obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) + rw [rank_eq_cardinal_basis' b, aleph0_le_mk_iff] at h + have e := (b.constr K (M' := K)).symm + rw [e.rank_eq, e.toEquiv.cardinal_eq] + apply rank_fun_infinite + +theorem lift_rank_lt_rank_dual' {V : Type v} [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : + Cardinal.lift.{u} (Module.rank K V) < Module.rank Kᵐᵒᵖ (V →ₗ[K] K) := by + obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) + rw [rank_eq_cardinal_basis' b, rank_dual_eq_card_dual_of_aleph0_le_rank' h, + ← (b.constr ℕ (M' := K)).toEquiv.cardinal_eq, mk_arrow] + apply cantor' + erw [nat_lt_lift_iff, one_lt_iff_nontrivial] + infer_instance + +theorem lift_rank_lt_rank_dual {K : Type u} {V : Type v} [Field K] [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : + Cardinal.lift.{u} (Module.rank K V) < Module.rank K (V →ₗ[K] K) := by + rw [rank_dual_eq_card_dual_of_aleph0_le_rank h, ← rank_dual_eq_card_dual_of_aleph0_le_rank' h] + exact lift_rank_lt_rank_dual' h + +theorem rank_lt_rank_dual' {V : Type u} [AddCommGroup V] [Module K V] (h : ℵ₀ ≤ Module.rank K V) : + Module.rank K V < Module.rank Kᵐᵒᵖ (V →ₗ[K] K) := by + convert lift_rank_lt_rank_dual' h; rw [lift_id] + +theorem rank_lt_rank_dual {K V : Type u} [Field K] [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : Module.rank K V < Module.rank K (V →ₗ[K] K) := by + convert lift_rank_lt_rank_dual h; rw [lift_id] + +end DivisionRing From d2d0dcdfe131b20dbd6a80e7ac6c8da622614b63 Mon Sep 17 00:00:00 2001 From: Thomas Zhu Date: Wed, 27 Dec 2023 19:56:00 +0000 Subject: [PATCH 260/353] chore(NumberTheory/Zsqrtd): use `@[ext]` (#9299) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added `@[ext]` to definition `structure Zsqrtd (d : ℤ)`. (also added lemma `sub_re`, `sub_im`) --- Mathlib/NumberTheory/Pell.lean | 4 +- Mathlib/NumberTheory/PellMatiyasevic.lean | 8 +- Mathlib/NumberTheory/Zsqrtd/Basic.lean | 73 ++++++++++--------- .../Zsqrtd/QuadraticReciprocity.lean | 4 +- 4 files changed, 44 insertions(+), 45 deletions(-) diff --git a/Mathlib/NumberTheory/Pell.lean b/Mathlib/NumberTheory/Pell.lean index aa5e779fbb3f7..27547e658e72c 100644 --- a/Mathlib/NumberTheory/Pell.lean +++ b/Mathlib/NumberTheory/Pell.lean @@ -140,7 +140,7 @@ theorem prop_y (a : Solution₁ d) : d * a.y ^ 2 = a.x ^ 2 - 1 := by rw [← a.p /-- Two solutions are equal if their `x` and `y` components are equal. -/ @[ext] theorem ext {a b : Solution₁ d} (hx : a.x = b.x) (hy : a.y = b.y) : a = b := - Subtype.ext <| ext.mpr ⟨hx, hy⟩ + Subtype.ext <| Zsqrtd.ext _ _ hx hy #align pell.solution₁.ext Pell.Solution₁.ext /-- Construct a solution from `x`, `y` and a proof that the equation is satisfied. -/ @@ -161,7 +161,7 @@ theorem y_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (mk x y prop).y = y := @[simp] theorem coe_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (↑(mk x y prop) : ℤ√d) = ⟨x, y⟩ := - Zsqrtd.ext.mpr ⟨x_mk x y prop, y_mk x y prop⟩ + Zsqrtd.ext _ _ (x_mk x y prop) (y_mk x y prop) #align pell.solution₁.coe_mk Pell.Solution₁.coe_mk @[simp] diff --git a/Mathlib/NumberTheory/PellMatiyasevic.lean b/Mathlib/NumberTheory/PellMatiyasevic.lean index 3f6f612f68240..bbb4b2542dba6 100644 --- a/Mathlib/NumberTheory/PellMatiyasevic.lean +++ b/Mathlib/NumberTheory/PellMatiyasevic.lean @@ -67,7 +67,7 @@ def IsPell : ℤ√d → Prop #align pell.is_pell Pell.IsPell theorem isPell_norm : ∀ {b : ℤ√d}, IsPell b ↔ b * star b = 1 - | ⟨x, y⟩ => by simp [Zsqrtd.ext, IsPell, mul_comm]; ring_nf + | ⟨x, y⟩ => by simp [Zsqrtd.ext_iff, IsPell, mul_comm]; ring_nf #align pell.is_pell_norm Pell.isPell_norm theorem isPell_iff_mem_unitary : ∀ {b : ℤ√d}, IsPell b ↔ b ∈ unitary (ℤ√d) @@ -217,7 +217,7 @@ theorem isPell_nat {x y : ℕ} : IsPell (⟨x, y⟩ : ℤ√(d a1)) ↔ x * x - #align pell.is_pell_nat Pell.isPell_nat @[simp] -theorem pellZd_succ (n : ℕ) : pellZd a1 (n + 1) = pellZd a1 n * ⟨a, 1⟩ := by simp [Zsqrtd.ext] +theorem pellZd_succ (n : ℕ) : pellZd a1 (n + 1) = pellZd a1 n * ⟨a, 1⟩ := by ext <;> simp #align pell.pell_zd_succ Pell.pellZd_succ theorem isPell_one : IsPell (⟨a, 1⟩ : ℤ√(d a1)) := @@ -511,9 +511,7 @@ theorem pellZd_succ_succ (n) : change (⟨_, _⟩ : ℤ√(d a1)) = ⟨_, _⟩ rw [dz_val] dsimp [az] - rw [Zsqrtd.ext] - dsimp - constructor <;> ring_nf + ext <;> dsimp <;> ring_nf simpa [mul_add, mul_comm, mul_left_comm, add_comm] using congr_arg (· * pellZd a1 n) this #align pell.pell_zd_succ_succ Pell.pellZd_succ_succ diff --git a/Mathlib/NumberTheory/Zsqrtd/Basic.lean b/Mathlib/NumberTheory/Zsqrtd/Basic.lean index 69c8b81c2e5d1..fd014b2ec79b4 100644 --- a/Mathlib/NumberTheory/Zsqrtd/Basic.lean +++ b/Mathlib/NumberTheory/Zsqrtd/Basic.lean @@ -26,11 +26,13 @@ to choices of square roots of `d` in `R`. /-- The ring of integers adjoined with a square root of `d`. These have the form `a + b √d` where `a b : ℤ`. The components are called `re` and `im` by analogy to the negative `d` case. -/ +@[ext] structure Zsqrtd (d : ℤ) where re : ℤ im : ℤ deriving DecidableEq #align zsqrtd Zsqrtd +#align zsqrtd.ext Zsqrtd.ext_iff prefix:100 "ℤ√" => Zsqrtd @@ -40,12 +42,6 @@ section variable {d : ℤ} -theorem ext : ∀ {z w : ℤ√d}, z = w ↔ z.re = w.re ∧ z.im = w.im - | ⟨x, y⟩, ⟨x', y'⟩ => - ⟨fun h => by injection h; constructor <;> assumption, - fun ⟨h₁, h₂⟩ => by congr⟩ -#align zsqrtd.ext Zsqrtd.ext - /-- Convert an integer to a `ℤ√d` -/ def ofInt (n : ℤ) : ℤ√d := ⟨n, 0⟩ @@ -190,7 +186,16 @@ instance addCommGroup : AddCommGroup (ℤ√d) := by add_left_neg := ?_ add_comm := ?_ } <;> intros <;> - simp [ext, add_comm, add_left_comm] + ext <;> + simp [add_comm, add_left_comm] + +@[simp] +theorem sub_re (z w : ℤ√d) : (z - w).re = z.re - w.re := + rfl + +@[simp] +theorem sub_im (z w : ℤ√d) : (z - w).im = z.im - w.im := + rfl instance addGroupWithOne : AddGroupWithOne (ℤ√d) := { Zsqrtd.addCommGroup with @@ -213,7 +218,7 @@ instance commRing : CommRing (ℤ√d) := by mul_one := ?_ mul_comm := ?_ } <;> intros <;> - refine ext.mpr ⟨?_, ?_⟩ <;> + ext <;> simp <;> ring @@ -259,13 +264,13 @@ theorem star_im (z : ℤ√d) : (star z).im = -z.im := #align zsqrtd.star_im Zsqrtd.star_im instance : StarRing (ℤ√d) where - star_involutive x := ext.mpr ⟨rfl, neg_neg _⟩ - star_mul a b := ext.mpr ⟨by simp; ring, by simp; ring⟩ - star_add a b := ext.mpr ⟨rfl, neg_add _ _⟩ + star_involutive x := Zsqrtd.ext _ _ rfl (neg_neg _) + star_mul a b := by ext <;> simp <;> ring + star_add a b := Zsqrtd.ext _ _ rfl (neg_add _ _) -- Porting note: proof was `by decide` instance nontrivial : Nontrivial (ℤ√d) := - ⟨⟨0, 1, ext.not.mpr <| by simp⟩⟩ + ⟨⟨0, 1, (Zsqrtd.ext_iff 0 1).not.mpr (by simp)⟩⟩ @[simp] theorem coe_nat_re (n : ℕ) : (n : ℤ√d).re = n := @@ -297,17 +302,17 @@ theorem coe_int_re (n : ℤ) : (n : ℤ√d).re = n := by cases n <;> rfl theorem coe_int_im (n : ℤ) : (n : ℤ√d).im = 0 := by cases n <;> rfl #align zsqrtd.coe_int_im Zsqrtd.coe_int_im -theorem coe_int_val (n : ℤ) : (n : ℤ√d) = ⟨n, 0⟩ := by simp [ext] +theorem coe_int_val (n : ℤ) : (n : ℤ√d) = ⟨n, 0⟩ := by ext <;> simp #align zsqrtd.coe_int_val Zsqrtd.coe_int_val -instance : CharZero (ℤ√d) where cast_injective m n := by simp [ext] +instance : CharZero (ℤ√d) where cast_injective m n := by simp [Zsqrtd.ext_iff] @[simp] -theorem ofInt_eq_coe (n : ℤ) : (ofInt n : ℤ√d) = n := by simp [ext, ofInt_re, ofInt_im] +theorem ofInt_eq_coe (n : ℤ) : (ofInt n : ℤ√d) = n := by ext <;> simp [ofInt_re, ofInt_im] #align zsqrtd.of_int_eq_coe Zsqrtd.ofInt_eq_coe @[simp] -theorem smul_val (n x y : ℤ) : (n : ℤ√d) * ⟨x, y⟩ = ⟨n * x, n * y⟩ := by simp [ext] +theorem smul_val (n x y : ℤ) : (n : ℤ√d) * ⟨x, y⟩ = ⟨n * x, n * y⟩ := by ext <;> simp #align zsqrtd.smul_val Zsqrtd.smul_val theorem smul_re (a : ℤ) (b : ℤ√d) : (↑a * b).re = a * b.re := by simp @@ -317,34 +322,34 @@ theorem smul_im (a : ℤ) (b : ℤ√d) : (↑a * b).im = a * b.im := by simp #align zsqrtd.smul_im Zsqrtd.smul_im @[simp] -theorem muld_val (x y : ℤ) : sqrtd (d := d) * ⟨x, y⟩ = ⟨d * y, x⟩ := by simp [ext] +theorem muld_val (x y : ℤ) : sqrtd (d := d) * ⟨x, y⟩ = ⟨d * y, x⟩ := by ext <;> simp #align zsqrtd.muld_val Zsqrtd.muld_val @[simp] -theorem dmuld : sqrtd (d := d) * sqrtd (d := d) = d := by simp [ext] +theorem dmuld : sqrtd (d := d) * sqrtd (d := d) = d := by ext <;> simp #align zsqrtd.dmuld Zsqrtd.dmuld @[simp] -theorem smuld_val (n x y : ℤ) : sqrtd * (n : ℤ√d) * ⟨x, y⟩ = ⟨d * n * y, n * x⟩ := by simp [ext] +theorem smuld_val (n x y : ℤ) : sqrtd * (n : ℤ√d) * ⟨x, y⟩ = ⟨d * n * y, n * x⟩ := by ext <;> simp #align zsqrtd.smuld_val Zsqrtd.smuld_val -theorem decompose {x y : ℤ} : (⟨x, y⟩ : ℤ√d) = x + sqrtd (d := d) * y := by simp [ext] +theorem decompose {x y : ℤ} : (⟨x, y⟩ : ℤ√d) = x + sqrtd (d := d) * y := by ext <;> simp #align zsqrtd.decompose Zsqrtd.decompose theorem mul_star {x y : ℤ} : (⟨x, y⟩ * star ⟨x, y⟩ : ℤ√d) = x * x - d * y * y := by - simp [ext, sub_eq_add_neg, mul_comm] + ext <;> simp [sub_eq_add_neg, mul_comm] #align zsqrtd.mul_star Zsqrtd.mul_star protected theorem coe_int_add (m n : ℤ) : (↑(m + n) : ℤ√d) = ↑m + ↑n := - (Int.castRingHom _).map_add _ _ + Int.cast_add m n #align zsqrtd.coe_int_add Zsqrtd.coe_int_add protected theorem coe_int_sub (m n : ℤ) : (↑(m - n) : ℤ√d) = ↑m - ↑n := - (Int.castRingHom _).map_sub _ _ + Int.cast_sub m n #align zsqrtd.coe_int_sub Zsqrtd.coe_int_sub protected theorem coe_int_mul (m n : ℤ) : (↑(m * n) : ℤ√d) = ↑m * ↑n := - (Int.castRingHom _).map_mul _ _ + Int.cast_mul m n #align zsqrtd.coe_int_mul Zsqrtd.coe_int_mul protected theorem coe_int_inj {m n : ℤ} (h : (↑m : ℤ√d) = ↑n) : m = n := by @@ -358,7 +363,7 @@ theorem coe_int_dvd_iff (z : ℤ) (a : ℤ√d) : ↑z ∣ a ↔ z ∣ a.re ∧ mul_re, mul_zero, coe_int_im] · rintro ⟨⟨r, hr⟩, ⟨i, hi⟩⟩ use ⟨r, i⟩ - rw [smul_val, ext] + rw [smul_val, Zsqrtd.ext_iff] exact ⟨hr, hi⟩ #align zsqrtd.coe_int_dvd_iff Zsqrtd.coe_int_dvd_iff @@ -374,14 +379,14 @@ theorem coe_int_dvd_coe_int (a b : ℤ) : (a : ℤ√d) ∣ b ↔ a ∣ b := by protected theorem eq_of_smul_eq_smul_left {a : ℤ} {b c : ℤ√d} (ha : a ≠ 0) (h : ↑a * b = a * c) : b = c := by - rw [ext] at h ⊢ + rw [Zsqrtd.ext_iff] at h ⊢ apply And.imp _ _ h <;> simpa only [smul_re, smul_im] using mul_left_cancel₀ ha #align zsqrtd.eq_of_smul_eq_smul_left Zsqrtd.eq_of_smul_eq_smul_left section Gcd theorem gcd_eq_zero_iff (a : ℤ√d) : Int.gcd a.re a.im = 0 ↔ a = 0 := by - simp only [Int.gcd_eq_zero_iff, ext, eq_self_iff_true, zero_im, zero_re] + simp only [Int.gcd_eq_zero_iff, Zsqrtd.ext_iff, eq_self_iff_true, zero_im, zero_re] #align zsqrtd.gcd_eq_zero_iff Zsqrtd.gcd_eq_zero_iff theorem gcd_pos_iff (a : ℤ√d) : 0 < Int.gcd a.re a.im ↔ a ≠ 0 := @@ -392,8 +397,7 @@ theorem coprime_of_dvd_coprime {a b : ℤ√d} (hcoprime : IsCoprime a.re a.im) IsCoprime b.re b.im := by apply isCoprime_of_dvd · rintro ⟨hre, him⟩ - obtain rfl : b = 0 := by - simp only [ext, hre, eq_self_iff_true, zero_im, him, and_self_iff, zero_re] + obtain rfl : b = 0 := Zsqrtd.ext b 0 hre him rw [zero_dvd_iff] at hdvd simp [hdvd, zero_im, zero_re, not_isCoprime_zero_zero] at hcoprime · rintro z hz - hzdvdu hzdvdv @@ -411,8 +415,7 @@ theorem exists_coprime_of_gcd_pos {a : ℤ√d} (hgcd : 0 < Int.gcd a.re a.im) : obtain ⟨re, im, H1, Hre, Him⟩ := Int.exists_gcd_one hgcd rw [mul_comm] at Hre Him refine' ⟨⟨re, im⟩, _, _⟩ - · rw [smul_val, ext, ← Hre, ← Him] - constructor <;> rfl + · rw [smul_val, ← Hre, ← Him] · rw [← Int.gcd_eq_one_iff_coprime, H1] #align zsqrtd.exists_coprime_of_gcd_pos Zsqrtd.exists_coprime_of_gcd_pos @@ -551,8 +554,7 @@ def normMonoidHom : ℤ√d →* ℤ where #align zsqrtd.norm_monoid_hom Zsqrtd.normMonoidHom theorem norm_eq_mul_conj (n : ℤ√d) : (norm n : ℤ√d) = n * star n := by - cases n - simp [norm, star, Zsqrtd.ext, mul_comm, sub_eq_add_neg] + ext <;> simp [norm, star, mul_comm, sub_eq_add_neg] #align zsqrtd.norm_eq_mul_conj Zsqrtd.norm_eq_mul_conj @[simp] @@ -607,12 +609,11 @@ theorem norm_eq_one_iff' {d : ℤ} (hd : d ≤ 0) (z : ℤ√d) : z.norm = 1 ↔ theorem norm_eq_zero_iff {d : ℤ} (hd : d < 0) (z : ℤ√d) : z.norm = 0 ↔ z = 0 := by constructor · intro h - rw [ext, zero_re, zero_im] rw [norm_def, sub_eq_add_neg, mul_assoc] at h have left := mul_self_nonneg z.re have right := neg_nonneg.mpr (mul_nonpos_of_nonpos_of_nonneg hd.le (mul_self_nonneg z.im)) obtain ⟨ha, hb⟩ := (add_eq_zero_iff' left right).mp h - constructor <;> apply eq_zero_of_mul_self_eq_zero + ext <;> apply eq_zero_of_mul_self_eq_zero · exact ha · rw [neg_eq_zero, mul_eq_zero] at hb exact hb.resolve_left hd.ne @@ -1005,7 +1006,7 @@ instance : OrderedRing (ℤ√d) := by infer_instance end theorem norm_eq_zero {d : ℤ} (h_nonsquare : ∀ n : ℤ, d ≠ n * n) (a : ℤ√d) : norm a = 0 ↔ a = 0 := by - refine' ⟨fun ha => ext.mpr _, fun h => by rw [h, norm_zero]⟩ + refine' ⟨fun ha => (Zsqrtd.ext_iff _ _).mpr _, fun h => by rw [h, norm_zero]⟩ dsimp only [norm] at ha rw [sub_eq_zero] at ha by_cases h : 0 ≤ d diff --git a/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean b/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean index 403f40dba084b..942d1502dad18 100644 --- a/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean +++ b/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean @@ -46,13 +46,13 @@ theorem mod_four_eq_three_of_nat_prime_of_prime (p : ℕ) [hp : Fact p.Prime] revert this hp3 hp1 generalize p % 4 = m intros; interval_cases m <;> simp_all -- Porting note: was `decide!` - let ⟨k, hk⟩ := (ZMod.exists_sq_eq_neg_one_iff (p := p)).2 <| by rw [hp41]; exact by decide + let ⟨k, hk⟩ := (ZMod.exists_sq_eq_neg_one_iff (p := p)).2 <| by rw [hp41]; decide obtain ⟨k, k_lt_p, rfl⟩ : ∃ (k' : ℕ) (_ : k' < p), (k' : ZMod p) = k := by refine' ⟨k.val, k.val_lt, ZMod.nat_cast_zmod_val k⟩ have hpk : p ∣ k ^ 2 + 1 := by rw [pow_two, ← CharP.cast_eq_zero_iff (ZMod p) p, Nat.cast_add, Nat.cast_mul, Nat.cast_one, ← hk, add_left_neg] - have hkmul : (k ^ 2 + 1 : ℤ[i]) = ⟨k, 1⟩ * ⟨k, -1⟩ := by simp [sq, Zsqrtd.ext] + have hkmul : (k ^ 2 + 1 : ℤ[i]) = ⟨k, 1⟩ * ⟨k, -1⟩ := by ext <;> simp [sq] have hkltp : 1 + k * k < p * p := calc 1 + k * k ≤ k + k * k := by From 7b59a5fa0da20633c93e76b2da3a1b4d32dc704a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 27 Dec 2023 20:59:07 +0000 Subject: [PATCH 261/353] =?UTF-8?q?feat:=20`(a=20=E2=80=A2=20s)=E2=81=BB?= =?UTF-8?q?=C2=B9=20=3D=20s=E2=81=BB=C2=B9=20=E2=80=A2=20a=E2=81=BB=C2=B9`?= =?UTF-8?q?=20(#9199)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and other simple pointwise lemmas for `Set` and `Finset`. Also add supporting `Fintype.piFinset` lemmas and fix the names of two lemmas. From LeanAPAP and LeanCamCombi --- Mathlib/Algebra/Opposites.lean | 3 + .../InnerProductSpace/GramSchmidtOrtho.lean | 2 +- Mathlib/Data/Finset/NAry.lean | 12 + Mathlib/Data/Finset/Pi.lean | 5 +- Mathlib/Data/Finset/Pointwise.lean | 220 ++++++++++++------ Mathlib/Data/Fintype/Pi.lean | 26 ++- Mathlib/Data/Set/Pointwise/Basic.lean | 9 +- Mathlib/Data/Set/Pointwise/SMul.lean | 22 +- 8 files changed, 225 insertions(+), 74 deletions(-) diff --git a/Mathlib/Algebra/Opposites.lean b/Mathlib/Algebra/Opposites.lean index c3edb226a06ae..20757a0240041 100644 --- a/Mathlib/Algebra/Opposites.lean +++ b/Mathlib/Algebra/Opposites.lean @@ -205,6 +205,9 @@ instance unique [Unique α] : Unique αᵐᵒᵖ := instance isEmpty [IsEmpty α] : IsEmpty αᵐᵒᵖ := Function.isEmpty unop +@[to_additive] +instance instDecidableEq [DecidableEq α] : DecidableEq αᵐᵒᵖ := unop_injective.decidableEq + instance zero [Zero α] : Zero αᵐᵒᵖ where zero := op 0 @[to_additive] diff --git a/Mathlib/Analysis/InnerProductSpace/GramSchmidtOrtho.lean b/Mathlib/Analysis/InnerProductSpace/GramSchmidtOrtho.lean index fd4603f6783b3..2d46c65438741 100644 --- a/Mathlib/Analysis/InnerProductSpace/GramSchmidtOrtho.lean +++ b/Mathlib/Analysis/InnerProductSpace/GramSchmidtOrtho.lean @@ -186,7 +186,7 @@ theorem gramSchmidt_of_orthogonal {f : ι → E} (hf : Pairwise fun i j => ⟪f · congr apply Finset.sum_eq_zero intro j hj - rw [coe_eq_zero] + rw [Submodule.coe_eq_zero] suffices span 𝕜 (f '' Set.Iic j) ⟂ 𝕜 ∙ f i by apply orthogonalProjection_mem_subspace_orthogonalComplement_eq_zero rw [mem_orthogonal_singleton_iff_inner_left] diff --git a/Mathlib/Data/Finset/NAry.lean b/Mathlib/Data/Finset/NAry.lean index d631dcb51a2d0..b6af4b1c54a4b 100644 --- a/Mathlib/Data/Finset/NAry.lean +++ b/Mathlib/Data/Finset/NAry.lean @@ -572,6 +572,18 @@ theorem image₂_union_inter_subset {f : α → α → β} {s t : Finset α} (hf end Finset +open Finset + +namespace Fintype +variable {ι : Type*} {α β γ : ι → Type*} [DecidableEq ι] [Fintype ι] [∀ i, DecidableEq (γ i)] + +lemma piFinset_image₂ (f : ∀ i, α i → β i → γ i) (s : ∀ i, Finset (α i)) (t : ∀ i, Finset (β i)) : + piFinset (fun i ↦ image₂ (f i) (s i) (t i)) = + image₂ (fun a b i ↦ f _ (a i) (b i)) (piFinset s) (piFinset t) := by + ext; simp only [mem_piFinset, mem_image₂, Classical.skolem, forall_and, Function.funext_iff] + +end Fintype + namespace Set variable [DecidableEq γ] {s : Set α} {t : Set β} diff --git a/Mathlib/Data/Finset/Pi.lean b/Mathlib/Data/Finset/Pi.lean index 5d941e51e8647..6097decc9b368 100644 --- a/Mathlib/Data/Finset/Pi.lean +++ b/Mathlib/Data/Finset/Pi.lean @@ -31,7 +31,7 @@ def Pi.empty (β : α → Sort*) (a : α) (h : a ∈ (∅ : Finset α)) : β a : #align finset.pi.empty Finset.Pi.empty universe u v -variable {β : α → Type u} {δ : α → Sort v} [DecidableEq α] +variable {β : α → Type u} {δ : α → Sort v} [DecidableEq α] {s : Finset α} {t : ∀ a, Finset (β a)} /-- Given a finset `s` of `α` and for all `a : α` a finset `t a` of `δ a`, then one can define the finset `s.pi t` of all functions defined on elements of `s` taking values in `t a` for `a ∈ s`. @@ -88,6 +88,9 @@ theorem pi_empty {t : ∀ a : α, Finset (β a)} : pi (∅ : Finset α) t = sing rfl #align finset.pi_empty Finset.pi_empty +@[simp] lemma pi_nonempty : (s.pi t).Nonempty ↔ ∀ a ∈ s, (t a).Nonempty := by + simp [Finset.Nonempty, Classical.skolem] + @[simp] theorem pi_insert [∀ a, DecidableEq (β a)] {s : Finset α} {t : ∀ a : α, Finset (β a)} {a : α} (ha : a ∉ s) : pi (insert a s) t = (t a).biUnion fun b => (pi s t).image (Pi.cons s a b) := by diff --git a/Mathlib/Data/Finset/Pointwise.lean b/Mathlib/Data/Finset/Pointwise.lean index 7feea71720368..5113284439635 100644 --- a/Mathlib/Data/Finset/Pointwise.lean +++ b/Mathlib/Data/Finset/Pointwise.lean @@ -91,6 +91,9 @@ theorem coe_one : ↑(1 : Finset α) = (1 : Set α) := #align finset.coe_one Finset.coe_one #align finset.coe_zero Finset.coe_zero +@[to_additive (attr := simp, norm_cast)] +lemma coe_eq_one : (s : Set α) = 1 ↔ s = 1 := coe_eq_singleton + @[to_additive (attr := simp)] theorem one_subset : (1 : Finset α) ⊆ s ↔ (1 : α) ∈ s := singleton_subset_iff @@ -258,32 +261,38 @@ theorem inv_insert (a : α) (s : Finset α) : (insert a s)⁻¹ = insert a⁻¹ #align finset.inv_insert Finset.inv_insert #align finset.neg_insert Finset.neg_insert +@[to_additive] lemma image_op_inv (s : Finset α) : s⁻¹.image op = (s.image op)⁻¹ := + image_comm op_inv + end Inv open Pointwise section InvolutiveInv +variable [DecidableEq α] [InvolutiveInv α] {s : Finset α} {a : α} -variable [DecidableEq α] [InvolutiveInv α] (s : Finset α) +@[to_additive (attr := simp)] +lemma mem_inv' : a ∈ s⁻¹ ↔ a⁻¹ ∈ s := by simp [mem_inv, inv_eq_iff_eq_inv] @[to_additive (attr := simp, norm_cast)] -theorem coe_inv : ↑s⁻¹ = (s : Set α)⁻¹ := - coe_image.trans Set.image_inv +theorem coe_inv (s : Finset α) : ↑s⁻¹ = (s : Set α)⁻¹ := coe_image.trans Set.image_inv #align finset.coe_inv Finset.coe_inv #align finset.coe_neg Finset.coe_neg @[to_additive (attr := simp)] -theorem card_inv : s⁻¹.card = s.card := - card_image_of_injective _ inv_injective +theorem card_inv (s : Finset α) : s⁻¹.card = s.card := card_image_of_injective _ inv_injective #align finset.card_inv Finset.card_inv #align finset.card_neg Finset.card_neg @[to_additive (attr := simp)] -theorem preimage_inv : s.preimage Inv.inv (inv_injective.injOn _) = s⁻¹ := +theorem preimage_inv (s : Finset α) : s.preimage (·⁻¹) (inv_injective.injOn _) = s⁻¹ := coe_injective <| by rw [coe_preimage, Set.inv_preimage, coe_inv] #align finset.preimage_inv Finset.preimage_inv #align finset.preimage_neg Finset.preimage_neg +@[to_additive (attr := simp)] +lemma inv_univ [Fintype α] : (univ : Finset α)⁻¹ = univ := by ext; simp + end InvolutiveInv /-! ### Finset addition/multiplication -/ @@ -540,11 +549,11 @@ theorem div_def : s / t = (s ×ˢ t).image fun p : α × α => p.1 / p.2 := #align finset.div_def Finset.div_def #align finset.sub_def Finset.sub_def -@[to_additive add_image_prod] -theorem image_div_prod : ((s ×ˢ t).image fun x : α × α => x.fst / x.snd) = s / t := +@[to_additive] +theorem image_div_product : ((s ×ˢ t).image fun x : α × α => x.fst / x.snd) = s / t := rfl -#align finset.image_div_prod Finset.image_div_prod -#align finset.add_image_prod Finset.add_image_prod +#align finset.image_div_prod Finset.image_div_product +#align finset.add_image_prod Finset.image_sub_product @[to_additive] theorem mem_div : a ∈ s / t ↔ ∃ b c, b ∈ s ∧ c ∈ t ∧ b / c = a := @@ -1012,6 +1021,8 @@ protected def divisionMonoid : DivisionMonoid (Finset α) := #align finset.division_monoid Finset.divisionMonoid #align finset.subtraction_monoid Finset.subtractionMonoid +scoped[Pointwise] attribute [instance] Finset.divisionMonoid Finset.subtractionMonoid + @[to_additive (attr := simp)] theorem isUnit_iff : IsUnit s ↔ ∃ a, s = {a} ∧ IsUnit a := by constructor @@ -1031,6 +1042,9 @@ theorem isUnit_coe : IsUnit (s : Set α) ↔ IsUnit s := by #align finset.is_unit_coe Finset.isUnit_coe #align finset.is_add_unit_coe Finset.isAddUnit_coe +@[to_additive (attr := simp)] +lemma univ_div_univ [Fintype α] : (univ / univ : Finset α) = univ := by simp [div_eq_mul_inv] + end DivisionMonoid /-- `Finset α` is a commutative division monoid under pointwise operations if `α` is. -/ @@ -1047,9 +1061,7 @@ protected def distribNeg [Mul α] [HasDistribNeg α] : HasDistribNeg (Finset α) #align finset.has_distrib_neg Finset.distribNeg scoped[Pointwise] - attribute [instance] - Finset.divisionMonoid Finset.subtractionMonoid - Finset.divisionCommMonoid Finset.subtractionCommMonoid Finset.distribNeg + attribute [instance] Finset.divisionCommMonoid Finset.subtractionCommMonoid Finset.distribNeg section Distrib @@ -1433,7 +1445,7 @@ section VSub -- Porting note: Reordered [VSub α β] and [DecidableEq α] to make vsub less dangerous. Bad? variable [VSub α β] [DecidableEq α] {s s₁ s₂ t t₁ t₂ : Finset β} {u : Finset α} {a : α} {b c : β} -/-- The pointwise product of two finsets `s` and `t`: `s -ᵥ t = {x -ᵥ y | x ∈ s, y ∈ t}`. -/ +/-- The pointwise subtraction of two finsets `s` and `t`: `s -ᵥ t = {x -ᵥ y | x ∈ s, y ∈ t}`. -/ protected def vsub : VSub (Finset α) (Finset β) := ⟨image₂ (· -ᵥ ·)⟩ #align finset.has_vsub Finset.vsub @@ -2062,8 +2074,64 @@ theorem card_dvd_card_mul_right {s t : Finset α} : ((· • t) '' (s : Set α)).PairwiseDisjoint id → t.card ∣ (s * t).card := card_dvd_card_image₂_right fun _ _ => mul_right_injective _ +@[to_additive (attr := simp)] +lemma inv_smul_finset_distrib (a : α) (s : Finset α) : (a • s)⁻¹ = op a⁻¹ • s⁻¹ := by + ext; simp [← inv_smul_mem_iff] + +@[to_additive (attr := simp)] +lemma inv_op_smul_finset_distrib (a : α) (s : Finset α) : (op a • s)⁻¹ = a⁻¹ • s⁻¹ := by + ext; simp [← inv_smul_mem_iff] + end Group +section SMulWithZero +variable [Zero α] [Zero β] [SMulWithZero α β] [DecidableEq β] {s : Finset α} {t : Finset β} + +/-! +Note that we have neither `SMulWithZero α (Finset β)` nor `SMulWithZero (Finset α) (Finset β)` +because `0 * ∅ ≠ 0`. +-/ + +lemma smul_zero_subset (s : Finset α) : s • (0 : Finset β) ⊆ 0 := by simp [subset_iff, mem_smul] +#align finset.smul_zero_subset Finset.smul_zero_subset + +lemma zero_smul_subset (t : Finset β) : (0 : Finset α) • t ⊆ 0 := by simp [subset_iff, mem_smul] +#align finset.zero_smul_subset Finset.zero_smul_subset + +lemma Nonempty.smul_zero (hs : s.Nonempty) : s • (0 : Finset β) = 0 := + s.smul_zero_subset.antisymm $ by simpa [mem_smul] using hs +#align finset.nonempty.smul_zero Finset.Nonempty.smul_zero + +lemma Nonempty.zero_smul (ht : t.Nonempty) : (0 : Finset α) • t = 0 := + t.zero_smul_subset.antisymm $ by simpa [mem_smul] using ht +#align finset.nonempty.zero_smul Finset.Nonempty.zero_smul + +/-- A nonempty set is scaled by zero to the singleton set containing zero. -/ +@[simp] lemma zero_smul_finset {s : Finset β} (h : s.Nonempty) : (0 : α) • s = (0 : Finset β) := + coe_injective $ by simpa using @Set.zero_smul_set α _ _ _ _ _ h +#align finset.zero_smul_finset Finset.zero_smul_finset + +lemma zero_smul_finset_subset (s : Finset β) : (0 : α) • s ⊆ 0 := + image_subset_iff.2 fun x _ ↦ mem_zero.2 $ zero_smul α x +#align finset.zero_smul_finset_subset Finset.zero_smul_finset_subset + +lemma zero_mem_smul_finset {t : Finset β} {a : α} (h : (0 : β) ∈ t) : (0 : β) ∈ a • t := + mem_smul_finset.2 ⟨0, h, smul_zero _⟩ +#align finset.zero_mem_smul_finset Finset.zero_mem_smul_finset + +variable [NoZeroSMulDivisors α β] {a : α} + +lemma zero_mem_smul_iff : + (0 : β) ∈ s • t ↔ (0 : α) ∈ s ∧ t.Nonempty ∨ (0 : β) ∈ t ∧ s.Nonempty := by + rw [← mem_coe, coe_smul, Set.zero_mem_smul_iff]; rfl +#align finset.zero_mem_smul_iff Finset.zero_mem_smul_iff + +lemma zero_mem_smul_finset_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by + rw [← mem_coe, coe_smul_finset, Set.zero_mem_smul_set_iff ha, mem_coe] +#align finset.zero_mem_smul_finset_iff Finset.zero_mem_smul_finset_iff + +end SMulWithZero + section GroupWithZero variable [DecidableEq β] [GroupWithZero α] [MulAction α β] {s t : Finset β} {a : α} {b : β} @@ -2106,6 +2174,10 @@ theorem smul_finset_symmDiff₀ (ha : a ≠ 0) : a • s ∆ t = (a • s) ∆ ( image_symmDiff _ _ <| MulAction.injective₀ ha #align finset.smul_finset_symm_diff₀ Finset.smul_finset_symmDiff₀ +lemma smul_finset_univ₀ [Fintype β] (ha : a ≠ 0) : a • (univ : Finset β) = univ := + coe_injective $ by push_cast; exact Set.smul_set_univ₀ ha +#align finset.smul_finset_univ₀ Finset.smul_finset_univ₀ + theorem smul_univ₀ [Fintype β] {s : Finset α} (hs : ¬s ⊆ 0) : s • (univ : Finset β) = univ := coe_injective <| by rw [← coe_subset] at hs @@ -2113,64 +2185,24 @@ theorem smul_univ₀ [Fintype β] {s : Finset α} (hs : ¬s ⊆ 0) : s • (univ exact Set.smul_univ₀ hs #align finset.smul_univ₀ Finset.smul_univ₀ -theorem smul_finset_univ₀ [Fintype β] (ha : a ≠ 0) : a • (univ : Finset β) = univ := - coe_injective <| by - push_cast - exact Set.smul_set_univ₀ ha -#align finset.smul_finset_univ₀ Finset.smul_finset_univ₀ - -end GroupWithZero - -section SMulWithZero - -variable [Zero α] [Zero β] [SMulWithZero α β] [DecidableEq β] {s : Finset α} {t : Finset β} - -/-! -Note that we have neither `SMulWithZero α (Finset β)` nor `SMulWithZero (Finset α) (Finset β)` -because `0 * ∅ ≠ 0`. --/ - - -theorem smul_zero_subset (s : Finset α) : s • (0 : Finset β) ⊆ 0 := by simp [subset_iff, mem_smul] -#align finset.smul_zero_subset Finset.smul_zero_subset - -theorem zero_smul_subset (t : Finset β) : (0 : Finset α) • t ⊆ 0 := by simp [subset_iff, mem_smul] -#align finset.zero_smul_subset Finset.zero_smul_subset - -theorem Nonempty.smul_zero (hs : s.Nonempty) : s • (0 : Finset β) = 0 := - s.smul_zero_subset.antisymm <| by simpa [mem_smul] using hs -#align finset.nonempty.smul_zero Finset.Nonempty.smul_zero - -theorem Nonempty.zero_smul (ht : t.Nonempty) : (0 : Finset α) • t = 0 := - t.zero_smul_subset.antisymm <| by simpa [mem_smul] using ht -#align finset.nonempty.zero_smul Finset.Nonempty.zero_smul +lemma smul_univ₀' [Fintype β] {s : Finset α} (hs : s.Nontrivial) : s • (univ : Finset β) = univ := + coe_injective $ by push_cast; exact Set.smul_univ₀' hs -/-- A nonempty set is scaled by zero to the singleton set containing 0. -/ -theorem zero_smul_finset {s : Finset β} (h : s.Nonempty) : (0 : α) • s = (0 : Finset β) := - coe_injective <| by simpa using @Set.zero_smul_set α _ _ _ _ _ h -#align finset.zero_smul_finset Finset.zero_smul_finset - -theorem zero_smul_finset_subset (s : Finset β) : (0 : α) • s ⊆ 0 := - image_subset_iff.2 fun x _ => mem_zero.2 <| zero_smul α x -#align finset.zero_smul_finset_subset Finset.zero_smul_finset_subset +variable [DecidableEq α] -theorem zero_mem_smul_finset {t : Finset β} {a : α} (h : (0 : β) ∈ t) : (0 : β) ∈ a • t := - mem_smul_finset.2 ⟨0, h, smul_zero _⟩ -#align finset.zero_mem_smul_finset Finset.zero_mem_smul_finset +@[simp] protected lemma inv_zero : (0 : Finset α)⁻¹ = 0 := by ext; simp -variable [NoZeroSMulDivisors α β] {a : α} +@[simp] lemma inv_smul_finset_distrib₀ (a : α) (s : Finset α) : (a • s)⁻¹ = op a⁻¹ • s⁻¹ := by + obtain rfl | ha := eq_or_ne a 0 + · obtain rfl | hs := s.eq_empty_or_nonempty <;> simp [*] + · ext; simp [← inv_smul_mem_iff₀, *] -theorem zero_mem_smul_iff : - (0 : β) ∈ s • t ↔ (0 : α) ∈ s ∧ t.Nonempty ∨ (0 : β) ∈ t ∧ s.Nonempty := by - rw [← mem_coe, coe_smul, Set.zero_mem_smul_iff] - rfl -#align finset.zero_mem_smul_iff Finset.zero_mem_smul_iff +@[simp] lemma inv_op_smul_finset_distrib₀ (a : α) (s : Finset α) : (op a • s)⁻¹ = a⁻¹ • s⁻¹ := by + obtain rfl | ha := eq_or_ne a 0 + · obtain rfl | hs := s.eq_empty_or_nonempty <;> simp [*] + · ext; simp [← inv_smul_mem_iff₀, *] -theorem zero_mem_smul_finset_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by - rw [← mem_coe, coe_smul_finset, Set.zero_mem_smul_set_iff ha, mem_coe] -#align finset.zero_mem_smul_finset_iff Finset.zero_mem_smul_finset_iff - -end SMulWithZero +end GroupWithZero section Monoid @@ -2208,8 +2240,57 @@ protected theorem neg_smul [DecidableEq α] : -s • t = -(s • t) := by end Ring +section BigOps +section CommMonoid +variable [CommMonoid α] {ι : Type*} [DecidableEq ι] + +@[to_additive (attr := simp)] lemma prod_inv_index [InvolutiveInv ι] (s : Finset ι) (f : ι → α) : + ∏ i in s⁻¹, f i = ∏ i in s, f i⁻¹ := prod_image $ inv_injective.injOn _ + +@[to_additive existing, simp] lemma prod_neg_index [InvolutiveNeg ι] (s : Finset ι) (f : ι → α) : + ∏ i in -s, f i = ∏ i in s, f (-i) := prod_image $ neg_injective.injOn _ + +end CommMonoid + +section AddCommMonoid +variable [AddCommMonoid α] {ι : Type*} [DecidableEq ι] + +@[to_additive existing, simp] lemma sum_inv_index [InvolutiveInv ι] (s : Finset ι) (f : ι → α) : + ∑ i in s⁻¹, f i = ∑ i in s, f i⁻¹ := sum_image $ inv_injective.injOn _ + +end AddCommMonoid +end BigOps end Finset +namespace Fintype +variable {ι : Type*} {α β : ι → Type*} [Fintype ι] [DecidableEq ι] [∀ i, DecidableEq (α i)] + [∀ i, DecidableEq (β i)] + +@[to_additive] +lemma piFinset_mul [∀ i, Mul (α i)] (s t : ∀ i, Finset (α i)) : + piFinset (fun i ↦ s i * t i) = piFinset s * piFinset t := piFinset_image₂ _ _ _ + +@[to_additive] +lemma piFinset_div [∀ i, Div (α i)] (s t : ∀ i, Finset (α i)) : + piFinset (fun i ↦ s i / t i) = piFinset s / piFinset t := piFinset_image₂ _ _ _ + +@[to_additive (attr := simp)] +lemma piFinset_inv [∀ i, Inv (α i)] (s : ∀ i, Finset (α i)) : + piFinset (fun i ↦ (s i)⁻¹) = (piFinset s)⁻¹ := piFinset_image _ _ + +@[to_additive] +lemma piFinset_smul [∀ i, SMul (α i) (β i)] (s : ∀ i, Finset (α i)) (t : ∀ i, Finset (β i)) : + piFinset (fun i ↦ s i • t i) = piFinset s • piFinset t := piFinset_image₂ _ _ _ + +@[to_additive] +lemma piFinset_smul_finset [∀ i, SMul (α i) (β i)] (a : ∀ i, α i) (s : ∀ i, Finset (β i)) : + piFinset (fun i ↦ a i • s i) = a • piFinset s := piFinset_image _ _ + +-- Note: We don't currently state `piFinset_vsub` because there's no +-- `[∀ i, VSub (β i) (α i)] → VSub (∀ i, β i) (∀ i, α i)` instance + +end Fintype + open Pointwise namespace Set @@ -2354,3 +2435,8 @@ lemma card_div_le : Nat.card (s / t) ≤ Nat.card s * Nat.card t := by end Group end Set + +instance Nat.decidablePred_mem_vadd_set {s : Set ℕ} [DecidablePred (· ∈ s)] (a : ℕ) : + DecidablePred (· ∈ a +ᵥ s) := + fun n ↦ decidable_of_iff' (a ≤ n ∧ n - a ∈ s) $ by + simp only [Set.mem_vadd_set, vadd_eq_add]; aesop diff --git a/Mathlib/Data/Fintype/Pi.lean b/Mathlib/Data/Fintype/Pi.lean index d9a618653a4ee..ddb38b10f78a6 100644 --- a/Mathlib/Data/Fintype/Pi.lean +++ b/Mathlib/Data/Fintype/Pi.lean @@ -20,7 +20,7 @@ open Finset namespace Fintype -variable [DecidableEq α] [Fintype α] {δ : α → Type*} +variable [DecidableEq α] [Fintype α] {γ δ : α → Type*} {s : ∀ a, Finset (γ a)} /-- Given for all `a : α` a finset `t a` of `δ a`, then one can define the finset `Fintype.piFinset t` of all functions taking values in `t a` for all `a`. This is the @@ -60,6 +60,13 @@ theorem piFinset_empty [Nonempty α] : piFinset (fun _ => ∅ : ∀ i, Finset ( eq_empty_of_forall_not_mem fun _ => by simp #align fintype.pi_finset_empty Fintype.piFinset_empty +@[simp] lemma piFinset_nonempty : (piFinset s).Nonempty ↔ ∀ a, (s a).Nonempty := by + simp [Finset.Nonempty, Classical.skolem] + +@[simp] +lemma piFinset_of_isEmpty [IsEmpty α] (s : ∀ a, Finset (γ a)) : piFinset s = univ := + eq_univ_of_forall fun _ ↦ by simp + @[simp] theorem piFinset_singleton (f : ∀ i, δ i) : piFinset (fun i => {f i} : ∀ i, Finset (δ i)) = {f} := ext fun _ => by simp only [Function.funext_iff, Fintype.mem_piFinset, mem_singleton] @@ -77,6 +84,23 @@ theorem piFinset_disjoint_of_disjoint (t₁ t₂ : ∀ a, Finset (δ a)) {a : α (congr_fun eq₁₂ a) #align fintype.pi_finset_disjoint_of_disjoint Fintype.piFinset_disjoint_of_disjoint +lemma piFinset_image [∀ a, DecidableEq (δ a)] (f : ∀ a, γ a → δ a) (s : ∀ a, Finset (γ a)) : + piFinset (fun a ↦ (s a).image (f a)) = (piFinset s).image fun b a ↦ f _ (b a) := by + ext; simp only [mem_piFinset, mem_image, Classical.skolem, forall_and, Function.funext_iff] + +lemma eval_image_piFinset_subset (t : ∀ a, Finset (δ a)) (a : α) [DecidableEq (δ a)] : + ((piFinset t).image fun f ↦ f a) ⊆ t a := image_subset_iff.2 fun _x hx ↦ mem_piFinset.1 hx _ + +lemma eval_image_piFinset (t : ∀ a, Finset (δ a)) (a : α) [DecidableEq (δ a)] + (ht : ∀ b, a ≠ b → (t b).Nonempty) : ((piFinset t).image fun f ↦ f a) = t a := by + refine (eval_image_piFinset_subset _ _).antisymm $ fun x h ↦ mem_image.2 ?_ + choose f hf using ht + exact ⟨fun b ↦ if h : a = b then h ▸ x else f _ h, by aesop, by simp⟩ + +lemma filter_piFinset_of_not_mem [∀ a, DecidableEq (δ a)] (t : ∀ a, Finset (δ a)) (a : α) + (x : δ a) (hx : x ∉ t a) : (piFinset t).filter (· a = x) = ∅ := by + simp only [filter_eq_empty_iff, mem_piFinset]; rintro f hf rfl; exact hx (hf _) + end Fintype /-! ### pi -/ diff --git a/Mathlib/Data/Set/Pointwise/Basic.lean b/Mathlib/Data/Set/Pointwise/Basic.lean index 02eba85d9c0c0..a690e8cbf3791 100644 --- a/Mathlib/Data/Set/Pointwise/Basic.lean +++ b/Mathlib/Data/Set/Pointwise/Basic.lean @@ -1066,6 +1066,8 @@ protected noncomputable def divisionMonoid : DivisionMonoid (Set α) := #align set.division_monoid Set.divisionMonoid #align set.subtraction_monoid Set.subtractionMonoid +scoped[Pointwise] attribute [instance] Set.divisionMonoid Set.subtractionMonoid + @[to_additive (attr := simp 500)] theorem isUnit_iff : IsUnit s ↔ ∃ a, s = {a} ∧ IsUnit a := by constructor @@ -1079,6 +1081,9 @@ theorem isUnit_iff : IsUnit s ↔ ∃ a, s = {a} ∧ IsUnit a := by #align set.is_unit_iff Set.isUnit_iff #align set.is_add_unit_iff Set.isAddUnit_iff +@[to_additive (attr := simp)] +lemma univ_div_univ : (univ / univ : Set α) = univ := by simp [div_eq_mul_inv] + end DivisionMonoid /-- `Set α` is a commutative division monoid under pointwise operations if `α` is. -/ @@ -1102,9 +1107,7 @@ protected noncomputable def hasDistribNeg [Mul α] [HasDistribNeg α] : HasDistr #align set.has_distrib_neg Set.hasDistribNeg scoped[Pointwise] - attribute [instance] - Set.divisionMonoid Set.subtractionMonoid Set.divisionCommMonoid Set.subtractionCommMonoid - Set.hasDistribNeg + attribute [instance] Set.divisionCommMonoid Set.subtractionCommMonoid Set.hasDistribNeg section Distrib diff --git a/Mathlib/Data/Set/Pointwise/SMul.lean b/Mathlib/Data/Set/Pointwise/SMul.lean index a8ca3f1fc3045..2c5838d00df39 100644 --- a/Mathlib/Data/Set/Pointwise/SMul.lean +++ b/Mathlib/Data/Set/Pointwise/SMul.lean @@ -814,7 +814,7 @@ theorem Nonempty.zero_smul (ht : t.Nonempty) : (0 : Set α) • t = 0 := #align set.nonempty.zero_smul Set.Nonempty.zero_smul /-- A nonempty set is scaled by zero to the singleton set containing 0. -/ -theorem zero_smul_set {s : Set β} (h : s.Nonempty) : (0 : α) • s = (0 : Set β) := by +@[simp] theorem zero_smul_set {s : Set β} (h : s.Nonempty) : (0 : α) • s = (0 : Set β) := by simp only [← image_smul, image_eta, zero_smul, h.image_const, singleton_zero] #align set.zero_smul_set Set.zero_smul_set @@ -1010,6 +1010,14 @@ theorem iUnion_smul_eq_setOf_exists {s : Set β} : ⋃ g : α, g • s = { a | #align set.Union_smul_eq_set_of_exists Set.iUnion_smul_eq_setOf_exists #align set.Union_vadd_eq_set_of_exists Set.iUnion_vadd_eq_setOf_exists +@[to_additive (attr := simp)] +lemma inv_smul_set_distrib (a : α) (s : Set α) : (a • s)⁻¹ = op a⁻¹ • s⁻¹ := by + ext; simp [mem_smul_set_iff_inv_smul_mem] + +@[to_additive (attr := simp)] +lemma inv_op_smul_set_distrib (a : α) (s : Set α) : (op a • s)⁻¹ = a⁻¹ • s⁻¹ := by + ext; simp [mem_smul_set_iff_inv_smul_mem] + end Group section GroupWithZero @@ -1075,6 +1083,18 @@ theorem smul_univ₀' {s : Set α} (hs : s.Nontrivial) : s • (univ : Set β) = smul_univ₀ hs.not_subset_singleton #align set.smul_univ₀' Set.smul_univ₀' +@[simp] protected lemma inv_zero : (0 : Set α)⁻¹ = 0 := by ext; simp + +@[simp] lemma inv_smul_set_distrib₀ (a : α) (s : Set α) : (a • s)⁻¹ = op a⁻¹ • s⁻¹ := by + obtain rfl | ha := eq_or_ne a 0 + · obtain rfl | hs := s.eq_empty_or_nonempty <;> simp [*] + · ext; simp [mem_smul_set_iff_inv_smul_mem₀, *] + +@[simp] lemma inv_op_smul_set_distrib₀ (a : α) (s : Set α) : (op a • s)⁻¹ = a⁻¹ • s⁻¹ := by + obtain rfl | ha := eq_or_ne a 0 + · obtain rfl | hs := s.eq_empty_or_nonempty <;> simp [*] + · ext; simp [mem_smul_set_iff_inv_smul_mem₀, *] + end GroupWithZero section Monoid From 82c60323a6de628434daaa26b09fddeae810c0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 27 Dec 2023 20:59:08 +0000 Subject: [PATCH 262/353] feat: Better lemmas for transferring finite sums along equivalences (#9237) Lemmas around this were a mess, throth in terms of names, statement and location. This PR standardises everything to be in `Algebra.BigOperators.Basic` and changes the lemmas to take in `InjOn` and `SurjOn` assumptions where possible (and where impossible make sure the hypotheses are taken in the correct order) and moves the equality of functions hypothesis last. Also add a few lemmas that help fix downstream uses by golfing. From LeanAPAP and LeanCamCombi --- Mathlib/Algebra/BigOperators/Basic.lean | 344 ++++++++++++------ Mathlib/Algebra/BigOperators/Finprod.lean | 12 +- Mathlib/Algebra/BigOperators/Finsupp.lean | 4 +- Mathlib/Algebra/BigOperators/Intervals.lean | 6 +- Mathlib/Algebra/BigOperators/Ring.lean | 21 +- Mathlib/Algebra/Tropical/BigOperators.lean | 2 +- .../AlternatingFaceMapComplex.lean | 20 +- Mathlib/Analysis/Analytic/Composition.lean | 16 +- Mathlib/Combinatorics/Configuration.lean | 41 +-- Mathlib/Data/Complex/Exponential.lean | 48 +-- Mathlib/Data/DFinsupp/Basic.lean | 5 +- Mathlib/Data/Finset/Card.lean | 4 +- Mathlib/Data/Finset/LocallyFinite.lean | 2 +- Mathlib/Data/Finsupp/Antidiagonal.lean | 4 +- Mathlib/Data/Finsupp/Basic.lean | 5 +- Mathlib/Data/Fintype/BigOperators.lean | 46 +-- Mathlib/Data/Multiset/Nodup.lean | 18 +- Mathlib/Data/Polynomial/Mirror.lean | 4 +- Mathlib/Data/Set/Card.lean | 6 +- Mathlib/Data/Set/Finite.lean | 2 +- Mathlib/Data/Sign.lean | 2 +- Mathlib/FieldTheory/Fixed.lean | 2 +- Mathlib/GroupTheory/PGroup.lean | 2 +- Mathlib/GroupTheory/Perm/Sign.lean | 79 ++-- Mathlib/GroupTheory/SchurZassenhaus.lean | 11 +- Mathlib/GroupTheory/Transfer.lean | 11 +- Mathlib/LinearAlgebra/Matrix/Determinant.lean | 43 +-- Mathlib/NumberTheory/ArithmeticFunction.lean | 152 +++----- .../LegendreSymbol/GaussEisensteinLemmas.lean | 7 +- .../NumberTheory/NumberField/Embeddings.lean | 2 +- Mathlib/NumberTheory/Wilson.lean | 2 +- Mathlib/Probability/StrongLaw.lean | 40 +- Mathlib/RingTheory/Discriminant.lean | 43 +-- Mathlib/RingTheory/HahnSeries.lean | 39 +- Mathlib/RingTheory/IntegralDomain.lean | 9 +- Mathlib/RingTheory/Noetherian.lean | 2 +- .../Polynomial/IntegralNormalization.lean | 4 +- Mathlib/RingTheory/PowerSeries/Basic.lean | 65 +--- 38 files changed, 493 insertions(+), 632 deletions(-) diff --git a/Mathlib/Algebra/BigOperators/Basic.lean b/Mathlib/Algebra/BigOperators/Basic.lean index 7c252a8743dfa..9a4a252031c9c 100644 --- a/Mathlib/Algebra/BigOperators/Basic.lean +++ b/Mathlib/Algebra/BigOperators/Basic.lean @@ -537,73 +537,165 @@ theorem prod_sigma' {σ : α → Type*} (s : Finset α) (t : ∀ a, Finset (σ a #align finset.prod_sigma' Finset.prod_sigma' #align finset.sum_sigma' Finset.sum_sigma' +section bij +variable {ι κ α : Type*} [CommMonoid α] {s : Finset ι} {t : Finset κ} {f : ι → α} {g : κ → α} + /-- Reorder a product. - The difference with `prod_bij'` is that the bijection is specified as a surjective injection, - rather than by an inverse function. --/ +The difference with `Finset.prod_bij'` is that the bijection is specified as a surjective injection, +rather than by an inverse function. + +The difference with `Finset.prod_nbij` is that the bijection is allowed to use membership of the +domain of the product, rather than being a non-dependent function. -/ @[to_additive "Reorder a sum. - The difference with `sum_bij'` is that the bijection is specified as a surjective injection, - rather than by an inverse function."] -theorem prod_bij {s : Finset α} {t : Finset γ} {f : α → β} {g : γ → β} (i : ∀ a ∈ s, γ) - (hi : ∀ a ha, i a ha ∈ t) (h : ∀ a ha, f a = g (i a ha)) - (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂) - (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : ∏ x in s, f x = ∏ x in t, g x := - congr_arg Multiset.prod (Multiset.map_eq_map_of_bij_of_nodup f g s.2 t.2 i hi h i_inj i_surj) +The difference with `Finset.sum_bij'` is that the bijection is specified as a surjective injection, +rather than by an inverse function. + +The difference with `Finset.sum_nbij` is that the bijection is allowed to use membership of the +domain of the sum, rather than being a non-dependent function."] +theorem prod_bij (i : ∀ a ∈ s, κ) (hi : ∀ a ha, i a ha ∈ t) + (i_inj : ∀ a₁ ha₁ a₂ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂) + (i_surj : ∀ b ∈ t, ∃ a ha, i a ha = b) (h : ∀ a ha, f a = g (i a ha)) : + ∏ x in s, f x = ∏ x in t, g x := + congr_arg Multiset.prod (Multiset.map_eq_map_of_bij_of_nodup f g s.2 t.2 i hi i_inj i_surj h) #align finset.prod_bij Finset.prod_bij #align finset.sum_bij Finset.sum_bij /-- Reorder a product. - The difference with `prod_bij` is that the bijection is specified with an inverse, rather than - as a surjective injection. --/ +The difference with `Finset.prod_bij` is that the bijection is specified with an inverse, rather +than as a surjective injection. + +The difference with `Finset.prod_nbij'` is that the bijection and its inverse are allowed to use +membership of the domains of the products, rather than being non-dependent functions. -/ @[to_additive "Reorder a sum. - The difference with `sum_bij` is that the bijection is specified with an inverse, rather than - as a surjective injection."] -theorem prod_bij' {s : Finset α} {t : Finset γ} {f : α → β} {g : γ → β} (i : ∀ a ∈ s, γ) - (hi : ∀ a ha, i a ha ∈ t) (h : ∀ a ha, f a = g (i a ha)) (j : ∀ a ∈ t, α) +The difference with `Finset.sum_bij` is that the bijection is specified with an inverse, rather than +as a surjective injection. + +The difference with `Finset.sum_nbij'` is that the bijection and its inverse are allowed to use +membership of the domains of the sums, rather than being non-dependent functions."] +theorem prod_bij' (i : ∀ a ∈ s, κ) (j : ∀ a ∈ t, ι) (hi : ∀ a ha, i a ha ∈ t) (hj : ∀ a ha, j a ha ∈ s) (left_inv : ∀ a ha, j (i a ha) (hi a ha) = a) - (right_inv : ∀ a ha, i (j a ha) (hj a ha) = a) : ∏ x in s, f x = ∏ x in t, g x := by - refine' prod_bij i hi h _ _ - · intro a1 a2 h1 h2 eq - rw [← left_inv a1 h1, ← left_inv a2 h2] - simp only [eq] - · intro b hb - use j b hb - use hj b hb - exact (right_inv b hb).symm + (right_inv : ∀ a ha, i (j a ha) (hj a ha) = a) (h : ∀ a ha, f a = g (i a ha)) : + ∏ x in s, f x = ∏ x in t, g x := by + refine prod_bij i hi (fun a1 h1 a2 h2 eq ↦ ?_) (fun b hb ↦ ⟨_, hj b hb, right_inv b hb⟩) h + rw [← left_inv a1 h1, ← left_inv a2 h2] + simp only [eq] #align finset.prod_bij' Finset.prod_bij' #align finset.sum_bij' Finset.sum_bij' -/-- Reindexing a product over a finset along an equivalence. -See `Equiv.prod_comp` for the version where `s` and `s'` are `univ`. -/ -@[to_additive " Reindexing a sum over a finset along an equivalence. -See `Equiv.sum_comp` for the version where `s` and `s'` are `univ`. "] -theorem Equiv.prod_comp_finset {ι'} [DecidableEq ι] (e : ι ≃ ι') (f : ι' → β) {s' : Finset ι'} - {s : Finset ι} (h : s = s'.image e.symm) : ∏ i' in s', f i' = ∏ i in s, f (e i) := by - rw [h] - refine' - Finset.prod_bij' (fun i' _hi' => e.symm i') (fun a ha => Finset.mem_image_of_mem _ ha) - (fun a _ha => by simp_rw [e.apply_symm_apply]) (fun i _hi => e i) (fun a ha => _) - (fun a _ha => e.apply_symm_apply a) fun a _ha => e.symm_apply_apply a - rcases Finset.mem_image.mp ha with ⟨i', hi', rfl⟩ - dsimp only - rwa [e.apply_symm_apply] -#align finset.equiv.prod_comp_finset Finset.Equiv.prod_comp_finset -#align finset.equiv.sum_comp_finset Finset.Equiv.sum_comp_finset +/-- Reorder a product. + +The difference with `Finset.prod_nbij'` is that the bijection is specified as a surjective +injection, rather than by an inverse function. + +The difference with `Finset.prod_bij` is that the bijection is a non-dependent function, rather than +being allowed to use membership of the domain of the product. -/ +@[to_additive "Reorder a sum. + +The difference with `Finset.sum_nbij'` is that the bijection is specified as a surjective injection, +rather than by an inverse function. + +The difference with `Finset.sum_bij` is that the bijection is a non-dependent function, rather than +being allowed to use membership of the domain of the sum."] +lemma prod_nbij (i : ι → κ) (hi : ∀ a ∈ s, i a ∈ t) (i_inj : (s : Set ι).InjOn i) + (i_surj : (s : Set ι).SurjOn i t) (h : ∀ a ∈ s, f a = g (i a)) : + ∏ x in s, f x = ∏ x in t, g x := + prod_bij (fun a _ ↦ i a) hi i_inj (by simpa using i_surj) h + +/-- Reorder a product. + +The difference with `Finset.prod_nbij` is that the bijection is specified with an inverse, rather +than as a surjective injection. + +The difference with `Finset.prod_bij'` is that the bijection and its inverse are non-dependent +functions, rather than being allowed to use membership of the domains of the products. + +The difference with `Finset.prod_equiv` is that bijectivity is only required to hold on the domains +of the products, rather than on the entire types. +-/ +@[to_additive "Reorder a sum. + +The difference with `Finset.sum_nbij` is that the bijection is specified with an inverse, rather +than as a surjective injection. + +The difference with `Finset.sum_bij'` is that the bijection and its inverse are non-dependent +functions, rather than being allowed to use membership of the domains of the sums. + +The difference with `Finset.sum_equiv` is that bijectivity is only required to hold on the domains +of the sums, rather than on the entire types."] +lemma prod_nbij' (i : ι → κ) (j : κ → ι) (hi : ∀ a ∈ s, i a ∈ t) (hj : ∀ a ∈ t, j a ∈ s) + (left_inv : ∀ a ∈ s, j (i a) = a) (right_inv : ∀ a ∈ t, i (j a) = a) + (h : ∀ a ∈ s, f a = g (i a)) : ∏ x in s, f x = ∏ x in t, g x := + prod_bij' (fun a _ ↦ i a) (fun b _ ↦ j b) hi hj left_inv right_inv h + +/-- Specialization of `Finset.prod_nbij'` that automatically fills in most arguments. + +See `Fintype.prod_equiv` for the version where `s` and `t` are `univ`. -/ +@[to_additive "`Specialization of `Finset.sum_nbij'` that automatically fills in most arguments. + +See `Fintype.sum_equiv` for the version where `s` and `t` are `univ`."] +lemma prod_equiv (e : ι ≃ κ) (hst : ∀ i, i ∈ s ↔ e i ∈ t) (hfg : ∀ i ∈ s, f i = g (e i)) : + ∏ i in s, f i = ∏ i in t, g i := by refine prod_nbij' e e.symm ?_ ?_ ?_ ?_ hfg <;> simp [hst] +#align finset.equiv.prod_comp_finset Finset.prod_equiv +#align finset.equiv.sum_comp_finset Finset.sum_equiv + +/-- Specialization of `Finset.prod_bij` that automatically fills in most arguments. + +See `Fintype.prod_bijective` for the version where `s` and `t` are `univ`. -/ +@[to_additive "`Specialization of `Finset.sum_bij` that automatically fills in most arguments. + +See `Fintype.sum_bijective` for the version where `s` and `t` are `univ`."] +lemma prod_bijective (e : ι → κ) (he : e.Bijective) (hst : ∀ i, i ∈ s ↔ e i ∈ t) + (hfg : ∀ i ∈ s, f i = g (e i)) : + ∏ i in s, f i = ∏ i in t, g i := prod_equiv (.ofBijective e he) hst hfg + +variable [DecidableEq κ] + +@[to_additive] +lemma prod_fiberwise_of_maps_to {g : ι → κ} (h : ∀ i ∈ s, g i ∈ t) (f : ι → α) : + ∏ j in t, ∏ i in s.filter fun i ↦ g i = j, f i = ∏ i in s, f i := by + rw [← prod_disjiUnion, disjiUnion_filter_eq_of_maps_to h] +#align finset.prod_fiberwise_of_maps_to Finset.prod_fiberwise_of_maps_to +#align finset.sum_fiberwise_of_maps_to Finset.sum_fiberwise_of_maps_to + +@[to_additive] +lemma prod_fiberwise_of_maps_to' {g : ι → κ} (h : ∀ i ∈ s, g i ∈ t) (f : κ → α) : + ∏ j in t, ∏ _i in s.filter fun i ↦ g i = j, f j = ∏ i in s, f (g i) := by + calc + _ = ∏ y in t, ∏ x in s.filter fun x ↦ g x = y, f (g x) := + prod_congr rfl $ fun y _ ↦ prod_congr rfl fun x hx ↦ by rw [(mem_filter.1 hx).2] + _ = _ := prod_fiberwise_of_maps_to h _ + +variable [Fintype κ] + +@[to_additive] +lemma prod_fiberwise (s : Finset ι) (g : ι → κ) (f : ι → α) : + ∏ j, ∏ i in s.filter fun i ↦ g i = j, f i = ∏ i in s, f i := + prod_fiberwise_of_maps_to (fun _ _ ↦ mem_univ _) _ +#align finset.prod_fiberwise Finset.prod_fiberwise +#align finset.sum_fiberwise Finset.sum_fiberwise + +@[to_additive] +lemma prod_fiberwise' (s : Finset ι) (g : ι → κ) (f : κ → α) : + ∏ j, ∏ _i in s.filter fun i ↦ g i = j, f j = ∏ i in s, f (g i) := + prod_fiberwise_of_maps_to' (fun _ _ ↦ mem_univ _) _ + +end bij + +@[to_additive (attr := simp)] +lemma prod_diag [DecidableEq α] (s : Finset α) (f : α × α → β) : + ∏ i in s.diag, f i = ∏ i in s, f (i, i) := by + apply prod_nbij' Prod.fst (fun i ↦ (i, i)) <;> simp @[to_additive] theorem prod_finset_product (r : Finset (γ × α)) (s : Finset γ) (t : γ → Finset α) (h : ∀ p : γ × α, p ∈ r ↔ p.1 ∈ s ∧ p.2 ∈ t p.1) {f : γ × α → β} : ∏ p in r, f p = ∏ c in s, ∏ a in t c, f (c, a) := by refine' Eq.trans _ (prod_sigma s t fun p => f (p.1, p.2)) - exact - prod_bij' (fun p _hp => ⟨p.1, p.2⟩) (fun p => mem_sigma.mpr ∘ (h p).mp) - (fun p _ => rfl) (fun p _hp => (p.1, p.2)) - (fun p => (h (p.1, p.2)).mpr ∘ mem_sigma.mp) (fun p _ => rfl) fun p _hp => p.eta + apply prod_equiv (Equiv.sigmaEquivProd _ _).symm <;> simp [h] #align finset.prod_finset_product Finset.prod_finset_product #align finset.sum_finset_product Finset.sum_finset_product @@ -620,10 +712,7 @@ theorem prod_finset_product_right (r : Finset (α × γ)) (s : Finset γ) (t : (h : ∀ p : α × γ, p ∈ r ↔ p.2 ∈ s ∧ p.1 ∈ t p.2) {f : α × γ → β} : ∏ p in r, f p = ∏ c in s, ∏ a in t c, f (a, c) := by refine' Eq.trans _ (prod_sigma s t fun p => f (p.2, p.1)) - exact - prod_bij' (fun p _hp => ⟨p.2, p.1⟩) (fun p => mem_sigma.mpr ∘ (h p).mp) - (fun p _c => rfl) (fun p _hp => (p.2, p.1)) - (fun p => (h (p.2, p.1)).mpr ∘ mem_sigma.mp) (fun p _ => rfl) fun p _hp => p.eta + apply prod_equiv ((Equiv.prodComm _ _).trans (Equiv.sigmaEquivProd _ _).symm) <;> simp [h] #align finset.prod_finset_product_right Finset.prod_finset_product_right #align finset.sum_finset_product_right Finset.sum_finset_product_right @@ -635,14 +724,6 @@ theorem prod_finset_product_right' (r : Finset (α × γ)) (s : Finset γ) (t : #align finset.prod_finset_product_right' Finset.prod_finset_product_right' #align finset.sum_finset_product_right' Finset.sum_finset_product_right' -@[to_additive] -theorem prod_fiberwise_of_maps_to [DecidableEq γ] {s : Finset α} {t : Finset γ} {g : α → γ} - (h : ∀ x ∈ s, g x ∈ t) (f : α → β) : - (∏ y in t, ∏ x in s.filter fun x => g x = y, f x) = ∏ x in s, f x := by - rw [← prod_disjiUnion, disjiUnion_filter_eq_of_maps_to h] -#align finset.prod_fiberwise_of_maps_to Finset.prod_fiberwise_of_maps_to -#align finset.sum_fiberwise_of_maps_to Finset.sum_fiberwise_of_maps_to - @[to_additive] theorem prod_image' [DecidableEq α] {s : Finset γ} {g : γ → α} (h : γ → β) (eq : ∀ c ∈ s, f (g c) = ∏ x in s.filter fun c' => g c' = g c, h x) : @@ -662,6 +743,11 @@ theorem prod_mul_distrib : ∏ x in s, f x * g x = (∏ x in s, f x) * ∏ x in #align finset.prod_mul_distrib Finset.prod_mul_distrib #align finset.sum_add_distrib Finset.sum_add_distrib +@[to_additive] +lemma prod_mul_prod_comm (f g h i : α → β) : + (∏ a in s, f a * g a) * ∏ a in s, h a * i a = (∏ a in s, f a * h a) * ∏ a in s, g a * i a := by + simp_rw [prod_mul_distrib, mul_mul_mul_comm] + @[to_additive] theorem prod_product {s : Finset γ} {t : Finset α} {f : γ × α → β} : ∏ x in s ×ˢ t, f x = ∏ x in s, ∏ y in t, f (x, y) := @@ -807,6 +893,16 @@ theorem prod_eq_single {s : Finset α} {f : α → β} (a : α) (h₀ : ∀ b #align finset.prod_eq_single Finset.prod_eq_single #align finset.sum_eq_single Finset.sum_eq_single +@[to_additive] +lemma prod_union_eq_left [DecidableEq α] (hs : ∀ a ∈ s₂, a ∉ s₁ → f a = 1) : + ∏ a in s₁ ∪ s₂, f a = ∏ a in s₁, f a := + Eq.symm $ + prod_subset (subset_union_left _ _) fun _a ha ha' ↦ hs _ ((mem_union.1 ha).resolve_left ha') ha' + +@[to_additive] +lemma prod_union_eq_right [DecidableEq α] (hs : ∀ a ∈ s₁, a ∉ s₂ → f a = 1) : + ∏ a in s₁ ∪ s₂, f a = ∏ a in s₂, f a := by rw [union_comm, prod_union_eq_left hs] + @[to_additive] theorem prod_eq_mul_of_mem {s : Finset α} {f : α → β} (a b : α) (ha : a ∈ s) (hb : b ∈ s) (hn : a ≠ b) (h₀ : ∀ c ∈ s, c ≠ a ∧ c ≠ b → f c = 1) : ∏ x in s, f x = f a * f b := by @@ -851,7 +947,7 @@ theorem prod_eq_mul {s : Finset α} {f : α → β} (a b : α) (hn : a ≠ b) #align finset.sum_eq_add Finset.sum_eq_add @[to_additive] -theorem prod_attach {f : α → β} : ∏ x in s.attach, f x = ∏ x in s, f x := +theorem prod_attach (s : Finset α) (f : α → β) : ∏ x in s.attach, f x = ∏ x in s, f x := haveI := Classical.decEq α calc ∏ x in s.attach, f x.val = ∏ x in s.attach.image Subtype.val, f x := by @@ -905,8 +1001,7 @@ theorem prod_coe_sort_eq_attach (f : s → β) : ∏ i : s, f i = ∏ i in s.att #align finset.sum_coe_sort_eq_attach Finset.sum_coe_sort_eq_attach @[to_additive] -theorem prod_coe_sort : ∏ i : s, f i = ∏ i in s, f i := - prod_attach +theorem prod_coe_sort : ∏ i : s, f i = ∏ i in s, f i := prod_attach _ _ #align finset.prod_coe_sort Finset.prod_coe_sort #align finset.sum_coe_sort Finset.sum_coe_sort @@ -964,7 +1059,7 @@ theorem prod_apply_dite {s : Finset α} {p : α → Prop} {hp : DecidablePred p} (prod_filter_mul_prod_filter_not s p _).symm _ = (∏ x in (s.filter p).attach, h (if hx : p x.1 then f x.1 hx else g x.1 hx)) * ∏ x in (s.filter fun x => ¬p x).attach, h (if hx : p x.1 then f x.1 hx else g x.1 hx) := - congr_arg₂ _ prod_attach.symm prod_attach.symm + congr_arg₂ _ (prod_attach _ _).symm (prod_attach _ _).symm _ = (∏ x in (s.filter p).attach, h (f x.1 $ by simpa using (mem_filter.mp x.2).2)) * ∏ x in (s.filter fun x ↦ ¬p x).attach, h (g x.1 $ by simpa using (mem_filter.mp x.2).2) := congr_arg₂ _ (prod_congr rfl fun x _hx ↦ @@ -978,8 +1073,7 @@ theorem prod_apply_ite {s : Finset α} {p : α → Prop} {_hp : DecidablePred p} (h : γ → β) : (∏ x in s, h (if p x then f x else g x)) = (∏ x in s.filter p, h (f x)) * ∏ x in s.filter fun x => ¬p x, h (g x) := - _root_.trans (prod_apply_dite _ _ _) - (congr_arg₂ _ (@prod_attach _ _ _ _ (h ∘ f)) (@prod_attach _ _ _ _ (h ∘ g))) + (prod_apply_dite _ _ _).trans $ congr_arg₂ _ (prod_attach _ (h ∘ f)) (prod_attach _ (h ∘ g)) #align finset.prod_apply_ite Finset.prod_apply_ite #align finset.sum_apply_ite Finset.sum_apply_ite @@ -1192,6 +1286,11 @@ lemma prod_mulIndicator_eq_prod_filter (s : Finset ι) (f : ι → κ → β) (t #align finset.prod_mul_indicator_eq_prod_filter Finset.prod_mulIndicator_eq_prod_filter #align finset.sum_indicator_eq_sum_filter Finset.sum_indicator_eq_sum_filter +@[to_additive] +lemma prod_mulIndicator_eq_prod_inter [DecidableEq ι] (s t : Finset ι) (f : ι → β) : + ∏ i in s, (t : Set ι).mulIndicator f i = ∏ i in s ∩ t, f i := by + rw [← filter_mem_eq_inter, prod_mulIndicator_eq_prod_filter]; rfl + @[to_additive] lemma mulIndicator_prod (s : Finset ι) (t : Set κ) (f : ι → κ → β) : mulIndicator t (∏ i in s, f i) = ∏ i in s, mulIndicator t (f i) := @@ -1227,8 +1326,8 @@ end indicator @[to_additive] theorem prod_bij_ne_one {s : Finset α} {t : Finset γ} {f : α → β} {g : γ → β} (i : ∀ a ∈ s, f a ≠ 1 → γ) (hi : ∀ a h₁ h₂, i a h₁ h₂ ∈ t) - (i_inj : ∀ a₁ a₂ h₁₁ h₁₂ h₂₁ h₂₂, i a₁ h₁₁ h₁₂ = i a₂ h₂₁ h₂₂ → a₁ = a₂) - (i_surj : ∀ b ∈ t, g b ≠ 1 → ∃ a h₁ h₂, b = i a h₁ h₂) (h : ∀ a h₁ h₂, f a = g (i a h₁ h₂)) : + (i_inj : ∀ a₁ h₁₁ h₁₂ a₂ h₂₁ h₂₂, i a₁ h₁₁ h₁₂ = i a₂ h₂₁ h₂₂ → a₁ = a₂) + (i_surj : ∀ b ∈ t, g b ≠ 1 → ∃ a h₁ h₂, i a h₁ h₂ = b) (h : ∀ a h₁ h₂, f a = g (i a h₁ h₂)) : ∏ x in s, f x = ∏ x in t, g x := by classical calc @@ -1243,9 +1342,7 @@ theorem prod_bij_ne_one {s : Finset α} {t : Finset γ} {f : α → β} {g : γ refine (mem_filter.mpr ⟨hi a h₁ _, ?_⟩) specialize h a h₁ fun H ↦ by rw [H] at h₂; simp at h₂ rwa [← h] - · refine' (fun a ha => (mem_filter.mp ha).elim fun h₁ h₂ ↦ _) - exact h a h₁ fun H ↦ by rw [H] at h₂; simp at h₂ - · intros a₁ a₂ ha₁ ha₂ + · intros a₁ ha₁ a₂ ha₂ refine' (mem_filter.mp ha₁).elim fun _ha₁₁ _ha₁₂ ↦ _ refine' (mem_filter.mp ha₂).elim fun _ha₂₁ _ha₂₂ ↦ _ apply i_inj @@ -1253,30 +1350,24 @@ theorem prod_bij_ne_one {s : Finset α} {t : Finset γ} {f : α → β} {g : γ refine' (mem_filter.mp hb).elim fun h₁ h₂ ↦ _ obtain ⟨a, ha₁, ha₂, eq⟩ := i_surj b h₁ fun H ↦ by rw [H] at h₂; simp at h₂ exact ⟨a, mem_filter.mpr ⟨ha₁, ha₂⟩, eq⟩ + · refine' (fun a ha => (mem_filter.mp ha).elim fun h₁ h₂ ↦ _) + exact h a h₁ fun H ↦ by rw [H] at h₂; simp at h₂ #align finset.prod_bij_ne_one Finset.prod_bij_ne_one #align finset.sum_bij_ne_zero Finset.sum_bij_ne_zero @[to_additive] theorem prod_dite_of_false {p : α → Prop} {hp : DecidablePred p} (h : ∀ x ∈ s, ¬p x) (f : ∀ x : α, p x → β) (g : ∀ x : α, ¬p x → β) : - ∏ x in s, (if hx : p x then f x hx else g x hx) = ∏ x : s, g x.val (h x.val x.property) := - prod_bij (fun x hx => ⟨x, hx⟩) (fun x hx => by simp) - (fun a ha => by - dsimp - rw [dif_neg]) - (fun a₁ a₂ h₁ h₂ hh => congr_arg Subtype.val hh) fun b _hb => ⟨b.1, b.2, by simp⟩ + ∏ x in s, (if hx : p x then f x hx else g x hx) = ∏ x : s, g x.val (h x.val x.property) := by + refine prod_bij' (fun x hx => ⟨x, hx⟩) (fun x _ ↦ x) ?_ ?_ ?_ ?_ ?_ <;> aesop #align finset.prod_dite_of_false Finset.prod_dite_of_false #align finset.sum_dite_of_false Finset.sum_dite_of_false @[to_additive] theorem prod_dite_of_true {p : α → Prop} {hp : DecidablePred p} (h : ∀ x ∈ s, p x) (f : ∀ x : α, p x → β) (g : ∀ x : α, ¬p x → β) : - ∏ x in s, (if hx : p x then f x hx else g x hx) = ∏ x : s, f x.val (h x.val x.property) := - prod_bij (fun x hx => ⟨x, hx⟩) (fun x hx => by simp) - (fun a ha => by - dsimp - rw [dif_pos]) - (fun a₁ a₂ h₁ h₂ hh => congr_arg Subtype.val hh) fun b _hb => ⟨b.1, b.2, by simp⟩ + ∏ x in s, (if hx : p x then f x hx else g x hx) = ∏ x : s, f x.val (h x.val x.property) := by + refine prod_bij' (fun x hx => ⟨x, hx⟩) (fun x _ ↦ x) ?_ ?_ ?_ ?_ ?_ <;> aesop #align finset.prod_dite_of_true Finset.prod_dite_of_true #align finset.sum_dite_of_true Finset.sum_dite_of_true @@ -1429,12 +1520,9 @@ theorem prod_multiset_count_of_subset [DecidableEq α] [CommMonoid α] (m : Mult @[to_additive] theorem prod_mem_multiset [DecidableEq α] (m : Multiset α) (f : { x // x ∈ m } → β) (g : α → β) - (hfg : ∀ x, f x = g x) : ∏ x : { x // x ∈ m }, f x = ∏ x in m.toFinset, g x := - prod_bij (fun x _ => x.1) (fun x _ => Multiset.mem_toFinset.mpr x.2) (fun _ _ => hfg _) - (fun _ _ _ _ h => by - ext - assumption) - fun y hy => ⟨⟨y, Multiset.mem_toFinset.mp hy⟩, Finset.mem_univ _, rfl⟩ + (hfg : ∀ x, f x = g x) : ∏ x : { x // x ∈ m }, f x = ∏ x in m.toFinset, g x := by + refine' prod_bij' (fun x _ ↦ x) (fun x hx ↦ ⟨x, Multiset.mem_toFinset.1 hx⟩) ?_ ?_ ?_ ?_ ?_ <;> + simp [hfg] #align finset.prod_mem_multiset Finset.prod_mem_multiset #align finset.sum_mem_multiset Finset.sum_mem_multiset @@ -1618,20 +1706,8 @@ theorem prod_involution {s : Finset α} {f : α → β} : @[to_additive "The sum of the composition of functions `f` and `g`, is the sum over `b ∈ s.image g` of `f b` times of the cardinality of the fibre of `b`. See also `Finset.sum_image`."] theorem prod_comp [DecidableEq γ] (f : γ → β) (g : α → γ) : - (∏ a in s, f (g a)) = ∏ b in s.image g, f b ^ (s.filter fun a => g a = b).card := - calc - (∏ a in s, f (g a)) = - ∏ x in (s.image g).sigma fun b : γ => s.filter fun a => g a = b, f (g x.2) := - prod_bij (fun a _ha => ⟨g a, a⟩) (by simp; tauto) (fun _ _ => rfl) (by simp) - (by -- `(by finish)` closes this - rintro ⟨b_fst, b_snd⟩ H - simp only [mem_image, exists_prop, mem_filter, mem_sigma, decide_eq_true_eq] at H - tauto) - _ = ∏ b in s.image g, ∏ a in s.filter fun a => g a = b, f (g a) := prod_sigma _ _ _ - _ = ∏ b in s.image g, ∏ _a in s.filter fun a => g a = b, f b := - prod_congr rfl fun b _hb => prod_congr rfl (by simp (config := { contextual := true })) - _ = ∏ b in s.image g, f b ^ (s.filter fun a => g a = b).card := - prod_congr rfl fun _ _ => prod_const _ + ∏ a in s, f (g a) = ∏ b in s.image g, f b ^ (s.filter fun a => g a = b).card := by + simp_rw [← prod_const, prod_fiberwise_of_maps_to' fun _ ↦ mem_image_of_mem _] #align finset.prod_comp Finset.prod_comp #align finset.sum_comp Finset.sum_comp @@ -1782,12 +1858,13 @@ theorem prod_erase [DecidableEq α] (s : Finset α) {f : α → β} {a : α} (h /-- See also `Finset.prod_boole`. -/ @[to_additive "See also `Finset.sum_boole`."] -theorem prod_ite_one {f : α → Prop} [DecidablePred f] (hf : (s : Set α).PairwiseDisjoint f) - (a : β) : (∏ i in s, ite (f i) a 1) = ite (∃ i ∈ s, f i) a 1 := by +theorem prod_ite_one (s : Finset α) (p : α → Prop) [DecidablePred p] + (h : ∀ i ∈ s, ∀ j ∈ s, p i → p j → i = j) (a : β) : + ∏ i in s, ite (p i) a 1 = ite (∃ i ∈ s, p i) a 1 := by split_ifs with h - · obtain ⟨i, hi, hfi⟩ := h - rw [prod_eq_single_of_mem _ hi, if_pos hfi] - exact fun j hj h => if_neg fun hfj => (hf hj hi h).le_bot ⟨hfj, hfi⟩ + · obtain ⟨i, hi, hpi⟩ := h + rw [prod_eq_single_of_mem _ hi, if_pos hpi] + exact fun j hj hji ↦ if_neg fun hpj ↦ hji $ h _ hj _ hi hpj hpi · push_neg at h rw [prod_eq_one] exact fun i hi => if_neg (h i hi) @@ -2086,6 +2163,7 @@ theorem prod_int_mod (s : Finset α) (n : ℤ) (f : α → ℤ) : end Finset namespace Fintype +variable {ι κ α : Type*} [Fintype ι] [Fintype κ] [CommMonoid α] open Finset @@ -2096,17 +2174,13 @@ See `Function.Bijective.prod_comp` for a version without `h`. -/ `Function.Bijective`. See `Function.Bijective.sum_comp` for a version without `h`. "] -theorem prod_bijective {α β M : Type*} [Fintype α] [Fintype β] [CommMonoid M] (e : α → β) - (he : Function.Bijective e) (f : α → M) (g : β → M) (h : ∀ x, f x = g (e x)) : - ∏ x : α, f x = ∏ x : β, g x := - prod_bij (fun x _ => e x) (fun x _ => mem_univ (e x)) (fun x _ => h x) - (fun _x _x' _ _ h => he.injective h) fun y _ => - (he.surjective y).imp fun _a h => ⟨mem_univ _, h.symm⟩ +lemma prod_bijective (e : ι → κ) (he : e.Bijective) (f : ι → α) (g : κ → α) + (h : ∀ x, f x = g (e x)) : ∏ x, f x = ∏ x, g x := + prod_equiv (.ofBijective e he) (by simp) (by simp [h]) #align fintype.prod_bijective Fintype.prod_bijective #align fintype.sum_bijective Fintype.sum_bijective -alias _root_.Function.Bijective.finset_prod := prod_bijective -attribute [to_additive] Function.Bijective.finset_prod +@[to_additive] alias _root_.Function.Bijective.finset_prod := prod_bijective /-- `Fintype.prod_equiv` is a specialization of `Finset.prod_bij` that automatically fills in most arguments. @@ -2117,12 +2191,39 @@ See `Equiv.prod_comp` for a version without `h`. automatically fills in most arguments. See `Equiv.sum_comp` for a version without `h`."] -theorem prod_equiv {α β M : Type*} [Fintype α] [Fintype β] [CommMonoid M] (e : α ≃ β) (f : α → M) - (g : β → M) (h : ∀ x, f x = g (e x)) : ∏ x : α, f x = ∏ x : β, g x := - e.bijective.finset_prod _ f g h +lemma prod_equiv (e : ι ≃ κ) (f : ι → α) (g : κ → α) (h : ∀ x, f x = g (e x)) : + ∏ x, f x = ∏ x, g x := prod_bijective _ e.bijective _ _ h #align fintype.prod_equiv Fintype.prod_equiv #align fintype.sum_equiv Fintype.sum_equiv +@[to_additive] +lemma _root_.Function.Bijective.prod_comp {e : ι → κ} (he : e.Bijective) (g : κ → α) : + ∏ i, g (e i) = ∏ i, g i := prod_bijective _ he _ _ fun _ ↦ rfl +#align function.bijective.prod_comp Function.Bijective.prod_comp +#align function.bijective.sum_comp Function.Bijective.sum_comp + +@[to_additive] +lemma _root_.Equiv.prod_comp (e : ι ≃ κ) (g : κ → α) : ∏ i, g (e i) = ∏ i, g i := + prod_equiv e _ _ fun _ ↦ rfl +#align equiv.prod_comp Equiv.prod_comp +#align equiv.sum_comp Equiv.sum_comp + +@[to_additive] +lemma prod_fiberwise [DecidableEq κ] [Fintype ι] (g : ι → κ) (f : ι → α) : + ∏ j, ∏ i : {i // g i = j}, f i = ∏ i, f i := by + rw [← Finset.prod_fiberwise _ g f] + congr with j + exact (prod_subtype _ (by simp) _).symm +#align fintype.prod_fiberwise Fintype.prod_fiberwise +#align fintype.sum_fiberwise Fintype.sum_fiberwise + +@[to_additive] +lemma prod_fiberwise' [DecidableEq κ] [Fintype ι] (g : ι → κ) (f : κ → α) : + ∏ j, ∏ _i : {i // g i = j}, f j = ∏ i, f (g i) := by + rw [← Finset.prod_fiberwise' _ g f] + congr with j + exact (prod_subtype _ (by simp) fun _ ↦ _).symm + @[to_additive] theorem prod_unique {α β : Type*} [CommMonoid β] [Unique α] [Fintype α] (f : α → β) : ∏ x : α, f x = f default := by rw [univ_unique, prod_singleton] @@ -2491,3 +2592,12 @@ theorem toAdd_prod (s : Finset ι) (f : ι → Multiplicative α) : #align to_add_prod toAdd_prod end AddCommMonoid + +/-! +### Deprecated lemmas + +Those lemmas were deprecated on the 2023/12/23. +-/ + +@[deprecated] alias Equiv.prod_comp' := Fintype.prod_equiv +@[deprecated] alias Equiv.sum_comp' := Fintype.sum_equiv diff --git a/Mathlib/Algebra/BigOperators/Finprod.lean b/Mathlib/Algebra/BigOperators/Finprod.lean index de4c32ff727b3..15d5f5e1c8fe2 100644 --- a/Mathlib/Algebra/BigOperators/Finprod.lean +++ b/Mathlib/Algebra/BigOperators/Finprod.lean @@ -1240,14 +1240,10 @@ theorem finprod_mem_finset_product' [DecidableEq α] [DecidableEq β] (s : Finse (f : α × β → M) : (∏ᶠ (ab) (_ : ab ∈ s), f ab) = ∏ᶠ (a) (b) (_ : b ∈ (s.filter fun ab => Prod.fst ab = a).image Prod.snd), f (a, b) := by - have : - ∀ a, - (∏ i : β in (s.filter fun ab => Prod.fst ab = a).image Prod.snd, f (a, i)) = - (Finset.filter (fun ab => Prod.fst ab = a) s).prod f := by - refine' fun a => Finset.prod_bij (fun b _ => (a, b)) _ _ _ _ <;> simp - suffices ∀ a' b, (a', b) ∈ s → a' = a → (a, b) ∈ s ∧ a' = a by simpa - rintro a' b hp rfl - exact ⟨hp, rfl⟩ + have (a) : + ∏ i in (s.filter fun ab => Prod.fst ab = a).image Prod.snd, f (a, i) = + (s.filter (Prod.fst · = a)).prod f := by + refine Finset.prod_nbij' (fun b ↦ (a, b)) Prod.snd ?_ ?_ ?_ ?_ ?_ <;> aesop rw [finprod_mem_finset_eq_prod] simp_rw [finprod_mem_finset_eq_prod, this] rw [finprod_eq_prod_of_mulSupport_subset _ diff --git a/Mathlib/Algebra/BigOperators/Finsupp.lean b/Mathlib/Algebra/BigOperators/Finsupp.lean index 316ee175939b6..6abd5300cd09d 100644 --- a/Mathlib/Algebra/BigOperators/Finsupp.lean +++ b/Mathlib/Algebra/BigOperators/Finsupp.lean @@ -645,7 +645,7 @@ lemma indicator_eq_sum_attach_single [AddCommMonoid M] {s : Finset α} (f : ∀ lemma indicator_eq_sum_single [AddCommMonoid M] (s : Finset α) (f : α → M) : indicator s (fun x _ ↦ f x) = ∑ x in s, single x (f x) := - (indicator_eq_sum_attach_single _).trans <| sum_attach (f := fun x ↦ single x (f x)) + (indicator_eq_sum_attach_single _).trans <| sum_attach _ fun x ↦ single x (f x) @[to_additive (attr := simp)] lemma prod_indicator_index_eq_prod_attach [Zero M] [CommMonoid N] @@ -661,7 +661,7 @@ lemma prod_indicator_index_eq_prod_attach [Zero M] [CommMonoid N] lemma prod_indicator_index [Zero M] [CommMonoid N] {s : Finset α} (f : α → M) {h : α → M → N} (h_zero : ∀ a ∈ s, h a 0 = 1) : (indicator s (fun x _ ↦ f x)).prod h = ∏ x in s, h x (f x) := - (prod_indicator_index_eq_prod_attach _ h_zero).trans <| prod_attach (f := fun x ↦ h x (f x)) + (prod_indicator_index_eq_prod_attach _ h_zero).trans <| prod_attach _ fun x ↦ h x (f x) lemma sum_cons [AddCommMonoid M] (n : ℕ) (σ : Fin n →₀ M) (i : M) : (sum (cons i σ) fun _ e ↦ e) = i + sum σ (fun _ e ↦ e) := by diff --git a/Mathlib/Algebra/BigOperators/Intervals.lean b/Mathlib/Algebra/BigOperators/Intervals.lean index f661f602e41d8..7568f0062b5df 100644 --- a/Mathlib/Algebra/BigOperators/Intervals.lean +++ b/Mathlib/Algebra/BigOperators/Intervals.lean @@ -123,10 +123,8 @@ theorem sum_Ico_Ico_comm {M : Type*} [AddCommMonoid M] (a b : ℕ) (f : ℕ → (∑ i in Finset.Ico a b, ∑ j in Finset.Ico i b, f i j) = ∑ j in Finset.Ico a b, ∑ i in Finset.Ico a (j + 1), f i j := by rw [Finset.sum_sigma', Finset.sum_sigma'] - refine' - Finset.sum_bij' (fun (x : Σ _ : ℕ, ℕ) _ => (⟨x.2, x.1⟩ : Σ _ : ℕ, ℕ)) _ (fun _ _ => rfl) - (fun (x : Σ _ : ℕ, ℕ) _ => (⟨x.2, x.1⟩ : Σ _ : ℕ, ℕ)) _ (by (rintro ⟨⟩ _; rfl)) - (by (rintro ⟨⟩ _; rfl)) <;> + refine' sum_nbij' (fun x ↦ ⟨x.2, x.1⟩) (fun x ↦ ⟨x.2, x.1⟩) _ _ (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) + (fun _ _ ↦ rfl) <;> simp only [Finset.mem_Ico, Sigma.forall, Finset.mem_sigma] <;> rintro a b ⟨⟨h₁, h₂⟩, ⟨h₃, h₄⟩⟩ <;> refine' ⟨⟨_, _⟩, ⟨_, _⟩⟩ <;> diff --git a/Mathlib/Algebra/BigOperators/Ring.lean b/Mathlib/Algebra/BigOperators/Ring.lean index 8019d55d222ed..a49c66756c97f 100644 --- a/Mathlib/Algebra/BigOperators/Ring.lean +++ b/Mathlib/Algebra/BigOperators/Ring.lean @@ -140,23 +140,18 @@ theorem prod_add [DecidableEq α] (f g : α → β) (s : Finset α) : prod_sum _ = ∑ t in s.powerset, (∏ a in t, f a) * ∏ a in s \ t, g a := sum_bij' - (fun f _ => s.filter (fun a => ∀ h : a ∈ s, f a h)) - (by simp) - (fun a _ => by - rw [prod_ite] - congr 1 - exact prod_bij' - (fun a _ => a.1) (by simp) (by simp) - (fun a ha => ⟨a, (mem_filter.1 ha).1⟩) (fun a ha => by simp at ha; simp; tauto) - (by simp) (by simp) - exact prod_bij' - (fun a _ => a.1) (by simp) (by simp) - (fun a ha => ⟨a, (mem_sdiff.1 ha).1⟩) (fun a ha => by simp at ha; simp; tauto) - (by simp) (by simp)) + (fun f _ ↦ s.filter fun a ↦ ∃ h : a ∈ s, f a h) (fun t _ a _ => a ∈ t) + (by simp) (by simp [Classical.em]) (by simp_rw [mem_filter, Function.funext_iff, eq_iff_iff, mem_pi, mem_insert]; tauto) (by simp_rw [ext_iff, @mem_filter _ _ (id _), mem_powerset]; tauto) + (fun a _ ↦ by + simp only [prod_ite, filter_attach', prod_map, Function.Embedding.coeFn_mk, + Subtype.map_coe, id_eq, prod_attach, filter_congr_decidable] + congr 2 with x + simp only [mem_filter, mem_sdiff, not_and, not_exists, and_congr_right_iff] + tauto) #align finset.prod_add Finset.prod_add /-- `∏ i, (f i + g i) = (∏ i, f i) + ∑ i, g i * (∏ j < i, f j + g j) * (∏ j > i, f j)`. -/ diff --git a/Mathlib/Algebra/Tropical/BigOperators.lean b/Mathlib/Algebra/Tropical/BigOperators.lean index 51b829e2861c8..738e54e3af19a 100644 --- a/Mathlib/Algebra/Tropical/BigOperators.lean +++ b/Mathlib/Algebra/Tropical/BigOperators.lean @@ -142,5 +142,5 @@ theorem untrop_sum [ConditionallyCompleteLinearOrder R] [Fintype S] (f : S → T as it is simply not true on conditionally complete lattices! -/ theorem Finset.untrop_sum [ConditionallyCompleteLinearOrder R] (s : Finset S) (f : S → Tropical (WithTop R)) : untrop (∑ i in s, f i) = ⨅ i : s, untrop (f i) := by - simpa [← _root_.untrop_sum] using sum_attach.symm + simpa [← _root_.untrop_sum] using (sum_attach _ _).symm #align finset.untrop_sum Finset.untrop_sum diff --git a/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean b/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean index 47acaa261eed2..b84b183ea8ca6 100644 --- a/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean +++ b/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean @@ -90,17 +90,8 @@ theorem d_squared (n : ℕ) : objD X (n + 1) ≫ objD X n = 0 := by simp only [Finset.mem_univ, Finset.compl_filter, Finset.mem_filter, true_and_iff, Fin.val_succ, Fin.coe_castLT] at hij ⊢ linarith - · -- identification of corresponding terms in both sums - rintro ⟨i, j⟩ hij - dsimp - simp only [zsmul_comp, comp_zsmul, smul_smul, ← neg_smul] - congr 1 - · simp only [Fin.val_succ, pow_add, pow_one, mul_neg, neg_neg, mul_one] - apply mul_comm - · rw [CategoryTheory.SimplicialObject.δ_comp_δ''] - simpa using hij · -- φ : S → Sᶜ is injective - rintro ⟨i, j⟩ ⟨i', j'⟩ hij hij' h + rintro ⟨i, j⟩ hij ⟨i', j'⟩ hij' h rw [Prod.mk.inj_iff] exact ⟨by simpa using congr_arg Prod.snd h, by simpa [Fin.castSucc_castLT] using congr_arg Fin.castSucc (congr_arg Prod.fst h)⟩ @@ -114,6 +105,15 @@ theorem d_squared (n : ℕ) : objD X (n + 1) ≫ objD X n = 0 := by · simpa only [Finset.mem_univ, forall_true_left, Prod.forall, ge_iff_le, Finset.mem_filter, Fin.coe_castSucc, Fin.coe_pred, true_and] using Nat.le_sub_one_of_lt hij' · simp only [Fin.castLT_castSucc, Fin.succ_pred] + · -- identification of corresponding terms in both sums + rintro ⟨i, j⟩ hij + dsimp + simp only [zsmul_comp, comp_zsmul, smul_smul, ← neg_smul] + congr 1 + · simp only [Fin.val_succ, pow_add, pow_one, mul_neg, neg_neg, mul_one] + apply mul_comm + · rw [CategoryTheory.SimplicialObject.δ_comp_δ''] + simpa using hij #align algebraic_topology.alternating_face_map_complex.d_squared AlgebraicTopology.AlternatingFaceMapComplex.d_squared /-! diff --git a/Mathlib/Analysis/Analytic/Composition.lean b/Mathlib/Analysis/Analytic/Composition.lean index 8a8945c8e29a6..bdce464db1ce0 100644 --- a/Mathlib/Analysis/Analytic/Composition.lean +++ b/Mathlib/Analysis/Analytic/Composition.lean @@ -616,7 +616,7 @@ def compPartialSumTargetSet (m M N : ℕ) : Set (Σ n, Composition n) := theorem compPartialSumTargetSet_image_compPartialSumSource (m M N : ℕ) (i : Σ n, Composition n) (hi : i ∈ compPartialSumTargetSet m M N) : - ∃ (j : _) (hj : j ∈ compPartialSumSource m M N), i = compChangeOfVariables m M N j hj := by + ∃ (j : _) (hj : j ∈ compPartialSumSource m M N), compChangeOfVariables m M N j hj = i := by rcases i with ⟨n, c⟩ refine' ⟨⟨c.length, c.blocksFun⟩, _, _⟩ · simp only [compPartialSumTargetSet, Set.mem_setOf_eq] at hi @@ -625,7 +625,7 @@ theorem compPartialSumTargetSet_image_compPartialSumSource (m M N : ℕ) · dsimp [compChangeOfVariables] rw [Composition.sigma_eq_iff_blocks_eq] simp only [Composition.blocksFun, Composition.blocks, Subtype.coe_eta, List.get_map] - conv_lhs => rw [← List.ofFn_get c.blocks] + conv_rhs => rw [← List.ofFn_get c.blocks] #align formal_multilinear_series.comp_partial_sum_target_subset_image_comp_partial_sum_source FormalMultilinearSeries.compPartialSumTargetSet_image_compPartialSumSource /-- Target set in the change of variables to compute the composition of partial sums of formal @@ -665,11 +665,8 @@ theorem compChangeOfVariables_sum {α : Type*} [AddCommMonoid α] (m M N : ℕ) map_ofFn, length_ofFn, true_and_iff, compChangeOfVariables] intro j simp only [Composition.blocksFun, (H.right _).right, List.get_ofFn] - -- 2 - show that the composition gives the `comp_along_composition` application - · rintro ⟨k, blocks_fun⟩ H - rw [h] - -- 3 - show that the map is injective - · rintro ⟨k, blocks_fun⟩ ⟨k', blocks_fun'⟩ H H' heq + -- 2 - show that the map is injective + · rintro ⟨k, blocks_fun⟩ H ⟨k', blocks_fun'⟩ H' heq obtain rfl : k = k' := by have := (compChangeOfVariables_length m M N H).symm rwa [heq, compChangeOfVariables_length] at this @@ -682,10 +679,13 @@ theorem compChangeOfVariables_sum {α : Type*} [AddCommMonoid α] (m M N : ℕ) apply Composition.blocksFun_congr <;> first | rw [heq] | rfl _ = blocks_fun' i := compChangeOfVariables_blocksFun m M N H' i - -- 4 - show that the map is surjective + -- 3 - show that the map is surjective · intro i hi apply compPartialSumTargetSet_image_compPartialSumSource m M N i simpa [compPartialSumTarget] using hi + -- 4 - show that the composition gives the `comp_along_composition` application + · rintro ⟨k, blocks_fun⟩ H + rw [h] #align formal_multilinear_series.comp_change_of_variables_sum FormalMultilinearSeries.compChangeOfVariables_sum /-- The auxiliary set corresponding to the composition of partial sums asymptotically contains diff --git a/Mathlib/Combinatorics/Configuration.lean b/Mathlib/Combinatorics/Configuration.lean index b798e25edacf1..85825f46b961f 100644 --- a/Mathlib/Combinatorics/Configuration.lean +++ b/Mathlib/Combinatorics/Configuration.lean @@ -35,7 +35,8 @@ Together, these four statements say that any two of the following properties imp -/ -open BigOperators +open Finset +open scoped BigOperators namespace Configuration @@ -234,17 +235,11 @@ theorem HasLines.card_le [HasLines P L] [Fintype P] [Fintype L] : ∑ p, lineCount L p = ∑ l, pointCount P l := sum_lineCount_eq_sum_pointCount P L _ ≤ ∑ l, lineCount L (f l) := (Finset.sum_le_sum fun l _ => HasLines.pointCount_le_lineCount (hf₂ l)) - _ = ∑ p in Finset.univ.image f, lineCount L p := - (Finset.sum_bij (fun l _ => f l) (fun l hl => Finset.mem_image_of_mem f hl) - (fun l _ => rfl) (fun l₁ l₂ hl₁ hl₂ hl₃ => hf₁ hl₃) fun p => by - rw [Finset.mem_image] - exact fun ⟨a, ⟨h, h'⟩⟩ => ⟨a, ⟨h, h'.symm⟩⟩) + _ = ∑ p in univ.map ⟨f, hf₁⟩, lineCount L p := by rw [sum_map]; dsimp _ < ∑ p, lineCount L p := by obtain ⟨p, hp⟩ := not_forall.mp (mt (Fintype.card_le_of_surjective f) hc₂) - refine' - Finset.sum_lt_sum_of_subset (Finset.univ.image f).subset_univ (Finset.mem_univ p) _ _ - fun p _ _ => zero_le (lineCount L p) - · simpa only [Finset.mem_image, exists_prop, Finset.mem_univ, true_and_iff] + refine sum_lt_sum_of_subset (subset_univ _) (mem_univ p) ?_ ?_ fun p _ _ ↦ zero_le _ + · simpa only [Finset.mem_map, exists_prop, Finset.mem_univ, true_and_iff] · rw [lineCount, Nat.card_eq_fintype_card, Fintype.card_pos_iff] obtain ⟨l, _⟩ := @exists_line P L _ _ p exact @@ -267,16 +262,8 @@ theorem HasLines.exists_bijective_of_card_eq [HasLines P L] [Fintype P] [Fintype classical obtain ⟨f, hf1, hf2⟩ := Nondegenerate.exists_injective_of_card_le (ge_of_eq h) have hf3 := (Fintype.bijective_iff_injective_and_card f).mpr ⟨hf1, h.symm⟩ - refine' - ⟨f, hf3, fun l => - (Finset.sum_eq_sum_iff_of_le fun l _ => HasLines.pointCount_le_lineCount (hf2 l)).mp - ((sum_lineCount_eq_sum_pointCount P L).symm.trans - (Finset.sum_bij (fun l _ => f l) (fun l _ => Finset.mem_univ (f l)) - (fun l _ => refl (lineCount L (f l))) (fun l₁ l₂ hl₁ hl₂ hl => hf1 hl) fun p hp => - _).symm) - l (Finset.mem_univ l)⟩ - obtain ⟨l, rfl⟩ := hf3.2 p - exact ⟨l, Finset.mem_univ l, rfl⟩ + exact ⟨f, hf3, fun l ↦ (sum_eq_sum_iff_of_le fun l _ ↦ pointCount_le_lineCount (hf2 l)).1 + ((hf3.sum_comp _).trans (sum_lineCount_eq_sum_pointCount P L)).symm _ $ mem_univ _⟩ #align configuration.has_lines.exists_bijective_of_card_eq Configuration.HasLines.exists_bijective_of_card_eq theorem HasLines.lineCount_eq_pointCount [HasLines P L] [Fintype P] [Fintype L] @@ -290,15 +277,11 @@ theorem HasLines.lineCount_eq_pointCount [HasLines P L] [Fintype P] [Fintype L] simp_rw [Finset.sum_const, Finset.card_univ, hPL, sum_lineCount_eq_sum_pointCount] have step2 : ∑ i in s, lineCount L i.1 = ∑ i in s, pointCount P i.2 := by rw [s.sum_finset_product Finset.univ fun p => Set.toFinset { l | p ∈ l }] - rw [s.sum_finset_product_right Finset.univ fun l => Set.toFinset { p | p ∈ l }] - refine' - (Finset.sum_bij (fun l _ => f l) (fun l _ => Finset.mem_univ (f l)) (fun l hl => _) - (fun _ _ _ _ h => hf1.1 h) fun p _ => _).symm - · simp_rw [Finset.sum_const, Set.toFinset_card, ← Nat.card_eq_fintype_card] - change pointCount P l • pointCount P l = lineCount L (f l) • lineCount L (f l) - rw [hf2] - · obtain ⟨l, hl⟩ := hf1.2 p - exact ⟨l, Finset.mem_univ l, hl.symm⟩ + rw [s.sum_finset_product_right Finset.univ fun l => Set.toFinset { p | p ∈ l }, eq_comm] + refine sum_bijective _ hf1 (by simp) fun l _ ↦ ?_ + simp_rw [hf2, sum_const, Set.toFinset_card, ← Nat.card_eq_fintype_card] + change pointCount P l • _ = lineCount L (f l) • _ + rw [hf2] all_goals simp_rw [Finset.mem_univ, true_and_iff, Set.mem_toFinset]; exact fun p => Iff.rfl have step3 : ∑ i in sᶜ, lineCount L i.1 = ∑ i in sᶜ, pointCount P i.2 := by rwa [← s.sum_add_sum_compl, ← s.sum_add_sum_compl, step2, add_left_cancel_iff] at step1 diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index 94daa0ee28250..22c0b65c9f658 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -187,31 +187,12 @@ theorem sum_range_diag_flip {α : Type*} [AddCommMonoid α] (n : ℕ) (f : ℕ (∑ m in range n, ∑ k in range (m + 1), f k (m - k)) = ∑ m in range n, ∑ k in range (n - m), f m k := by rw [sum_sigma', sum_sigma'] - exact - sum_bij (fun a _ => ⟨a.2, a.1 - a.2⟩) - (fun a ha => - have h₁ : a.1 < n := mem_range.1 (mem_sigma.1 ha).1 - have h₂ : a.2 < Nat.succ a.1 := mem_range.1 (mem_sigma.1 ha).2 - mem_sigma.2 - ⟨mem_range.2 (lt_of_lt_of_le h₂ h₁), - mem_range.2 ((tsub_lt_tsub_iff_right (Nat.le_of_lt_succ h₂)).2 h₁)⟩) - (fun _ _ => rfl) - (fun ⟨a₁, a₂⟩ ⟨b₁, b₂⟩ ha hb h => - have ha : a₁ < n ∧ a₂ ≤ a₁ := - ⟨mem_range.1 (mem_sigma.1 ha).1, Nat.le_of_lt_succ (mem_range.1 (mem_sigma.1 ha).2)⟩ - have hb : b₁ < n ∧ b₂ ≤ b₁ := - ⟨mem_range.1 (mem_sigma.1 hb).1, Nat.le_of_lt_succ (mem_range.1 (mem_sigma.1 hb).2)⟩ - have h : a₂ = b₂ ∧ _ := by simpa using h - have h' : a₁ = b₁ - b₂ + a₂ := (tsub_eq_iff_eq_add_of_le ha.2).1 (eq_of_heq h.2) - Sigma.mk.inj_iff.2 ⟨tsub_add_cancel_of_le hb.2 ▸ h'.symm ▸ h.1 ▸ rfl, heq_of_eq h.1⟩) - fun ⟨a₁, a₂⟩ ha => - have ha : a₁ < n ∧ a₂ < n - a₁ := - ⟨mem_range.1 (mem_sigma.1 ha).1, mem_range.1 (mem_sigma.1 ha).2⟩ - ⟨⟨a₂ + a₁, a₁⟩, - ⟨mem_sigma.2 - ⟨mem_range.2 (lt_tsub_iff_right.1 ha.2), - mem_range.2 (Nat.lt_succ_of_le (Nat.le_add_left _ _))⟩, - Sigma.mk.inj_iff.2 ⟨rfl, heq_of_eq (add_tsub_cancel_right _ _).symm⟩⟩⟩ + refine sum_nbij' (fun a ↦ ⟨a.2, a.1 - a.2⟩) (fun a ↦ ⟨a.1 + a.2, a.1⟩) ?_ ?_ ?_ ?_ ?_ <;> + simp (config := { contextual := true }) only [mem_sigma, mem_range, lt_tsub_iff_left, + Nat.lt_succ_iff, le_add_iff_nonneg_right, zero_le, and_true, and_imp, imp_self, implies_true, + Sigma.forall, forall_const, add_tsub_cancel_of_le, Sigma.mk.inj_iff, + add_tsub_cancel_left, heq_eq_eq] + · exact fun a b han hba ↦ lt_of_le_of_lt hba han #align sum_range_diag_flip sum_range_diag_flip end @@ -1602,20 +1583,9 @@ theorem sum_div_factorial_le {α : Type*} [LinearOrderedField α] (n j : ℕ) (h (1 / m.factorial : α)) ≤ n.succ / (n.factorial * n) := calc (∑ m in filter (fun k => n ≤ k) (range j), (1 / m.factorial : α)) = - ∑ m in range (j - n), (1 / ((m + n).factorial : α)) := - sum_bij (fun m _ => m - n) - (fun m hm => - mem_range.2 <| - (tsub_lt_tsub_iff_right (by simp at hm; tauto)).2 (by simp at hm; tauto)) - (fun m hm => by rw [tsub_add_cancel_of_le]; simp at *; tauto) - (fun a₁ a₂ ha₁ ha₂ h => by - rwa [tsub_eq_iff_eq_add_of_le, tsub_add_eq_add_tsub, eq_comm, tsub_eq_iff_eq_add_of_le, - add_left_inj, eq_comm] at h <;> - simp at * <;> aesop) - fun b hb => - ⟨b + n, - mem_filter.2 ⟨mem_range.2 <| lt_tsub_iff_right.mp (mem_range.1 hb), Nat.le_add_left _ _⟩, - by dsimp; rw [add_tsub_cancel_right]⟩ + ∑ m in range (j - n), (1 / ((m + n).factorial : α)) := by + refine sum_nbij' (· - n) (· + n) ?_ ?_ ?_ ?_ ?_ <;> + simp (config := { contextual := true }) [lt_tsub_iff_right, tsub_add_cancel_of_le] _ ≤ ∑ m in range (j - n), ((n.factorial : α) * (n.succ : α) ^ m)⁻¹ := by simp_rw [one_div] gcongr diff --git a/Mathlib/Data/DFinsupp/Basic.lean b/Mathlib/Data/DFinsupp/Basic.lean index ab6ca2fbb9707..b7092d2244060 100644 --- a/Mathlib/Data/DFinsupp/Basic.lean +++ b/Mathlib/Data/DFinsupp/Basic.lean @@ -2151,9 +2151,8 @@ theorem sum_single [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable @[to_additive] theorem prod_subtypeDomain_index [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ] {v : Π₀ i, β i} {p : ι → Prop} [DecidablePred p] {h : ∀ i, β i → γ} - (hp : ∀ x ∈ v.support, p x) : ((v.subtypeDomain p).prod fun i b => h i b) = v.prod h := - Finset.prod_bij (fun p _ => p) (by simp) (by simp) (fun ⟨a₀, ha₀⟩ ⟨a₁, ha₁⟩ => by simp) - fun i hi => ⟨⟨i, hp i hi⟩, by simpa using hi, rfl⟩ + (hp : ∀ x ∈ v.support, p x) : (v.subtypeDomain p).prod (fun i b => h i b) = v.prod h := by + refine Finset.prod_bij (fun p _ ↦ p) ?_ ?_ ?_ ?_ <;> aesop #align dfinsupp.prod_subtype_domain_index DFinsupp.prod_subtypeDomain_index #align dfinsupp.sum_subtype_domain_index DFinsupp.sum_subtypeDomain_index diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean index 25446a9b962ae..e284e7657663d 100644 --- a/Mathlib/Data/Finset/Card.lean +++ b/Mathlib/Data/Finset/Card.lean @@ -398,14 +398,14 @@ theorem surj_on_of_inj_on_of_card_le {t : Finset β} (f : ∀ a ∈ s, β) (hf : #align finset.surj_on_of_inj_on_of_card_le Finset.surj_on_of_inj_on_of_card_le theorem inj_on_of_surj_on_of_card_le {t : Finset β} (f : ∀ a ∈ s, β) (hf : ∀ a ha, f a ha ∈ t) - (hsurj : ∀ b ∈ t, ∃ a ha, b = f a ha) (hst : s.card ≤ t.card) ⦃a₁ a₂⦄ (ha₁ : a₁ ∈ s) + (hsurj : ∀ b ∈ t, ∃ a ha, f a ha = b) (hst : s.card ≤ t.card) ⦃a₁⦄ (ha₁ : a₁ ∈ s) ⦃a₂⦄ (ha₂ : a₂ ∈ s) (ha₁a₂ : f a₁ ha₁ = f a₂ ha₂) : a₁ = a₂ := haveI : Inhabited { x // x ∈ s } := ⟨⟨a₁, ha₁⟩⟩ let f' : { x // x ∈ s } → { x // x ∈ t } := fun x => ⟨f x.1 x.2, hf x.1 x.2⟩ let g : { x // x ∈ t } → { x // x ∈ s } := @surjInv _ _ f' fun x => let ⟨y, hy₁, hy₂⟩ := hsurj x.1 x.2 - ⟨⟨y, hy₁⟩, Subtype.eq hy₂.symm⟩ + ⟨⟨y, hy₁⟩, Subtype.eq hy₂⟩ have hg : Injective g := injective_surjInv _ have hsg : Surjective g := fun x => let ⟨y, hy⟩ := diff --git a/Mathlib/Data/Finset/LocallyFinite.lean b/Mathlib/Data/Finset/LocallyFinite.lean index d0bce673b2a08..f0293ee9a027f 100644 --- a/Mathlib/Data/Finset/LocallyFinite.lean +++ b/Mathlib/Data/Finset/LocallyFinite.lean @@ -1179,7 +1179,7 @@ theorem prod_prod_Ioi_mul_eq_prod_prod_off_diag [Fintype ι] [LinearOrder ι] simp_rw [← Ioi_disjUnion_Iio, prod_disjUnion, prod_mul_distrib] congr 1 rw [prod_sigma', prod_sigma'] - refine' prod_bij' (fun i _ => ⟨i.2, i.1⟩) _ _ (fun i _ => ⟨i.2, i.1⟩) _ _ _ <;> simp + refine' prod_nbij' (fun i ↦ ⟨i.2, i.1⟩) (fun i ↦ ⟨i.2, i.1⟩) _ _ _ _ _ <;> simp #align finset.prod_prod_Ioi_mul_eq_prod_prod_off_diag Finset.prod_prod_Ioi_mul_eq_prod_prod_off_diag #align finset.sum_sum_Ioi_add_eq_sum_sum_off_diag Finset.sum_sum_Ioi_add_eq_sum_sum_off_diag diff --git a/Mathlib/Data/Finsupp/Antidiagonal.lean b/Mathlib/Data/Finsupp/Antidiagonal.lean index 249a21f269ca9..36fcb225a2f10 100644 --- a/Mathlib/Data/Finsupp/Antidiagonal.lean +++ b/Mathlib/Data/Finsupp/Antidiagonal.lean @@ -56,9 +56,7 @@ theorem antidiagonal_zero : antidiagonal (0 : α →₀ ℕ) = singleton (0, 0) theorem prod_antidiagonal_swap {M : Type*} [CommMonoid M] (n : α →₀ ℕ) (f : (α →₀ ℕ) → (α →₀ ℕ) → M) : ∏ p in antidiagonal n, f p.1 p.2 = ∏ p in antidiagonal n, f p.2 p.1 := - Finset.prod_bij (fun p _hp ↦ p.swap) (fun _p ↦ swap_mem_antidiagonal.2) (fun _p _hp ↦ rfl) - (fun _p₁ _p₂ _ _ h ↦ Prod.swap_injective h) fun p hp ↦ - ⟨p.swap, swap_mem_antidiagonal.2 hp, p.swap_swap.symm⟩ + prod_equiv (Equiv.prodComm _ _) (by simp [add_comm]) (by simp) #align finsupp.prod_antidiagonal_swap Finsupp.prod_antidiagonal_swap #align finsupp.sum_antidiagonal_swap Finsupp.sum_antidiagonal_swap diff --git a/Mathlib/Data/Finsupp/Basic.lean b/Mathlib/Data/Finsupp/Basic.lean index 378919364cb2f..1032755daf26f 100644 --- a/Mathlib/Data/Finsupp/Basic.lean +++ b/Mathlib/Data/Finsupp/Basic.lean @@ -1052,9 +1052,8 @@ theorem subtypeDomain_eq_zero_iff {f : α →₀ M} (hf : ∀ x ∈ f.support, p @[to_additive] theorem prod_subtypeDomain_index [CommMonoid N] {v : α →₀ M} {h : α → M → N} - (hp : ∀ x ∈ v.support, p x) : ((v.subtypeDomain p).prod fun a b => h a b) = v.prod h := - prod_bij (fun p _ => p.val) (fun _ => by classical exact mem_subtype.1) (fun _ _ => rfl) - (fun _ _ _ _ => Subtype.eq) fun b hb => ⟨⟨b, hp b hb⟩, by classical exact mem_subtype.2 hb, rfl⟩ + (hp : ∀ x ∈ v.support, p x) : (v.subtypeDomain p).prod (fun a b ↦ h a b) = v.prod h := by + refine Finset.prod_bij (fun p _ ↦ p) ?_ ?_ ?_ ?_ <;> aesop #align finsupp.prod_subtype_domain_index Finsupp.prod_subtypeDomain_index #align finsupp.sum_subtype_domain_index Finsupp.sum_subtypeDomain_index diff --git a/Mathlib/Data/Fintype/BigOperators.lean b/Mathlib/Data/Fintype/BigOperators.lean index da93fd27a5c40..94cc552427eb2 100644 --- a/Mathlib/Data/Fintype/BigOperators.lean +++ b/Mathlib/Data/Fintype/BigOperators.lean @@ -173,13 +173,7 @@ theorem Finset.prod_attach_univ [Fintype α] [CommMonoid β] (f : { a : α // a theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*} {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) : ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by - refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp) - (by simp (config := { contextual := true }) [Function.funext_iff]) fun x hx => - ⟨fun a _ => x a, by simp_all⟩ - -- Porting note: old proof was `by simp` - intro a ha - simp only [Fintype.piFinset, mem_map, mem_pi, Function.Embedding.coeFn_mk] - exact ⟨a, by simpa using ha, by simp⟩ + apply prod_nbij' (fun x i ↦ x i $ mem_univ _) (fun x i _ ↦ x i) <;> simp #align finset.prod_univ_pi Finset.prod_univ_pi #align finset.sum_univ_pi Finset.sum_univ_pi @@ -202,34 +196,13 @@ theorem Fintype.sum_pow_mul_eq_add_pow (α : Type*) [Fintype α] {R : Type*} [Co Finset.sum_pow_mul_eq_add_pow _ _ _ #align fintype.sum_pow_mul_eq_add_pow Fintype.sum_pow_mul_eq_add_pow -@[to_additive] -theorem Function.Bijective.prod_comp [Fintype α] [Fintype β] [CommMonoid γ] {f : α → β} - (hf : Function.Bijective f) (g : β → γ) : (∏ i, g (f i)) = ∏ i, g i := - Fintype.prod_bijective f hf _ _ fun _x => rfl -#align function.bijective.prod_comp Function.Bijective.prod_comp -#align function.bijective.sum_comp Function.Bijective.sum_comp - -@[to_additive] -theorem Equiv.prod_comp [Fintype α] [Fintype β] [CommMonoid γ] (e : α ≃ β) (f : β → γ) : - (∏ i, f (e i)) = ∏ i, f i := - e.bijective.prod_comp f -#align equiv.prod_comp Equiv.prod_comp -#align equiv.sum_comp Equiv.sum_comp - -@[to_additive] -theorem Equiv.prod_comp' [Fintype α] [Fintype β] [CommMonoid γ] (e : α ≃ β) (f : α → γ) (g : β → γ) - (h : ∀ i, f i = g (e i)) : ∏ i, f i = ∏ i, g i := - (show f = g ∘ e from funext h).symm ▸ e.prod_comp _ -#align equiv.prod_comp' Equiv.prod_comp' -#align equiv.sum_comp' Equiv.sum_comp' - /-- It is equivalent to compute the product of a function over `Fin n` or `Finset.range n`. -/ @[to_additive "It is equivalent to sum a function over `fin n` or `finset.range n`."] theorem Fin.prod_univ_eq_prod_range [CommMonoid α] (f : ℕ → α) (n : ℕ) : ∏ i : Fin n, f i = ∏ i in range n, f i := calc ∏ i : Fin n, f i = ∏ i : { x // x ∈ range n }, f i := - (Fin.equivSubtype.trans (Equiv.subtypeEquivRight (by simp))).prod_comp' _ _ (by simp) + Fintype.prod_equiv (Fin.equivSubtype.trans (Equiv.subtypeEquivRight (by simp))) _ _ (by simp) _ = ∏ i in range n, f i := by rw [← attach_eq_univ, prod_attach] #align fin.prod_univ_eq_prod_range Fin.prod_univ_eq_prod_range #align fin.sum_univ_eq_sum_range Fin.sum_univ_eq_sum_range @@ -251,21 +224,6 @@ theorem Finset.prod_toFinset_eq_subtype {M : Type*} [CommMonoid M] [Fintype α] #align finset.prod_to_finset_eq_subtype Finset.prod_toFinset_eq_subtype #align finset.sum_to_finset_eq_subtype Finset.sum_toFinset_eq_subtype -@[to_additive] -theorem Finset.prod_fiberwise [DecidableEq β] [Fintype β] [CommMonoid γ] (s : Finset α) (f : α → β) - (g : α → γ) : (∏ b : β, ∏ a in s.filter fun a => f a = b, g a) = ∏ a in s, g a := - Finset.prod_fiberwise_of_maps_to (fun _x _ => mem_univ _) _ -#align finset.prod_fiberwise Finset.prod_fiberwise -#align finset.sum_fiberwise Finset.sum_fiberwise - -@[to_additive] -theorem Fintype.prod_fiberwise [Fintype α] [DecidableEq β] [Fintype β] [CommMonoid γ] (f : α → β) - (g : α → γ) : (∏ b : β, ∏ a : { a // f a = b }, g (a : α)) = ∏ a, g a := by - rw [← (Equiv.sigmaFiberEquiv f).prod_comp, ← univ_sigma_univ, prod_sigma] - rfl -#align fintype.prod_fiberwise Fintype.prod_fiberwise -#align fintype.sum_fiberwise Fintype.sum_fiberwise - nonrec theorem Fintype.prod_dite [Fintype α] {p : α → Prop} [DecidablePred p] [CommMonoid β] (f : ∀ a, p a → β) (g : ∀ a, ¬p a → β) : (∏ a, dite (p a) (f a) (g a)) = diff --git a/Mathlib/Data/Multiset/Nodup.lean b/Mathlib/Data/Multiset/Nodup.lean index d1418b4021db3..1a27d4e730c1e 100644 --- a/Mathlib/Data/Multiset/Nodup.lean +++ b/Mathlib/Data/Multiset/Nodup.lean @@ -167,6 +167,8 @@ theorem nodup_attach {s : Multiset α} : Nodup (attach s) ↔ Nodup s := Quot.induction_on s fun _ => List.nodup_attach #align multiset.nodup_attach Multiset.nodup_attach +protected alias ⟨_, Nodup.attach⟩ := nodup_attach + theorem Nodup.pmap {p : α → Prop} {f : ∀ a, p a → β} {s : Multiset α} {H} (hf : ∀ a ha b hb, f a ha = f b hb → a = b) : Nodup s → Nodup (pmap f s H) := Quot.induction_on s (fun _ _ => List.Nodup.pmap hf) H @@ -265,16 +267,12 @@ theorem mem_sub_of_nodup [DecidableEq α] {a : α} {s t : Multiset α} (d : Nodu theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset α} {t : Multiset β} (hs : s.Nodup) (ht : t.Nodup) (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t) - (h : ∀ a ha, f a = g (i a ha)) (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂) - (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : s.map f = t.map g := - have : t = s.attach.map fun x => i x.1 x.2 := - (ht.ext <| - (nodup_attach.2 hs).map <| - show Injective fun x : { x // x ∈ s } => i x x.2 from fun x y hxy => - Subtype.ext <| i_inj x y x.2 y.2 hxy).2 - fun x => by - simp only [mem_map, true_and_iff, Subtype.exists, eq_comm, mem_attach] - exact ⟨i_surj _, fun ⟨y, hy⟩ => hy.snd.symm ▸ hi _ _⟩ + (i_inj : ∀ a₁ ha₁ a₂ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂) + (i_surj : ∀ b ∈ t, ∃ a ha, i a ha = b) (h : ∀ a ha, f a = g (i a ha)) : s.map f = t.map g := by + have : t = s.attach.map fun x => i x.1 x.2 + · rw [ht.ext] + · aesop + · exact hs.attach.map $ fun x y hxy ↦ Subtype.ext $ i_inj _ x.2 _ y.2 hxy calc s.map f = s.pmap (fun x _ => f x) fun _ => id := by rw [pmap_eq_map] _ = s.attach.map fun x => f x.1 := by rw [pmap_eq_map_attach] diff --git a/Mathlib/Data/Polynomial/Mirror.lean b/Mathlib/Data/Polynomial/Mirror.lean index 862bc472591db..83763fc7ba080 100644 --- a/Mathlib/Data/Polynomial/Mirror.lean +++ b/Mathlib/Data/Polynomial/Mirror.lean @@ -107,10 +107,10 @@ theorem mirror_eval_one : p.mirror.eval 1 = p.eval 1 := by rw [revAt_le (hn.trans (Nat.le_add_right _ _))] rw [tsub_le_iff_tsub_le, add_comm, add_tsub_cancel_right, ← mirror_natTrailingDegree] exact natTrailingDegree_le_of_ne_zero hp - · exact fun n₁ n₂ _ _ _ _ h => by rw [← @revAt_invol _ n₁, h, revAt_invol] + · exact fun n₁ _ _ _ _ _ h => by rw [← @revAt_invol _ n₁, h, revAt_invol] · intro n hn hp use revAt (p.natDegree + p.natTrailingDegree) n - refine' ⟨_, _, revAt_invol.symm⟩ + refine' ⟨_, _, revAt_invol⟩ · rw [Finset.mem_range_succ_iff] at * rw [revAt_le (hn.trans (Nat.le_add_right _ _))] rw [tsub_le_iff_tsub_le, add_comm, add_tsub_cancel_right] diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index cb503f4944cce..85b2b3652dab4 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -804,7 +804,7 @@ theorem surj_on_of_inj_on_of_ncard_le {t : Set β} (f : ∀ a ∈ s, β) (hf : #align set.surj_on_of_inj_on_of_ncard_le Set.surj_on_of_inj_on_of_ncard_le theorem inj_on_of_surj_on_of_ncard_le {t : Set β} (f : ∀ a ∈ s, β) (hf : ∀ a ha, f a ha ∈ t) - (hsurj : ∀ b ∈ t, ∃ a ha, b = f a ha) (hst : s.ncard ≤ t.ncard) ⦃a₁ a₂⦄ (ha₁ : a₁ ∈ s) + (hsurj : ∀ b ∈ t, ∃ a ha, f a ha = b) (hst : s.ncard ≤ t.ncard) ⦃a₁⦄ (ha₁ : a₁ ∈ s) ⦃a₂⦄ (ha₂ : a₂ ∈ s) (ha₁a₂ : f a₁ ha₁ = f a₂ ha₂) (hs : s.Finite := by toFinite_tac) : a₁ = a₂ := by classical @@ -820,8 +820,8 @@ theorem inj_on_of_surj_on_of_ncard_le {t : Set β} (f : ∀ a ∈ s, β) (hf : exact @Finset.inj_on_of_surj_on_of_card_le _ _ _ t.toFinset f'' (fun a ha ↦ by { rw [mem_toFinset] at ha ⊢; exact hf a ha }) (by simpa) - (by { rwa [← ncard_eq_toFinset_card', ← ncard_eq_toFinset_card'] }) a₁ a₂ - (by simpa) (by simpa) (by simpa) + (by { rwa [← ncard_eq_toFinset_card', ← ncard_eq_toFinset_card'] }) a₁ + (by simpa) a₂ (by simpa) (by simpa) #align set.inj_on_of_surj_on_of_ncard_le Set.inj_on_of_surj_on_of_ncard_le section Lattice diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index d12a6ae783770..e061cc66ef6fc 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -892,7 +892,7 @@ lemma Finite.of_surjOn {s : Set α} {t : Set β} (f : α → β) (hf : SurjOn f t.Finite := (hs.image _).subset hf theorem Finite.dependent_image {s : Set α} (hs : s.Finite) (F : ∀ i ∈ s, β) : - { y : β | ∃ (x : _) (hx : x ∈ s), y = F x hx }.Finite := by + {y : β | ∃ x hx, F x hx = y}.Finite := by cases hs simpa [range, eq_comm] using finite_range fun x : s => F x x.2 #align set.finite.dependent_image Set.Finite.dependent_image diff --git a/Mathlib/Data/Sign.lean b/Mathlib/Data/Sign.lean index 0954d3a48353d..34aff1961e3ce 100644 --- a/Mathlib/Data/Sign.lean +++ b/Mathlib/Data/Sign.lean @@ -518,7 +518,7 @@ theorem exists_signed_sum {α : Type u_1} [DecidableEq α] (s : Finset α) (f : ∀ a ∈ s, (∑ b, if g b = a then (sgn b : ℤ) else 0) = f a := let ⟨β, t, sgn, g, hg, ht, hf⟩ := exists_signed_sum_aux s f ⟨t, inferInstance, fun b => sgn b, fun b => g b, fun b => hg b, by simp [ht], fun a ha => - (@sum_attach _ _ t _ fun b => ite (g b = a) (sgn b : ℤ) 0).trans <| hf _ ha⟩ + (sum_attach t fun b ↦ ite (g b = a) (sgn b : ℤ) 0).trans <| hf _ ha⟩ #align exists_signed_sum exists_signed_sum /-- We can decompose a sum of absolute value less than `n` into a sum of at most `n` signs. -/ diff --git a/Mathlib/FieldTheory/Fixed.lean b/Mathlib/FieldTheory/Fixed.lean index 7665979fd3d83..cb2d229512be5 100644 --- a/Mathlib/FieldTheory/Fixed.lean +++ b/Mathlib/FieldTheory/Fixed.lean @@ -144,7 +144,7 @@ theorem linearIndependent_smul_of_linearIndependent {s : Finset F} : (linearIndependent_iff'.1 (ih hs.1) s.attach (fun i => g • l i - l i) _ ⟨i, his⟩ (mem_attach _ _) : _) - refine' (@sum_attach _ _ s _ fun i => (g • l i - l i) • MulAction.toFun G F i).trans _ + refine' (sum_attach s fun i ↦ (g • l i - l i) • MulAction.toFun G F i).trans _ ext g'; dsimp only conv_lhs => rw [sum_apply] diff --git a/Mathlib/GroupTheory/PGroup.lean b/Mathlib/GroupTheory/PGroup.lean index 261210b0e8032..6ccc3e3b556f8 100644 --- a/Mathlib/GroupTheory/PGroup.lean +++ b/Mathlib/GroupTheory/PGroup.lean @@ -199,7 +199,7 @@ theorem card_modEq_card_fixedPoints [Fintype (fixedPoints G α)] : refine' Eq.symm (Finset.sum_bij_ne_zero (fun a _ _ => Quotient.mk'' a.1) (fun _ _ _ => Finset.mem_univ _) - (fun a₁ a₂ _ _ _ _ h => + (fun a₁ _ _ a₂ _ _ h => Subtype.eq (mem_fixedPoints'.mp a₂.2 a₁.1 (Quotient.exact' h))) (fun b => Quotient.inductionOn' b fun b _ hb => _) fun a ha _ => by rw [key, mem_fixedPoints_iff_card_orbit_eq_one.mp a.2]) diff --git a/Mathlib/GroupTheory/Perm/Sign.lean b/Mathlib/GroupTheory/Perm/Sign.lean index 5d00783df7b7a..3c26db827af4c 100644 --- a/Mathlib/GroupTheory/Perm/Sign.lean +++ b/Mathlib/GroupTheory/Perm/Sign.lean @@ -328,21 +328,20 @@ def signBijAux {n : ℕ} (f : Perm (Fin n)) (a : Σ_ : Fin n, Fin n) : Σ_ : Fin -- porting note: Lean insists `ha` and `hb` are unused despite obvious uses set_option linter.unusedVariables false in -theorem signBijAux_inj {n : ℕ} {f : Perm (Fin n)} : - ∀ a b : Σ_a : Fin n, Fin n, - a ∈ finPairsLT n → b ∈ finPairsLT n → signBijAux f a = signBijAux f b → a = b := - fun ⟨a₁, a₂⟩ ⟨b₁, b₂⟩ ha hb h => by - unfold signBijAux at h - rw [mem_finPairsLT] at * - have : ¬b₁ < b₂ := hb.le.not_lt - split_ifs at h <;> - simp_all [(Equiv.injective f).eq_iff, eq_self_iff_true, and_self_iff, heq_iff_eq] - · exact absurd this (not_le.mpr ha) - · exact absurd this (not_le.mpr ha) -#align equiv.perm.sign_bij_aux_inj Equiv.Perm.signBijAux_inj +theorem signBijAux_injOn {n : ℕ} {f : Perm (Fin n)} : + (finPairsLT n : Set (Σ _, Fin n)).InjOn (signBijAux f) := by + rintro ⟨a₁, a₂⟩ ha ⟨b₁, b₂⟩ hb h + dsimp [signBijAux] at h + rw [Finset.mem_coe, mem_finPairsLT] at * + have : ¬b₁ < b₂ := hb.le.not_lt + split_ifs at h <;> + simp_all [(Equiv.injective f).eq_iff, eq_self_iff_true, and_self_iff, heq_iff_eq] + · exact absurd this (not_le.mpr ha) + · exact absurd this (not_le.mpr ha) +#align equiv.perm.sign_bij_aux_inj Equiv.Perm.signBijAux_injOn theorem signBijAux_surj {n : ℕ} {f : Perm (Fin n)} : - ∀ a ∈ finPairsLT n, ∃ (b: Σ (_: Fin n), Fin n) (_H: b ∈ finPairsLT n), a = signBijAux f b := + ∀ a ∈ finPairsLT n, ∃ b ∈ finPairsLT n, signBijAux f b = a := fun ⟨a₁, a₂⟩ ha => if hxa : f⁻¹ a₂ < f⁻¹ a₁ then ⟨⟨f⁻¹ a₁, f⁻¹ a₂⟩, mem_finPairsLT.2 hxa, by @@ -369,41 +368,37 @@ theorem signBijAux_mem {n : ℕ} {f : Perm (Fin n)} : @[simp] theorem signAux_inv {n : ℕ} (f : Perm (Fin n)) : signAux f⁻¹ = signAux f := - prod_bij (fun a _ => signBijAux f⁻¹ a) signBijAux_mem - (fun ⟨a, b⟩ hab => - if h : f⁻¹ b < f⁻¹ a then by - simp_all [signBijAux, dif_pos h, if_neg h.not_le, apply_inv_self, apply_inv_self, - if_neg (mem_finPairsLT.1 hab).not_le] - split_ifs with h₁ - · dsimp [finPairsLT] at hab - simp? at hab says - simp only [mem_sigma, mem_univ, mem_attachFin, mem_range, Fin.val_fin_lt, - true_and] at hab - exact absurd h₁ (not_le_of_gt hab) - · rfl - else by - simp_all [signBijAux, if_pos (le_of_not_gt h), dif_neg h, apply_inv_self, apply_inv_self, - if_pos (mem_finPairsLT.1 hab).le] - split_ifs with h₁ h₂ h₃ - · rfl - · exact absurd h (not_le_of_gt h₁) - · rfl - · dsimp at * - dsimp [finPairsLT] at hab - simp? at * says - simp only [mem_sigma, mem_univ, mem_attachFin, mem_range, Fin.val_fin_lt, - true_and, not_lt, apply_inv_self, not_le, Int.neg_units_ne_self] at * - exact absurd h₃ (asymm_of LT.lt hab)) - signBijAux_inj signBijAux_surj + prod_nbij (signBijAux f⁻¹) signBijAux_mem signBijAux_injOn signBijAux_surj fun ⟨a, b⟩ hab ↦ + if h : f⁻¹ b < f⁻¹ a then by + simp_all [signBijAux, dif_pos h, if_neg h.not_le, apply_inv_self, apply_inv_self, + if_neg (mem_finPairsLT.1 hab).not_le] + split_ifs with h₁ + · dsimp [finPairsLT] at hab + simp? at hab says + simp only [mem_sigma, mem_univ, mem_attachFin, mem_range, Fin.val_fin_lt, + true_and] at hab + exact absurd h₁ (not_le_of_gt hab) + · rfl + else by + simp_all [signBijAux, if_pos (le_of_not_gt h), dif_neg h, apply_inv_self, apply_inv_self, + if_pos (mem_finPairsLT.1 hab).le] + split_ifs with h₁ h₂ h₃ + · rfl + · exact absurd h (not_le_of_gt h₁) + · rfl + · dsimp at * + dsimp [finPairsLT] at hab + simp? at * says + simp only [mem_sigma, mem_univ, mem_attachFin, mem_range, Fin.val_fin_lt, + true_and, not_lt, apply_inv_self, not_le, Int.neg_units_ne_self] at * + exact absurd h₃ (asymm_of LT.lt hab) #align equiv.perm.sign_aux_inv Equiv.Perm.signAux_inv theorem signAux_mul {n : ℕ} (f g : Perm (Fin n)) : signAux (f * g) = signAux f * signAux g := by rw [← signAux_inv g] unfold signAux rw [← prod_mul_distrib] - refine' - prod_bij (fun a _ => signBijAux g a) signBijAux_mem _ signBijAux_inj - (by simpa using signBijAux_surj) + refine prod_nbij (signBijAux g) signBijAux_mem signBijAux_injOn signBijAux_surj ?_ rintro ⟨a, b⟩ hab dsimp only [signBijAux] rw [mul_apply, mul_apply] diff --git a/Mathlib/GroupTheory/SchurZassenhaus.lean b/Mathlib/GroupTheory/SchurZassenhaus.lean index 30095bd8c7498..c781a463b753f 100644 --- a/Mathlib/GroupTheory/SchurZassenhaus.lean +++ b/Mathlib/GroupTheory/SchurZassenhaus.lean @@ -59,14 +59,9 @@ theorem smul_diff_smul' [hH : Normal H] (g : Gᵐᵒᵖ) : map_one' := by rw [Subtype.ext_iff, coe_mk, coe_one, mul_one, inv_mul_self] map_mul' := fun h₁ h₂ => by simp only [Subtype.ext_iff, coe_mk, coe_mul, mul_assoc, mul_inv_cancel_left] } - refine' - Eq.trans - (Finset.prod_bij' (fun q _ => g⁻¹ • q) (fun q _ => Finset.mem_univ _) - (fun q _ => Subtype.ext _) (fun q _ => g • q) (fun q _ => Finset.mem_univ _) - (fun q _ => smul_inv_smul g q) fun q _ => inv_smul_smul g q) - (map_prod ϕ _ _).symm - simp only [MonoidHom.id_apply, MonoidHom.coe_mk, OneHom.coe_mk, - smul_apply_eq_smul_apply_inv_smul, smul_eq_mul_unop, mul_inv_rev, mul_assoc] + refine (Fintype.prod_equiv (MulAction.toPerm g).symm _ _ fun x ↦ ?_).trans (map_prod ϕ _ _).symm + simp only [smul_apply_eq_smul_apply_inv_smul, smul_eq_mul_unop, mul_inv_rev, mul_assoc, + MonoidHom.id_apply, toPerm_symm_apply, MonoidHom.coe_mk, OneHom.coe_mk] #align subgroup.smul_diff_smul' Subgroup.smul_diff_smul' variable {H} [Normal H] diff --git a/Mathlib/GroupTheory/Transfer.lean b/Mathlib/GroupTheory/Transfer.lean index abe4c606c8b7f..40e81534d69a2 100644 --- a/Mathlib/GroupTheory/Transfer.lean +++ b/Mathlib/GroupTheory/Transfer.lean @@ -79,14 +79,9 @@ theorem diff_inv : (diff ϕ S T)⁻¹ = diff ϕ T S := @[to_additive] theorem smul_diff_smul (g : G) : diff ϕ (g • S) (g • T) = diff ϕ S T := let _ := H.fintypeQuotientOfFiniteIndex - prod_bij' (fun q _ => g⁻¹ • q) (fun _ _ => mem_univ _) - (fun _ _ => - congr_arg ϕ - (by - simp_rw [smul_apply_eq_smul_apply_inv_smul, smul_eq_mul, mul_inv_rev, mul_assoc, - inv_mul_cancel_left])) - (fun q _ => g • q) (fun _ _ => mem_univ _) (fun q _ => smul_inv_smul g q) fun q _ => - inv_smul_smul g q + Fintype.prod_equiv (MulAction.toPerm g).symm _ _ $ fun _ ↦ by + simp only [smul_apply_eq_smul_apply_inv_smul, smul_eq_mul, mul_inv_rev, mul_assoc, + inv_mul_cancel_left, toPerm_symm_apply] #align subgroup.left_transversals.smul_diff_smul Subgroup.leftTransversals.smul_diff_smul #align add_subgroup.left_transversals.vadd_diff_vadd AddSubgroup.leftTransversals.vadd_diff_vadd diff --git a/Mathlib/LinearAlgebra/Matrix/Determinant.lean b/Mathlib/LinearAlgebra/Matrix/Determinant.lean index 927d256e85f6e..30018656a2541 100644 --- a/Mathlib/LinearAlgebra/Matrix/Determinant.lean +++ b/Mathlib/LinearAlgebra/Matrix/Determinant.lean @@ -160,9 +160,9 @@ theorem det_mul (M N : Matrix n n R) : det (M * N) = det M * det N := sum_subset (filter_subset _ _) fun f _ hbij => det_mul_aux <| by simpa only [true_and_iff, mem_filter, mem_univ] using hbij) _ = ∑ τ : Perm n, ∑ σ : Perm n, ε σ * ∏ i, M (σ i) (τ i) * N (τ i) i := - (sum_bij (fun p h => Equiv.ofBijective p (mem_filter.1 h).2) (fun _ _ => mem_univ _) - (fun _ _ => rfl) (fun _ _ _ _ h => by injection h) fun b _ => - ⟨b, mem_filter.2 ⟨mem_univ _, b.bijective⟩, coe_fn_injective rfl⟩) + sum_bij (fun p h ↦ Equiv.ofBijective p (mem_filter.1 h).2) (fun _ _ ↦ mem_univ _) + (fun _ _ _ _ h ↦ by injection h) + (fun b _ ↦ ⟨b, mem_filter.2 ⟨mem_univ _, b.bijective⟩, coe_fn_injective rfl⟩) fun _ _ ↦ rfl _ = ∑ σ : Perm n, ∑ τ : Perm n, (∏ i, N (σ i) i) * ε τ * ∏ j, M (τ j) (σ j) := by simp only [mul_comm, mul_left_comm, prod_mul_distrib, mul_assoc] _ = ∑ σ : Perm n, ∑ τ : Perm n, (∏ i, N (σ i) i) * (ε σ * ε τ) * ∏ i, M (τ i) i := @@ -585,19 +585,12 @@ theorem det_blockDiagonal {o : Type*} [Fintype o] [DecidableEq o] (M : o → Mat Finset.mem_filter.trans ⟨fun h => h.2, fun h => ⟨Finset.mem_univ _, h⟩⟩ rw [← Finset.sum_subset (Finset.subset_univ preserving_snd) _] -- And that these are in bijection with `o → Equiv.Perm m`. - rw [(Finset.sum_bij - (fun (σ : ∀ k : o, k ∈ Finset.univ → Equiv.Perm n) _ => - prodCongrLeft fun k => σ k (Finset.mem_univ k)) - _ _ _ _).symm] + refine (Finset.sum_bij (fun σ _ => prodCongrLeft fun k ↦ σ k (mem_univ k)) ?_ ?_ ?_ ?_).symm · intro σ _ rw [mem_preserving_snd] rintro ⟨-, x⟩ simp only [prodCongrLeft_apply] - · intro σ _ - rw [Finset.prod_mul_distrib, ← Finset.univ_product_univ, Finset.prod_product_right] - simp only [sign_prodCongrLeft, Units.coe_prod, Int.cast_prod, blockDiagonal_apply_eq, - prodCongrLeft_apply] - · intro σ σ' _ _ eq + · intro σ _ σ' _ eq ext x hx k simp only at eq have : @@ -632,6 +625,10 @@ theorem det_blockDiagonal {o : Type*} [Fintype o] [DecidableEq o] (M : o → Mat · ext ⟨k, x⟩ · simp only [coe_fn_mk, prodCongrLeft_apply] · simp only [prodCongrLeft_apply, hσ] + · intro σ _ + rw [Finset.prod_mul_distrib, ← Finset.univ_product_univ, Finset.prod_product_right] + simp only [sign_prodCongrLeft, Units.coe_prod, Int.cast_prod, blockDiagonal_apply_eq, + prodCongrLeft_apply] · intro σ _ hσ rw [mem_preserving_snd] at hσ obtain ⟨⟨k, x⟩, hkx⟩ := not_forall.mp hσ @@ -652,21 +649,13 @@ theorem det_fromBlocks_zero₂₁ (A : Matrix m m R) (B : Matrix m n R) (D : Mat sum_subset (β := R) (subset_univ ((sumCongrHom m n).range : Set (Perm (Sum m n))).toFinset) ?_ rw [sum_mul_sum] simp_rw [univ_product_univ] - rw [(sum_bij (fun (σ : Perm m × Perm n) _ => Equiv.sumCongr σ.fst σ.snd) _ _ _ _).symm] - · intro σ₁₂ h + refine sum_nbij (fun σ ↦ σ.fst.sumCongr σ.snd) ?_ ?_ ?_ ?_ + · intro σ₁₂ _ simp only erw [Set.mem_toFinset, MonoidHom.mem_range] use σ₁₂ simp only [sumCongrHom_apply] - · simp only [forall_prop_of_true, Prod.forall, mem_univ] - intro σ₁ σ₂ - rw [Fintype.prod_sum_type] - simp_rw [Equiv.sumCongr_apply, Sum.map_inr, Sum.map_inl, fromBlocks_apply₁₁, - fromBlocks_apply₂₂] - rw [mul_mul_mul_comm] - congr - rw [sign_sumCongr, Units.val_mul, Int.cast_mul] - · intro σ₁ σ₂ h₁ h₂ + · intro σ₁ _ σ₂ _ dsimp only intro h have h2 : ∀ x, Perm.sumCongr σ₁.fst σ₁.snd x = Perm.sumCongr σ₂.fst σ₂.snd x := @@ -682,6 +671,14 @@ theorem det_fromBlocks_zero₂₁ (A : Matrix m m R) (B : Matrix m n R) (D : Mat use σ₁₂ rw [← hσ₁₂] simp + · simp only [forall_prop_of_true, Prod.forall, mem_univ] + intro σ₁ σ₂ + rw [Fintype.prod_sum_type] + simp_rw [Equiv.sumCongr_apply, Sum.map_inr, Sum.map_inl, fromBlocks_apply₁₁, + fromBlocks_apply₂₂] + rw [mul_mul_mul_comm] + congr + rw [sign_sumCongr, Units.val_mul, Int.cast_mul] · rintro σ - hσn have h1 : ¬∀ x, ∃ y, Sum.inl y = σ (Sum.inl x) := by rw [Set.mem_toFinset] at hσn diff --git a/Mathlib/NumberTheory/ArithmeticFunction.lean b/Mathlib/NumberTheory/ArithmeticFunction.lean index 606b2c417a74e..d8403b476668f 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction.lean @@ -306,35 +306,8 @@ theorem mul_smul' (f g : ArithmeticFunction R) (h : ArithmeticFunction M) : (f * g) • h = f • g • h := by ext n simp only [mul_apply, smul_apply, sum_smul, mul_smul, smul_sum, Finset.sum_sigma'] - apply Finset.sum_bij - pick_goal 5 - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ _H - exact ⟨(k, l * j), (l, j)⟩ - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ H - simp only [Finset.mem_sigma, mem_divisorsAntidiagonal] at H ⊢ - rcases H with ⟨⟨rfl, n0⟩, rfl, i0⟩ - refine' ⟨⟨(mul_assoc _ _ _).symm, n0⟩, trivial, _⟩ - rw [mul_ne_zero_iff] at * - exact ⟨i0.2, n0.2⟩ - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ _H - simp only [mul_assoc] - · rintro ⟨⟨a, b⟩, ⟨c, d⟩⟩ ⟨⟨i, j⟩, ⟨k, l⟩⟩ H₁ H₂ - simp only [Finset.mem_sigma, mem_divisorsAntidiagonal, and_imp, Prod.mk.inj_iff, add_comm, - heq_iff_eq] at H₁ H₂ ⊢ - simp only [Sigma.mk.inj_iff, Prod.mk.injEq, heq_eq_eq, and_imp] -- porting note: added - rintro h h2 rfl rfl - subst h -- porting note: added. The `rintro h ...` above was `rintro rfl ...` - exact ⟨⟨Eq.trans H₁.2.1.symm H₂.2.1, rfl⟩, rfl, rfl⟩ - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ H - refine' ⟨⟨(i * k, l), (i, k)⟩, _, _⟩ - · simp only [Finset.mem_sigma, mem_divisorsAntidiagonal] at H ⊢ - rcases H with ⟨⟨rfl, n0⟩, rfl, j0⟩ - refine' ⟨⟨mul_assoc _ _ _, n0⟩, trivial, _⟩ - rw [mul_ne_zero_iff] at * - exact ⟨n0.1, j0.1⟩ - · simp only [true_and_iff, mem_divisorsAntidiagonal, and_true_iff, Prod.mk.inj_iff, - eq_self_iff_true, Ne.def, mem_sigma, heq_iff_eq] at H ⊢ - rw [H.2.1] + apply Finset.sum_nbij' (fun ⟨⟨_i, j⟩, ⟨k, l⟩⟩ ↦ ⟨(k, l * j), (l, j)⟩) + (fun ⟨⟨i, _j⟩, ⟨k, l⟩⟩ ↦ ⟨(i * k, l), (i, k)⟩) <;> aesop (add simp mul_assoc) #align nat.arithmetic_function.mul_smul' Nat.ArithmeticFunction.mul_smul' theorem one_smul' (b : ArithmeticFunction M) : (1 : ArithmeticFunction R) • b = b := by @@ -679,69 +652,64 @@ theorem int_cast {f : ArithmeticFunction ℤ} [Ring R] (h : f.IsMultiplicative) #align nat.arithmetic_function.is_multiplicative.int_cast Nat.ArithmeticFunction.IsMultiplicative.int_cast theorem mul [CommSemiring R] {f g : ArithmeticFunction R} (hf : f.IsMultiplicative) - (hg : g.IsMultiplicative) : IsMultiplicative (f * g) := - ⟨by - -- porting note was `simp [hf, hg]`. - simp [hf.1, hg.1], - by - simp only [mul_apply] - intro m n cop - rw [sum_mul_sum] - symm - apply sum_bij fun (x : (ℕ × ℕ) × ℕ × ℕ) _h => (x.1.1 * x.2.1, x.1.2 * x.2.2) - · rintro ⟨⟨a1, a2⟩, ⟨b1, b2⟩⟩ h - simp only [mem_divisorsAntidiagonal, Ne.def, mem_product] at h - rcases h with ⟨⟨rfl, ha⟩, ⟨rfl, hb⟩⟩ - simp only [mem_divisorsAntidiagonal, Nat.mul_eq_zero, Ne.def] - constructor - · ring - rw [Nat.mul_eq_zero] at * - apply not_or_of_not ha hb - · rintro ⟨⟨a1, a2⟩, ⟨b1, b2⟩⟩ h - simp only [mem_divisorsAntidiagonal, Ne.def, mem_product] at h - rcases h with ⟨⟨rfl, ha⟩, ⟨rfl, hb⟩⟩ - dsimp only - rw [hf.map_mul_of_coprime cop.coprime_mul_right.coprime_mul_right_right, - hg.map_mul_of_coprime cop.coprime_mul_left.coprime_mul_left_right] - ring - · rintro ⟨⟨a1, a2⟩, ⟨b1, b2⟩⟩ ⟨⟨c1, c2⟩, ⟨d1, d2⟩⟩ hab hcd h - simp only [mem_divisorsAntidiagonal, Ne.def, mem_product] at hab - rcases hab with ⟨⟨rfl, ha⟩, ⟨rfl, hb⟩⟩ - simp only [mem_divisorsAntidiagonal, Ne.def, mem_product] at hcd - simp only [Prod.mk.inj_iff] at h - ext <;> dsimp only - · trans Nat.gcd (a1 * a2) (a1 * b1) - · rw [Nat.gcd_mul_left, cop.coprime_mul_left.coprime_mul_right_right.gcd_eq_one, mul_one] - · rw [← hcd.1.1, ← hcd.2.1] at cop - rw [← hcd.1.1, h.1, Nat.gcd_mul_left, - cop.coprime_mul_left.coprime_mul_right_right.gcd_eq_one, mul_one] - · trans Nat.gcd (a1 * a2) (a2 * b2) - · rw [mul_comm, Nat.gcd_mul_left, cop.coprime_mul_right.coprime_mul_left_right.gcd_eq_one, - mul_one] - · rw [← hcd.1.1, ← hcd.2.1] at cop - rw [← hcd.1.1, h.2, mul_comm, Nat.gcd_mul_left, - cop.coprime_mul_right.coprime_mul_left_right.gcd_eq_one, mul_one] - · trans Nat.gcd (b1 * b2) (a1 * b1) - · rw [mul_comm, Nat.gcd_mul_right, - cop.coprime_mul_right.coprime_mul_left_right.symm.gcd_eq_one, one_mul] - · rw [← hcd.1.1, ← hcd.2.1] at cop - rw [← hcd.2.1, h.1, mul_comm c1 d1, Nat.gcd_mul_left, - cop.coprime_mul_right.coprime_mul_left_right.symm.gcd_eq_one, mul_one] - · trans Nat.gcd (b1 * b2) (a2 * b2) - · rw [Nat.gcd_mul_right, cop.coprime_mul_left.coprime_mul_right_right.symm.gcd_eq_one, - one_mul] - · rw [← hcd.1.1, ← hcd.2.1] at cop - rw [← hcd.2.1, h.2, Nat.gcd_mul_right, - cop.coprime_mul_left.coprime_mul_right_right.symm.gcd_eq_one, one_mul] - · rintro ⟨b1, b2⟩ h - simp only [mem_divisorsAntidiagonal, Ne.def, mem_product] at h - use ((b1.gcd m, b2.gcd m), (b1.gcd n, b2.gcd n)) - simp only [exists_prop, Prod.mk.inj_iff, Ne.def, mem_product, mem_divisorsAntidiagonal] - rw [← cop.gcd_mul _, ← cop.gcd_mul _, ← h.1, Nat.gcd_mul_gcd_of_coprime_of_mul_eq_mul cop h.1, - Nat.gcd_mul_gcd_of_coprime_of_mul_eq_mul cop.symm _] - · rw [Nat.mul_eq_zero, not_or] at h - simp [h.2.1, h.2.2] - rw [mul_comm n m, h.1]⟩ + (hg : g.IsMultiplicative) : IsMultiplicative (f * g) := by + refine ⟨by simp [hf.1, hg.1], ?_⟩ + simp only [mul_apply] + intro m n cop + rw [sum_mul_sum] + symm + apply sum_nbij fun ((i, j), k, l) ↦ (i * k, j * l) + · rintro ⟨⟨a1, a2⟩, ⟨b1, b2⟩⟩ h + simp only [mem_divisorsAntidiagonal, Ne.def, mem_product] at h + rcases h with ⟨⟨rfl, ha⟩, ⟨rfl, hb⟩⟩ + simp only [mem_divisorsAntidiagonal, Nat.mul_eq_zero, Ne.def] + constructor + · ring + rw [Nat.mul_eq_zero] at * + apply not_or_of_not ha hb + · simp only [Set.InjOn, mem_coe, mem_divisorsAntidiagonal, Ne.def, mem_product, Prod.mk.inj_iff] + rintro ⟨⟨a1, a2⟩, ⟨b1, b2⟩⟩ ⟨⟨rfl, ha⟩, ⟨rfl, hb⟩⟩ ⟨⟨c1, c2⟩, ⟨d1, d2⟩⟩ hcd h + simp only [Prod.mk.inj_iff] at h + ext <;> dsimp only + · trans Nat.gcd (a1 * a2) (a1 * b1) + · rw [Nat.gcd_mul_left, cop.coprime_mul_left.coprime_mul_right_right.gcd_eq_one, mul_one] + · rw [← hcd.1.1, ← hcd.2.1] at cop + rw [← hcd.1.1, h.1, Nat.gcd_mul_left, + cop.coprime_mul_left.coprime_mul_right_right.gcd_eq_one, mul_one] + · trans Nat.gcd (a1 * a2) (a2 * b2) + · rw [mul_comm, Nat.gcd_mul_left, cop.coprime_mul_right.coprime_mul_left_right.gcd_eq_one, + mul_one] + · rw [← hcd.1.1, ← hcd.2.1] at cop + rw [← hcd.1.1, h.2, mul_comm, Nat.gcd_mul_left, + cop.coprime_mul_right.coprime_mul_left_right.gcd_eq_one, mul_one] + · trans Nat.gcd (b1 * b2) (a1 * b1) + · rw [mul_comm, Nat.gcd_mul_right, + cop.coprime_mul_right.coprime_mul_left_right.symm.gcd_eq_one, one_mul] + · rw [← hcd.1.1, ← hcd.2.1] at cop + rw [← hcd.2.1, h.1, mul_comm c1 d1, Nat.gcd_mul_left, + cop.coprime_mul_right.coprime_mul_left_right.symm.gcd_eq_one, mul_one] + · trans Nat.gcd (b1 * b2) (a2 * b2) + · rw [Nat.gcd_mul_right, cop.coprime_mul_left.coprime_mul_right_right.symm.gcd_eq_one, + one_mul] + · rw [← hcd.1.1, ← hcd.2.1] at cop + rw [← hcd.2.1, h.2, Nat.gcd_mul_right, + cop.coprime_mul_left.coprime_mul_right_right.symm.gcd_eq_one, one_mul] + · simp only [Set.SurjOn, Set.subset_def, mem_coe, mem_divisorsAntidiagonal, Ne.def, mem_product, + Set.mem_image, exists_prop, Prod.mk.inj_iff] + rintro ⟨b1, b2⟩ h + dsimp at h + use ((b1.gcd m, b2.gcd m), (b1.gcd n, b2.gcd n)) + rw [← cop.gcd_mul _, ← cop.gcd_mul _, ← h.1, Nat.gcd_mul_gcd_of_coprime_of_mul_eq_mul cop h.1, + Nat.gcd_mul_gcd_of_coprime_of_mul_eq_mul cop.symm _] + · rw [Nat.mul_eq_zero, not_or] at h + simp [h.2.1, h.2.2] + rw [mul_comm n m, h.1] + · simp only [mem_divisorsAntidiagonal, Ne.def, mem_product] + rintro ⟨⟨a1, a2⟩, ⟨b1, b2⟩⟩ ⟨⟨rfl, ha⟩, ⟨rfl, hb⟩⟩ + dsimp only + rw [hf.map_mul_of_coprime cop.coprime_mul_right.coprime_mul_right_right, + hg.map_mul_of_coprime cop.coprime_mul_left.coprime_mul_left_right] + ring #align nat.arithmetic_function.is_multiplicative.mul Nat.ArithmeticFunction.IsMultiplicative.mul theorem pmul [CommSemiring R] {f g : ArithmeticFunction R} (hf : f.IsMultiplicative) diff --git a/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean b/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean index bc74b965696b2..f672a452c7d8e 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean @@ -41,7 +41,7 @@ theorem Ico_map_valMinAbs_natAbs_eq_Ico_map_id (p : ℕ) [hp : Fact p.Prime] (a simp [hap, CharP.cast_eq_zero_iff (ZMod p) p, hpe hx, lt_succ_iff, succ_le_iff, pos_iff_ne_zero, natAbs_valMinAbs_le _] have hsurj : ∀ (b : ℕ) (hb : b ∈ Ico 1 (p / 2).succ), - ∃ x ∈ Ico 1 (p / 2).succ, b = (a * x : ZMod p).valMinAbs.natAbs := by + ∃ x, ∃ _ : x ∈ Ico 1 (p / 2).succ, (a * x : ZMod p).valMinAbs.natAbs = b := by intro b hb refine' ⟨(b / a : ZMod p).valMinAbs.natAbs, mem_Ico.mpr ⟨_, _⟩, _⟩ · apply Nat.pos_of_ne_zero @@ -54,10 +54,9 @@ theorem Ico_map_valMinAbs_natAbs_eq_Ico_map_id (p : ℕ) [hp : Fact p.Prime] (a if_pos (le_of_lt_succ (mem_Ico.1 hb).2), Int.natAbs_ofNat] · erw [mul_neg, mul_div_cancel' _ hap, natAbs_valMinAbs_neg, valMinAbs_def_pos, val_cast_of_lt (hep hb), if_pos (le_of_lt_succ (mem_Ico.1 hb).2), Int.natAbs_ofNat] - simp only [← exists_prop] at hsurj exact Multiset.map_eq_map_of_bij_of_nodup _ _ (Finset.nodup _) (Finset.nodup _) - (fun x _ => (a * x : ZMod p).valMinAbs.natAbs) hmem (fun _ _ => rfl) - (inj_on_of_surj_on_of_card_le _ hmem hsurj le_rfl) hsurj + (fun x _ => (a * x : ZMod p).valMinAbs.natAbs) hmem + (inj_on_of_surj_on_of_card_le _ hmem hsurj le_rfl) hsurj (fun _ _ => rfl) #align zmod.Ico_map_val_min_abs_nat_abs_eq_Ico_map_id ZMod.Ico_map_valMinAbs_natAbs_eq_Ico_map_id private theorem gauss_lemma_aux₁ (p : ℕ) [Fact p.Prime] {a : ℤ} diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index 2e567a148a1cd..31a85ba3acf4b 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -511,7 +511,7 @@ open scoped BigOperators theorem prod_eq_abs_norm (x : K) : ∏ w : InfinitePlace K, w x ^ mult w = abs (Algebra.norm ℚ x) := by convert (congr_arg Complex.abs (@Algebra.norm_eq_prod_embeddings ℚ _ _ _ _ ℂ _ _ _ _ _ x)).symm - · rw [map_prod, ← Equiv.prod_comp' RingHom.equivRatAlgHom (fun f => Complex.abs (f x)) + · rw [map_prod, ← Fintype.prod_equiv RingHom.equivRatAlgHom (fun f => Complex.abs (f x)) (fun φ => Complex.abs (φ x)) fun _ => by simp [RingHom.equivRatAlgHom_apply]; rfl] rw [← Finset.prod_fiberwise Finset.univ (fun φ => mk φ) (fun φ => Complex.abs (φ x))] have : ∀ w : InfinitePlace K, ∀ φ ∈ Finset.filter (fun a ↦ mk a = w) Finset.univ, diff --git a/Mathlib/NumberTheory/Wilson.lean b/Mathlib/NumberTheory/Wilson.lean index 719004dc51467..79878b7a5c86b 100644 --- a/Mathlib/NumberTheory/Wilson.lean +++ b/Mathlib/NumberTheory/Wilson.lean @@ -59,7 +59,6 @@ theorem wilsons_lemma : ((p - 1)! : ZMod p) = -1 := by · apply Nat.pos_of_ne_zero; rw [← @val_zero p] intro h; apply Units.ne_zero a (val_injective p h) · exact val_lt _ - · rintro a -; simp only [cast_id, nat_cast_val] · intro _ _ _ _ h; rw [Units.ext_iff]; exact val_injective p h · intro b hb rw [mem_Ico, Nat.succ_le_iff, ← succ_sub hp, Nat.add_one_sub_one, pos_iff_ne_zero] at hb @@ -67,6 +66,7 @@ theorem wilsons_lemma : ((p - 1)! : ZMod p) = -1 := by · intro 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.val_mk0] + · rintro a -; simp only [cast_id, nat_cast_val] #align zmod.wilsons_lemma ZMod.wilsons_lemma @[simp] diff --git a/Mathlib/Probability/StrongLaw.lean b/Mathlib/Probability/StrongLaw.lean index ef94f9d48f0e0..b383b9836cc94 100644 --- a/Mathlib/Probability/StrongLaw.lean +++ b/Mathlib/Probability/StrongLaw.lean @@ -242,16 +242,8 @@ theorem sum_prob_mem_Ioc_le {X : Ω → ℝ} (hint : Integrable X) (hnonneg : 0 exact continuous_const.intervalIntegrable _ _ _ = ∑ i in range N, ∑ j in range (min (i + 1) K), ∫ _ in i..(i + 1 : ℕ), (1 : ℝ) ∂ρ := by simp_rw [sum_sigma'] - refine' sum_bij' (fun (p : Σ _ : ℕ, ℕ) _ => (⟨p.2, p.1⟩ : Σ _ : ℕ, ℕ)) _ (fun a _ => rfl) - (fun (p : Σ _ : ℕ, ℕ) _ => (⟨p.2, p.1⟩ : Σ _ : ℕ, ℕ)) _ _ _ - · rintro ⟨i, j⟩ hij - simp only [mem_sigma, mem_range, mem_Ico] at hij - simp only [hij, Nat.lt_succ_iff.2 hij.2.1, mem_sigma, mem_range, lt_min_iff, and_self_iff] - · rintro ⟨i, j⟩ hij - simp only [mem_sigma, mem_range, lt_min_iff] at hij - simp only [hij, Nat.lt_succ_iff.1 hij.2.1, mem_sigma, mem_range, mem_Ico, and_self_iff] - · rintro ⟨i, j⟩ hij; rfl - · rintro ⟨i, j⟩ hij; rfl + refine' sum_nbij' (fun p ↦ ⟨p.2, p.1⟩) (fun p ↦ ⟨p.2, p.1⟩) _ _ _ _ _ <;> + aesop (add simp Nat.lt_succ_iff) _ ≤ ∑ i in range N, (i + 1) * ∫ _ in i..(i + 1 : ℕ), (1 : ℝ) ∂ρ := by apply sum_le_sum fun i _ => ?_ simp only [Nat.cast_add, Nat.cast_one, sum_const, card_range, nsmul_eq_mul, Nat.cast_min] @@ -354,16 +346,8 @@ theorem sum_variance_truncation_le {X : Ω → ℝ} (hint : Integrable X) (hnonn exact (continuous_id.pow _).intervalIntegrable _ _ _ = ∑ k in range K, (∑ j in Ioo k K, ((j : ℝ) ^ 2)⁻¹) * ∫ x in k..(k + 1 : ℕ), x ^ 2 ∂ρ := by simp_rw [mul_sum, sum_mul, sum_sigma'] - refine' sum_bij' (fun (p : Σ _ : ℕ, ℕ) _ => (⟨p.2, p.1⟩ : Σ _ : ℕ, ℕ)) _ (fun a _ => rfl) - (fun (p : Σ _ : ℕ, ℕ) _ => (⟨p.2, p.1⟩ : Σ _ : ℕ, ℕ)) _ _ _ - · rintro ⟨i, j⟩ hij - simp only [mem_sigma, mem_range, mem_filter] at hij - simp [hij, mem_sigma, mem_range, and_self_iff, hij.2.trans hij.1] - · rintro ⟨i, j⟩ hij - simp only [mem_sigma, mem_range, mem_Ioo] at hij - simp only [hij, mem_sigma, mem_range, and_self_iff] - · rintro ⟨i, j⟩ hij; rfl - · rintro ⟨i, j⟩ hij; rfl + refine' sum_nbij' (fun p ↦ ⟨p.2, p.1⟩) (fun p ↦ ⟨p.2, p.1⟩) _ _ _ _ _ <;> + aesop (add unsafe lt_trans) _ ≤ ∑ k in range K, 2 / (k + 1 : ℝ) * ∫ x in k..(k + 1 : ℕ), x ^ 2 ∂ρ := by apply sum_le_sum fun k _ => ?_ refine' mul_le_mul_of_nonneg_right (sum_Ioo_inv_sq_le _ _) _ @@ -458,17 +442,11 @@ theorem strong_law_aux1 {c : ℝ} (c_one : 1 < c) {ε : ℝ} (εpos : 0 < ε) : _ = ∑ j in range (u (N - 1)), (∑ i in (range N).filter fun i => j < u i, ((u i : ℝ) ^ 2)⁻¹) * Var[Y j] := by simp_rw [mul_sum, sum_mul, sum_sigma'] - refine' sum_bij' (fun (p : Σ _ : ℕ, ℕ) _ => (⟨p.2, p.1⟩ : Σ _ : ℕ, ℕ)) _ (fun a _ => rfl) - (fun (p : Σ _ : ℕ, ℕ) _ => (⟨p.2, p.1⟩ : Σ _ : ℕ, ℕ)) _ _ _ - · rintro ⟨i, j⟩ hij - simp only [mem_sigma, mem_range] at hij - simp only [hij.1, hij.2, mem_sigma, mem_range, mem_filter, and_true_iff] - exact hij.2.trans_le (u_mono (Nat.le_sub_one_of_lt hij.1)) - · rintro ⟨i, j⟩ hij - simp only [mem_sigma, mem_range, mem_filter] at hij - simp only [hij.2.1, hij.2.2, mem_sigma, mem_range, and_self_iff] - · rintro ⟨i, j⟩ hij; rfl - · rintro ⟨i, j⟩ hij; rfl + refine' sum_nbij' (fun p ↦ ⟨p.2, p.1⟩) (fun p ↦ ⟨p.2, p.1⟩) _ _ _ _ _ + · simp only [mem_sigma, mem_range, filter_congr_decidable, mem_filter, and_imp, + Sigma.forall] + exact fun a b haN hb ↦ ⟨hb.trans_le $ u_mono $ Nat.le_pred_of_lt haN, haN, hb⟩ + all_goals aesop _ ≤ ∑ j in range (u (N - 1)), c ^ 5 * (c - 1)⁻¹ ^ 3 / ↑j ^ 2 * Var[Y j] := by apply sum_le_sum fun j hj => ?_ rcases @eq_zero_or_pos _ _ j with (rfl | hj) diff --git a/Mathlib/RingTheory/Discriminant.lean b/Mathlib/RingTheory/Discriminant.lean index 113aada14e678..ef1f4f28f3aa8 100644 --- a/Mathlib/RingTheory/Discriminant.lean +++ b/Mathlib/RingTheory/Discriminant.lean @@ -257,35 +257,20 @@ theorem discr_powerBasis_eq_norm [IsSeparable K L] : (IsAlgClosed.splits_codomain _) (hroots σ), ← Finset.prod_mk _ (hnodup.erase _)] rw [prod_sigma', prod_sigma'] - refine' - prod_bij (fun i _ => ⟨e i.2, e i.1 pb.gen⟩) (fun i hi => _) (fun i _ => by simp) - (fun i j hi hj hij => _) fun σ hσ => _ - · simp only [true_and_iff, Finset.mem_mk, mem_univ, mem_sigma] - rw [Multiset.mem_erase_of_ne fun h => ?_] - · exact hroots _ --- Porting note: `@mem_compl` was not necessary. - · simp only [true_and_iff, mem_univ, Ne.def, mem_sigma, @mem_compl _ _ _ (_), - mem_singleton] at hi - rw [← PowerBasis.liftEquiv_apply_coe, ← PowerBasis.liftEquiv_apply_coe] at h - exact hi (e.injective <| pb.liftEquiv.injective <| Subtype.eq h.symm) - · simp only [Sigma.mk.inj_iff, EmbeddingLike.apply_eq_iff_eq, heq_eq_eq] at hij - have h := hij.2 - rw [← PowerBasis.liftEquiv_apply_coe, ← PowerBasis.liftEquiv_apply_coe] at h - refine' Sigma.eq (Equiv.injective e (Equiv.injective _ (Subtype.eq h))) (by simp [hij.1]) - · simp only [true_and_iff, Finset.mem_mk, mem_univ, mem_sigma] at hσ ⊢ - simp only [Sigma.exists, exists_prop, mem_compl, mem_singleton, Ne.def] - refine' ⟨e.symm (PowerBasis.lift pb σ.2 _), e.symm σ.1, ⟨_, Sigma.eq _ _⟩⟩ - · rw [aeval_def, eval₂_eq_eval_map, ← IsRoot.def, ← mem_roots] - · exact Multiset.erase_subset _ _ hσ - · simp [minpoly.ne_zero (IsSeparable.isIntegral K pb.gen)] --- Porting note: the `simp only` was not needed. - · simp only [@mem_compl _ _ _ (_), mem_singleton] - intro h - replace h := AlgHom.congr_fun (Equiv.injective _ h) pb.gen - rw [PowerBasis.lift_gen] at h - rw [← h] at hσ - exact hnodup.not_mem_erase hσ - all_goals simp + refine prod_bij' (fun i _ ↦ ⟨e i.2, e i.1 pb.gen⟩) + (fun σ hσ ↦ ⟨e.symm (PowerBasis.lift pb σ.2 ?_), e.symm σ.1⟩) ?_ ?_ ?_ ?_ (fun i _ ↦ by simp) + -- Porting note: `@mem_compl` was not necessary. + <;> simp only [mem_sigma, mem_univ, Finset.mem_mk, hnodup.mem_erase_iff, IsRoot.def, mem_roots', + minpoly.ne_zero (IsSeparable.isIntegral K pb.gen), not_false_eq_true, mem_singleton, true_and, + @mem_compl _ _ _ (_), Sigma.forall, Equiv.apply_symm_apply, PowerBasis.lift_gen, and_imp, + implies_true, forall_const, Equiv.symm_apply_apply, Sigma.ext_iff, Equiv.symm_apply_eq, + heq_eq_eq, and_true] at * + · simpa only [aeval_def, eval₂_eq_eval_map] using hσ.2.2 + · exact fun a b hba ↦ ⟨fun h ↦ hba $ e.injective $ pb.algHom_ext h.symm, hroots _⟩ + · rintro a b hba ha + rw [ha, PowerBasis.lift_gen] at hba + exact hba.1 rfl + · exact fun a b _ ↦ pb.algHom_ext $ pb.lift_gen _ _ #align algebra.discr_power_basis_eq_norm Algebra.discr_powerBasis_eq_norm section Integral diff --git a/Mathlib/RingTheory/HahnSeries.lean b/Mathlib/RingTheory/HahnSeries.lean index a46cbdc5b51df..cb8ac26203e36 100644 --- a/Mathlib/RingTheory/HahnSeries.lean +++ b/Mathlib/RingTheory/HahnSeries.lean @@ -780,27 +780,9 @@ private theorem mul_assoc' [NonUnitalSemiring R] (x y z : HahnSeries Γ R) : rw [mul_coeff_left' (x.isPwo_support.add y.isPwo_support) support_mul_subset_add_support, mul_coeff_right' (y.isPwo_support.add z.isPwo_support) support_mul_subset_add_support] simp only [mul_coeff, add_coeff, sum_mul, mul_sum, sum_sigma'] - refine' sum_bij_ne_zero (fun a _ _ => ⟨⟨a.2.1, a.2.2 + a.1.2⟩, ⟨a.2.2, a.1.2⟩⟩) _ _ _ _ - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ H1 H2 - simp only [and_true_iff, Set.image2_add, eq_self_iff_true, mem_addAntidiagonal, Ne.def, - Set.image_prod, mem_sigma, Set.mem_setOf_eq] at H1 H2 ⊢ - obtain ⟨⟨H3, nz, rfl⟩, nx, ny, rfl⟩ := H1 - exact ⟨⟨nx, Set.add_mem_add ny nz, (add_assoc _ _ _).symm⟩, ny, nz⟩ - · rintro ⟨⟨i1, j1⟩, k1, l1⟩ ⟨⟨i2, j2⟩, k2, l2⟩ H1 H2 H3 H4 H5 - simp only [Set.image2_add, Prod.mk.inj_iff, mem_addAntidiagonal, Ne.def, Set.image_prod, - mem_sigma, Set.mem_setOf_eq, heq_iff_eq] at H1 H3 H5 - obtain (⟨⟨rfl, _⟩, rfl, rfl⟩ : (k1 = k2 ∧ l1 + j1 = l2 + j2) ∧ l1 = l2 ∧ j1 = j2) := - by simpa using H5 - simp only [and_true_iff, Prod.mk.inj_iff, eq_self_iff_true, heq_iff_eq, ← H1.2.2.2, ← H3.2.2.2] - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ H1 H2 - simp only [exists_prop, Set.image2_add, Prod.mk.inj_iff, mem_addAntidiagonal, Sigma.exists, - Ne.def, Set.image_prod, mem_sigma, Set.mem_setOf_eq, heq_iff_eq, Prod.exists] at H1 H2 ⊢ - obtain ⟨⟨nx, H, rfl⟩, ny, nz, rfl⟩ := H1 - exact - ⟨i + k, l, i, k, ⟨⟨Set.add_mem_add nx ny, nz, add_assoc _ _ _⟩ , nx, ny, rfl⟩, - fun h => H2 <| by rw [← h, mul_assoc], rfl⟩ - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ _ _ - simp [mul_assoc] + apply Finset.sum_nbij' (fun ⟨⟨_i, j⟩, ⟨k, l⟩⟩ ↦ ⟨(k, l + j), (l, j)⟩) + (fun ⟨⟨i, _j⟩, ⟨k, l⟩⟩ ↦ ⟨(i + k, l), (i, k)⟩) <;> + aesop (add safe Set.add_mem_add) (add simp [add_assoc, mul_assoc]) instance [NonUnitalNonAssocSemiring R] : NonUnitalNonAssocSemiring (HahnSeries Γ R) := { inferInstanceAs (AddCommMonoid (HahnSeries Γ R)), @@ -830,15 +812,12 @@ instance [Semiring R] : Semiring (HahnSeries Γ R) := { inferInstanceAs (NonAssocSemiring (HahnSeries Γ R)), inferInstanceAs (NonUnitalSemiring (HahnSeries Γ R)) with } -instance [NonUnitalCommSemiring R] : NonUnitalCommSemiring (HahnSeries Γ R) := - { inferInstanceAs (NonUnitalSemiring (HahnSeries Γ R)) with - mul_comm := fun x y => by - ext - simp_rw [mul_coeff, mul_comm] - refine' - sum_bij (fun a _ => a.swap) (fun a ha => _) (fun a _ => rfl) - (fun _ _ _ _ => Prod.swap_inj.1) fun a ha => ⟨a.swap, _, a.swap_swap.symm⟩ <;> - rwa [swap_mem_addAntidiagonal] } +instance [NonUnitalCommSemiring R] : NonUnitalCommSemiring (HahnSeries Γ R) where + __ : NonUnitalSemiring (HahnSeries Γ R) := inferInstance + mul_comm x y := by + ext + simp_rw [mul_coeff, mul_comm] + exact Finset.sum_equiv (Equiv.prodComm _ _) (fun _ ↦ swap_mem_addAntidiagonal.symm) $ by simp instance [CommSemiring R] : CommSemiring (HahnSeries Γ R) := { inferInstanceAs (NonUnitalCommSemiring (HahnSeries Γ R)), diff --git a/Mathlib/RingTheory/IntegralDomain.lean b/Mathlib/RingTheory/IntegralDomain.lean index 813c6e500a38b..5eb43c6b4eca0 100644 --- a/Mathlib/RingTheory/IntegralDomain.lean +++ b/Mathlib/RingTheory/IntegralDomain.lean @@ -255,15 +255,14 @@ theorem sum_hom_units_eq_zero (f : G →* R) (hf : f ≠ 1) : ∑ g : G, f g = 0 (∑ b : MonoidHom.range f.toHomUnits, ((b : Rˣ) : R)) = ∑ n in range (orderOf x), ((x : Rˣ) : R) ^ n := Eq.symm <| - sum_bij (fun n _ => x ^ n) (by simp only [mem_univ, forall_true_iff]) - (by simp only [imp_true_iff, eq_self_iff_true, Subgroup.coe_pow, - Units.val_pow_eq_pow_val]) - (fun m n hm hn => pow_injOn_Iio_orderOf (by simpa only [mem_range] using hm) - (by simpa only [mem_range] using hn)) + sum_nbij (x ^ ·) (by simp only [mem_univ, forall_true_iff]) + (by simpa using pow_injOn_Iio_orderOf) (fun b _ => let ⟨n, hn⟩ := hx b ⟨n % orderOf x, mem_range.2 (Nat.mod_lt _ (orderOf_pos _)), -- Porting note: have to use `dsimp` to apply the function by dsimp at hn ⊢; rw [pow_mod_orderOf, hn]⟩) + (by simp only [imp_true_iff, eq_self_iff_true, Subgroup.coe_pow, + Units.val_pow_eq_pow_val]) _ = 0 := ?_ rw [← mul_left_inj' hx1, zero_mul, geom_sum_mul] diff --git a/Mathlib/RingTheory/Noetherian.lean b/Mathlib/RingTheory/Noetherian.lean index 33ec72b17b6dc..3eef173dc2b31 100644 --- a/Mathlib/RingTheory/Noetherian.lean +++ b/Mathlib/RingTheory/Noetherian.lean @@ -588,7 +588,7 @@ theorem isNoetherian_of_fg_of_noetherian {R M} [Ring R] [AddCommGroup M] [Module rcases hn with ⟨l, hl1, hl2⟩ refine' ⟨fun x => l x, Subtype.ext _⟩ change (∑ i in s.attach, l i • (i : M)) = n - rw [@Finset.sum_attach M M s _ fun i => l i • i, ← hl2, + rw [s.sum_attach fun i ↦ l i • i, ← hl2, Finsupp.total_apply, Finsupp.sum, eq_comm] refine' Finset.sum_subset hl1 fun x _ hx => _ rw [Finsupp.not_mem_support_iff.1 hx, zero_smul] diff --git a/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean b/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean index 72a6ae6b66fab..90be3c5eb3061 100644 --- a/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean +++ b/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean @@ -119,7 +119,7 @@ theorem integralNormalization_eval₂_eq_zero {p : R[X]} (f : R →+* S) {z : S} f (coeff (integralNormalization p) i.1 * p.leadingCoeff ^ i.1) * z ^ i.1 := by rw [eval₂_eq_sum, sum_def, support_integralNormalization] simp only [mul_comm z, mul_pow, mul_assoc, RingHom.map_pow, RingHom.map_mul] - exact Finset.sum_attach.symm + rw [← Finset.sum_attach] _ = p.support.attach.sum fun i => f (coeff p i.1 * p.leadingCoeff ^ (natDegree p - 1)) * z ^ i.1 := by @@ -141,7 +141,7 @@ theorem integralNormalization_eval₂_eq_zero {p : R[X]} (f : R →+* S) {z : S} simp_rw [eval₂_eq_sum, sum_def, fun i => mul_comm (coeff p i), RingHom.map_mul, RingHom.map_pow, mul_assoc, ← Finset.mul_sum] congr 1 - exact @Finset.sum_attach _ _ p.support _ fun i => f (p.coeff i) * z ^ i + exact p.support.sum_attach fun i ↦ f (p.coeff i) * z ^ i _ = 0 := by rw [hz, mul_zero] #align polynomial.integral_normalization_eval₂_eq_zero Polynomial.integralNormalization_eval₂_eq_zero diff --git a/Mathlib/RingTheory/PowerSeries/Basic.lean b/Mathlib/RingTheory/PowerSeries/Basic.lean index 4004fcbd02b49..42b7957cbec84 100644 --- a/Mathlib/RingTheory/PowerSeries/Basic.lean +++ b/Mathlib/RingTheory/PowerSeries/Basic.lean @@ -298,27 +298,8 @@ protected theorem mul_assoc (φ₁ φ₂ φ₃ : MvPowerSeries σ R) : φ₁ * ext1 n classical simp only [coeff_mul, Finset.sum_mul, Finset.mul_sum, Finset.sum_sigma'] - refine' Finset.sum_bij (fun p _ => ⟨(p.2.1, p.2.2 + p.1.2), (p.2.2, p.1.2)⟩) _ _ _ _ <;> - simp only [mem_antidiagonal, Finset.mem_sigma, heq_iff_eq, Prod.mk.inj_iff, and_imp, - exists_prop] - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ - dsimp only - rintro rfl rfl - simp [add_assoc] - · rintro ⟨⟨a, b⟩, ⟨c, d⟩⟩ - dsimp only - rintro rfl rfl - apply mul_assoc - · rintro ⟨⟨a, b⟩, ⟨c, d⟩⟩ ⟨⟨i, j⟩, ⟨k, l⟩⟩ - dsimp only - rintro rfl rfl - rfl - simp only [Sigma.mk.inj_iff, Prod.mk.injEq, heq_iff_eq, and_imp] - rintro rfl - rfl rfl - simp only [and_self] - · rintro ⟨⟨i, j⟩, ⟨k, l⟩⟩ - dsimp only - rintro rfl rfl - refine' ⟨⟨(i + k, l), (i, k)⟩, _, _⟩ <;> simp [add_assoc] + apply Finset.sum_nbij' (fun ⟨⟨_i, j⟩, ⟨k, l⟩⟩ ↦ ⟨(k, l + j), (l, j)⟩) + (fun ⟨⟨i, _j⟩, ⟨k, l⟩⟩ ↦ ⟨(i + k, l), (i, k)⟩) <;> aesop (add simp [add_assoc, mul_assoc]) #align mv_power_series.mul_assoc MvPowerSeries.mul_assoc instance : Semiring (MvPowerSeries σ R) := @@ -1975,35 +1956,21 @@ theorem coeff_inv_aux (n : ℕ) (a : R) (φ : R⟦X⟧) : split_ifs; · rfl congr 1 symm - apply Finset.sum_bij fun (p : ℕ × ℕ) _h => (single () p.1, single () p.2) - · rintro ⟨i, j⟩ hij - rw [mem_antidiagonal] at hij - rw [mem_antidiagonal, ← Finsupp.single_add, hij] + apply Finset.sum_nbij' (fun (a, b) ↦ (single () a, single () b)) + fun (f, g) ↦ (f (), g ()) + · aesop + · aesop + · aesop + · aesop · rintro ⟨i, j⟩ _hij - by_cases H : j < n - · rw [if_pos H, if_pos] - · rfl - constructor - · rintro ⟨⟩ - simpa [Finsupp.single_eq_same] using le_of_lt H - · intro hh - rw [lt_iff_not_ge] at H - apply H - simpa [Finsupp.single_eq_same] using hh () - · rw [if_neg H, if_neg] - rintro ⟨_h₁, h₂⟩ - apply h₂ - rintro ⟨⟩ - simpa [Finsupp.single_eq_same] using not_lt.1 H - · rintro ⟨i, j⟩ ⟨k, l⟩ _hij _hkl - simpa only [Prod.mk.inj_iff, Finsupp.unique_single_eq_iff] using id - · rintro ⟨f, g⟩ hfg - refine' ⟨(f (), g ()), _, _⟩ - · rw [mem_antidiagonal] at hfg - rw [mem_antidiagonal, ← Finsupp.add_apply, hfg, Finsupp.single_eq_same] - · rw [Prod.mk.inj_iff] - dsimp - exact ⟨Finsupp.unique_single f, Finsupp.unique_single g⟩ + obtain H | H := le_or_lt n j + · aesop + rw [if_pos H, if_pos] + · rfl + refine ⟨?_, fun hh ↦ H.not_le ?_⟩ + · rintro ⟨⟩ + simpa [Finsupp.single_eq_same] using le_of_lt H + · simpa [Finsupp.single_eq_same] using hh () #align power_series.coeff_inv_aux PowerSeries.coeff_inv_aux /-- A formal power series is invertible if the constant coefficient is invertible.-/ From 521f71ff969b69b7c1ff2ad1337d994c650bce16 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Wed, 27 Dec 2023 20:59:09 +0000 Subject: [PATCH 263/353] feat: misc lemmas on uniform spaces (#9305) --- Mathlib/Topology/UniformSpace/Basic.lean | 13 +++++++++++++ Mathlib/Topology/UniformSpace/UniformEmbedding.lean | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/Mathlib/Topology/UniformSpace/Basic.lean b/Mathlib/Topology/UniformSpace/Basic.lean index c253e00725bea..42333bb75d707 100644 --- a/Mathlib/Topology/UniformSpace/Basic.lean +++ b/Mathlib/Topology/UniformSpace/Basic.lean @@ -720,6 +720,14 @@ theorem nhds_eq_comap_uniformity {x : α} : 𝓝 x = (𝓤 α).comap (Prod.mk x) rw [mem_nhds_uniformity_iff_right, mem_comap_prod_mk] #align nhds_eq_comap_uniformity nhds_eq_comap_uniformity +theorem nhdsWithin_eq_comap_uniformity_of_mem {x : α} {T : Set α} (hx : x ∈ T) (S : Set α) : + 𝓝[S] x = (𝓤 α ⊓ 𝓟 (T ×ˢ S)).comap (Prod.mk x) := by + simp [nhdsWithin, nhds_eq_comap_uniformity, hx] + +theorem nhdsWithin_eq_comap_uniformity {x : α} (S : Set α) : + 𝓝[S] x = (𝓤 α ⊓ 𝓟 (univ ×ˢ S)).comap (Prod.mk x) := + nhdsWithin_eq_comap_uniformity_of_mem (mem_univ _) S + /-- See also `isOpen_iff_open_ball_subset`. -/ theorem isOpen_iff_ball_subset {s : Set α} : IsOpen s ↔ ∀ x ∈ s, ∃ V ∈ 𝓤 α, ball x V ⊆ s := by simp_rw [isOpen_iff_mem_nhds, nhds_eq_comap_uniformity, mem_comap, ball] @@ -752,6 +760,11 @@ theorem UniformSpace.ball_mem_nhds (x : α) ⦃V : Set (α × α)⦄ (V_in : V exact ⟨V, V_in, Subset.rfl⟩ #align uniform_space.ball_mem_nhds UniformSpace.ball_mem_nhds +theorem UniformSpace.ball_mem_nhdsWithin {x : α} {S : Set α} ⦃V : Set (α × α)⦄ (x_in : x ∈ S) + (V_in : V ∈ 𝓤 α ⊓ 𝓟 (S ×ˢ S)) : ball x V ∈ 𝓝[S] x := by + rw [nhdsWithin_eq_comap_uniformity_of_mem x_in, mem_comap] + exact ⟨V, V_in, Subset.rfl⟩ + theorem UniformSpace.mem_nhds_iff_symm {x : α} {s : Set α} : s ∈ 𝓝 x ↔ ∃ V ∈ 𝓤 α, SymmetricRel V ∧ ball x V ⊆ s := by rw [UniformSpace.mem_nhds_iff] diff --git a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean index d757d91eb3e2f..71243a4599240 100644 --- a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean +++ b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean @@ -98,6 +98,12 @@ theorem UniformInducing.uniformContinuous_iff {f : α → β} {g : β → γ} (h rw [← hg.comap_uniformity, ← map_le_iff_le_comap, Filter.map_map]; rfl #align uniform_inducing.uniform_continuous_iff UniformInducing.uniformContinuous_iff +theorem UniformInducing.uniformContinuousOn_iff {f : α → β} {g : β → γ} {S : Set α} + (hg : UniformInducing g) : + UniformContinuousOn f S ↔ UniformContinuousOn (g ∘ f) S := by + dsimp only [UniformContinuousOn, Tendsto] + rw [← hg.comap_uniformity, ← map_le_iff_le_comap, Filter.map_map]; rfl + theorem UniformInducing.inducing {f : α → β} (h : UniformInducing f) : Inducing f := by obtain rfl := h.comap_uniformSpace exact inducing_induced f From 5dee9c0a2087a1b797ceb5a72cf5ac43669a03ff Mon Sep 17 00:00:00 2001 From: damiano Date: Wed, 27 Dec 2023 22:11:11 +0000 Subject: [PATCH 264/353] fix(Tactic/MoveAdd): add missing `withContext` (#9306) Adds a missing `withContext`, as mentioned in this [Zulip message](https://leanprover.zulipchat.com/#narrow/stream/144837-PR-reviews/topic/.2313483.20.60move_add.60/near/409960750). I also added the relevant test. --- Mathlib/Tactic/MoveAdd.lean | 2 +- test/MoveAdd.lean | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Mathlib/Tactic/MoveAdd.lean b/Mathlib/Tactic/MoveAdd.lean index 1dc9815dc4756..99e38ea26f949 100644 --- a/Mathlib/Tactic/MoveAdd.lean +++ b/Mathlib/Tactic/MoveAdd.lean @@ -358,7 +358,7 @@ operation and a list of "instructions" `instr` that it passes to `permuteExpr`. `op`-analogues of `add_comm, add_assoc, add_left_comm`. -/ def reorderAndSimp (mv : MVarId) (instr : List (Expr × Bool)) : - MetaM (List MVarId) := do + MetaM (List MVarId) := mv.withContext do let permExpr ← permuteExpr op (← mv.getType'') instr -- generate the implication `permutedMv → mv = permutedMv → mv` let eqmpr ← mkAppM ``Eq.mpr #[← mkFreshExprMVar (← mkEq (← mv.getType) permExpr)] diff --git a/test/MoveAdd.lean b/test/MoveAdd.lean index 38a84625f91af..970f1125b2b1f 100644 --- a/test/MoveAdd.lean +++ b/test/MoveAdd.lean @@ -88,6 +88,12 @@ example {a b c d e : Prop} (h : a ∨ b ∨ c ∨ d ∨ e) : a ∨ c ∨ e ∨ b end left_assoc +example (k : ℕ) (h0 : 0 + 2 = 9 + 0) (h9 : k + 2 = k + 9) : k + 2 = 9 + k := by + induction' k with k _ih + · exact h0 + · move_add [9] + exact h9 + -- Testing internals of the tactic `move_add`. section tactic open Mathlib.MoveAdd From 6cab3d646c38b08ac405dd08d69f9cd87938b5c1 Mon Sep 17 00:00:00 2001 From: Michael Stoll Date: Thu, 28 Dec 2023 01:33:58 +0000 Subject: [PATCH 265/353] feat(NumberTheory.SmoothNumbers): add `{smooth|rough}NumbersUpTo` and some API (#9240) This adds definitions of the `k`-smooth numbers up to and including `N` as a `Finset` and of its complement in `{1, ..., N}` plus some API, in particular cardinality bounds. There are also a few additional API lemmas for `Nat.primesBelow` and `Nat.smoothNumbers` (including a decidability instance for membership in the latter). This is a PR in preparation of the divergence of the sum of the reciprocals of the primes. See [here](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Sum.20over.201.2Fp.20diverges/near/409835682) on Zulip. Co-authored-by: Junyan Xu --- Mathlib/Data/Nat/Factorization/Basic.lean | 15 ++- Mathlib/NumberTheory/SmoothNumbers.lean | 135 +++++++++++++++++++++- 2 files changed, 144 insertions(+), 6 deletions(-) diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index 0259da359732d..04a3e396ce47a 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -866,7 +866,8 @@ theorem prod_pow_prime_padicValNat (n : Nat) (hn : n ≠ 0) (m : Nat) (pr : n < -- TODO: Port lemmas from `Data/Nat/Multiplicity` to here, re-written in terms of `factorization` -/-- Exactly `n / p` naturals in `[1, n]` are multiples of `p`. -/ +/-- Exactly `n / p` naturals in `[1, n]` are multiples of `p`. +See `Nat.card_multiples'` for an alternative spelling of the statement. -/ theorem card_multiples (n p : ℕ) : card ((Finset.range n).filter fun e => p ∣ e + 1) = n / p := by induction' n with n hn · simp @@ -887,4 +888,16 @@ theorem Ioc_filter_dvd_card_eq_div (n p : ℕ) : ((Ioc 0 n).filter fun x => p Finset.mem_filter, mem_Ioc, not_le.2 (lt_add_one n), Nat.succ_eq_add_one] #align nat.Ioc_filter_dvd_card_eq_div Nat.Ioc_filter_dvd_card_eq_div +/-- There are exactly `⌊N/n⌋` positive multiples of `n` that are `≤ N`. +See `Nat.card_multiples` for a "shifted-by-one" version. -/ +lemma card_multiples' (N n : ℕ) : + ((Finset.range N.succ).filter (fun k ↦ k ≠ 0 ∧ n ∣ k)).card = N / n := by + induction N with + | zero => simp + | succ N ih => + rw [Finset.range_succ, Finset.filter_insert] + by_cases h : n ∣ N.succ + · simp [h, succ_div_of_dvd, ih] + · simp [h, succ_div_of_not_dvd, ih] + end Nat diff --git a/Mathlib/NumberTheory/SmoothNumbers.lean b/Mathlib/NumberTheory/SmoothNumbers.lean index 9caa0b7f660dc..a99c3f0a8c027 100644 --- a/Mathlib/NumberTheory/SmoothNumbers.lean +++ b/Mathlib/NumberTheory/SmoothNumbers.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Stoll -/ import Mathlib.Data.Nat.Factorization.Basic +import Mathlib.Data.Nat.Squarefree /-! # Smooth numbers @@ -16,6 +17,11 @@ We also define the finite set `Nat.primesBelow n` to be the set of prime numbers The main definition `Nat.equivProdNatSmoothNumbers` establishes the bijection between `ℕ × (smoothNumbers p)` and `smoothNumbers (p+1)` given by sending `(e, n)` to `p^e * n`. Here `p` is a prime number. + +Additionally, we define `Nat.smoothNumbersUpTo N n` as the `Finset` of `n`-smooth numbers +up to and including `N`, and similarly `Nat.roughNumbersUpTo` for its complement in `{1, ..., N}`, +and we provide some API, in particular bounds for their cardinalities; see +`Nat.smoothNumbersUpTo_card_le` and `Nat.roughNumbersUpTo_card_le`. -/ namespace Nat @@ -27,6 +33,9 @@ def primesBelow (n : ℕ) : Finset ℕ := (Finset.range n).filter (fun p ↦ p.P lemma primesBelow_zero : primesBelow 0 = ∅ := by rw [primesBelow, Finset.range_zero, Finset.filter_empty] +lemma mem_primesBelow {k n : ℕ} : + n ∈ primesBelow k ↔ n < k ∧ n.Prime := by simp [primesBelow] + lemma prime_of_mem_primesBelow {p n : ℕ} (h : p ∈ n.primesBelow) : p.Prime := (Finset.mem_filter.mp h).2 @@ -47,14 +56,37 @@ def smoothNumbers (n : ℕ) : Set ℕ := {m | m ≠ 0 ∧ ∀ p ∈ factors m, p lemma mem_smoothNumbers {n m : ℕ} : m ∈ smoothNumbers n ↔ m ≠ 0 ∧ ∀ p ∈ factors m, p < n := Iff.rfl +/-- Membership in `Nat.smoothNumbers n` is decidable. -/ +instance (n : ℕ) : DecidablePred (· ∈ smoothNumbers n) := + inferInstanceAs <| DecidablePred fun x ↦ x ∈ {m | m ≠ 0 ∧ ∀ p ∈ factors m, p < n} + +/-- A number that divides an `n`-smooth number is itself `n`-smooth. -/ +lemma mem_smoothNumbers_of_dvd {n m k : ℕ} (h : m ∈ smoothNumbers n) (h' : k ∣ m) (hk : k ≠ 0) : + k ∈ smoothNumbers n := by + rw [mem_smoothNumbers] at h ⊢ + obtain ⟨h₁, h₂⟩ := h + refine ⟨hk, fun p hp ↦ h₂ p ?_⟩ + rw [mem_factors <| by assumption] at hp ⊢ + exact ⟨hp.1, hp.2.trans h'⟩ + +/-- `m` is `n`-smooth if and only if `m` is nonzero and all prime divisors `≤ m` of `m` +are less than `n`. -/ +lemma mem_smoothNumbers_iff_forall_le {n m : ℕ} : + m ∈ smoothNumbers n ↔ m ≠ 0 ∧ ∀ p ≤ m, p.Prime → p ∣ m → p < n := by + simp_rw [mem_smoothNumbers, mem_factors'] + exact ⟨fun ⟨H₀, H₁⟩ ↦ ⟨H₀, fun p _ hp₂ hp₃ ↦ H₁ p ⟨hp₂, hp₃, H₀⟩⟩, + fun ⟨H₀, H₁⟩ ↦ + ⟨H₀, fun p ⟨hp₁, hp₂, hp₃⟩ ↦ H₁ p (Nat.le_of_dvd (Nat.pos_of_ne_zero hp₃) hp₂) hp₁ hp₂⟩⟩ + /-- `m` is `n`-smooth if and only if all prime divisors of `m` are less than `n`. -/ lemma mem_smoothNumbers' {n m : ℕ} : m ∈ smoothNumbers n ↔ ∀ p, p.Prime → p ∣ m → p < n := by - rw [mem_smoothNumbers] - refine ⟨fun H p hp h ↦ H.2 p <| (mem_factors_iff_dvd H.1 hp).mpr h, - fun H ↦ ⟨?_, fun p hp ↦ H p (prime_of_mem_factors hp) (dvd_of_mem_factors hp)⟩⟩ - rintro rfl obtain ⟨p, hp₁, hp₂⟩ := exists_infinite_primes n - exact ((H p hp₂ <| dvd_zero _).trans_le hp₁).false + rw [mem_smoothNumbers_iff_forall_le] + exact ⟨fun ⟨H₀, H₁⟩ ↦ fun p hp₁ hp₂ ↦ H₁ p (Nat.le_of_dvd (Nat.pos_of_ne_zero H₀) hp₂) hp₁ hp₂, + fun H ↦ ⟨fun h ↦ ((H p hp₂ <| h.symm ▸ dvd_zero p).trans_le hp₁).false, fun p _ ↦ H p⟩⟩ + +lemma ne_zero_of_mem_smoothNumbers {n m : ℕ} (h : m ∈ smoothNumbers n) : m ≠ 0 := + (mem_smoothNumbers_iff_forall_le.mp h).1 @[simp] lemma smoothNumbers_zero : smoothNumbers 0 = {1} := by @@ -166,4 +198,97 @@ lemma equivProdNatSmoothNumbers_apply {p e m : ℕ} (hp: p.Prime) (hm : m ∈ p. lemma equivProdNatSmoothNumbers_apply' {p : ℕ} (hp: p.Prime) (x : ℕ × p.smoothNumbers) : equivProdNatSmoothNumbers hp x = p ^ x.1 * x.2 := rfl +/-- The `k`-smooth numbers up to and including `N` as a `Finset` -/ +def smoothNumbersUpTo (N k : ℕ) : Finset ℕ := + (Finset.range N.succ).filter (· ∈ smoothNumbers k) + +lemma mem_smoothNumbersUpTo {N k n : ℕ} : + n ∈ smoothNumbersUpTo N k ↔ n ≤ N ∧ n ∈ smoothNumbers k := by + simp [smoothNumbersUpTo, lt_succ] + +/-- The positive non-`k`-smooth (so "`k`-rough") numbers up to and including `N` as a `Finset` -/ +def roughNumbersUpTo (N k : ℕ) : Finset ℕ := + (Finset.range N.succ).filter (fun n ↦ n ≠ 0 ∧ n ∉ smoothNumbers k) + +lemma smoothNumbersUpTo_card_add_roughNumbersUpTo_card (N k : ℕ) : + (smoothNumbersUpTo N k).card + (roughNumbersUpTo N k).card = N := by + rw [smoothNumbersUpTo, roughNumbersUpTo, + ← Finset.card_union_eq <| Finset.disjoint_filter.mpr fun n _ hn₂ h ↦ h.2 hn₂, + Finset.filter_union_right] + suffices : Finset.card (Finset.filter (fun x ↦ x ≠ 0) (Finset.range (succ N))) = N + · convert this with n + have hn : n ∈ smoothNumbers k → n ≠ 0 := ne_zero_of_mem_smoothNumbers + tauto + · rw [Finset.filter_ne', Finset.card_erase_of_mem <| Finset.mem_range_succ_iff.mpr <| zero_le N] + simp + +/-- A `k`-smooth number can be written as a square times a product of distinct primes `< k`. -/ +lemma eq_prod_primes_mul_sq_of_mem_smoothNumbers {n k : ℕ} (h : n ∈ smoothNumbers k) : + ∃ s ∈ k.primesBelow.powerset, ∃ m, n = m ^ 2 * (s.prod id) := by + obtain ⟨l, m, H₁, H₂⟩ := sq_mul_squarefree n + have hl : l ∈ smoothNumbers k := + mem_smoothNumbers_of_dvd h (Dvd.intro_left (m ^ 2) H₁) <| Squarefree.ne_zero H₂ + refine ⟨l.factors.toFinset, ?_, m, ?_⟩ + · simp only [toFinset_factors, Finset.mem_powerset] + refine fun p hp ↦ mem_primesBelow.mpr ⟨?_, (mem_primeFactors.mp hp).1⟩ + rw [mem_primeFactors] at hp + exact mem_smoothNumbers'.mp hl p hp.1 hp.2.1 + rw [← H₁] + congr + simp only [toFinset_factors] + exact (prod_primeFactors_of_squarefree H₂).symm + +/-- The set of `k`-smooth numbers `≤ N` is contained in the set of numbers of the form `m^2 * P`, +where `m ≤ √N` and `P` is a product of distinct primes `< k`. -/ +lemma smoothNumbersUpTo_subset_image (N k : ℕ) : + smoothNumbersUpTo N k ⊆ Finset.image (fun (s, m) ↦ m ^ 2 * (s.prod id)) + (k.primesBelow.powerset ×ˢ (Finset.range N.sqrt.succ).erase 0) := by + intro n hn + obtain ⟨hn₁, hn₂⟩ := mem_smoothNumbersUpTo.mp hn + obtain ⟨s, hs, m, hm⟩ := eq_prod_primes_mul_sq_of_mem_smoothNumbers hn₂ + simp only [id_eq, Finset.mem_range, zero_lt_succ, not_true_eq_false, Finset.mem_image, + Finset.mem_product, Finset.mem_powerset, Finset.mem_erase, Prod.exists] + refine ⟨s, m, ⟨Finset.mem_powerset.mp hs, ?_, ?_⟩, hm.symm⟩ + · have := hm ▸ ne_zero_of_mem_smoothNumbers hn₂ + simp only [ne_eq, _root_.mul_eq_zero, zero_lt_two, pow_eq_zero_iff, not_or] at this + exact this.1 + · rw [lt_succ, le_sqrt'] + refine LE.le.trans ?_ (hm ▸ hn₁) + nth_rw 1 [← mul_one (m ^ 2)] + exact mul_le_mul_left' (Finset.one_le_prod' fun p hp ↦ + (prime_of_mem_primesBelow <| Finset.mem_powerset.mp hs hp).one_lt.le) _ + +/-- The cardinality of the set of `k`-smooth numbers `≤ N` is bounded by `2^π(k-1) * √N`. -/ +lemma smoothNumbersUpTo_card_le (N k : ℕ) : + (smoothNumbersUpTo N k).card ≤ 2 ^ k.primesBelow.card * N.sqrt := by + convert (Finset.card_le_card <| smoothNumbersUpTo_subset_image N k).trans <| + Finset.card_image_le + simp + +/-- The set of `k`-rough numbers `≤ N` can be written as the union of the sets of multiples `≤ N` +of primes `k ≤ p ≤ N`. -/ +lemma roughNumbersUpTo_eq_biUnion (N k) : + roughNumbersUpTo N k = + (N.succ.primesBelow \ k.primesBelow).biUnion + fun p ↦ (Finset.range N.succ).filter (fun m ↦ m ≠ 0 ∧ p ∣ m) := by + ext m + simp only [roughNumbersUpTo, mem_smoothNumbers_iff_forall_le, not_and, not_forall, + not_lt, exists_prop, exists_and_left, Finset.mem_range, not_le, Finset.mem_filter, + Finset.filter_congr_decidable, Finset.mem_biUnion, Finset.mem_sdiff, mem_primesBelow, + show ∀ P Q : Prop, P ∧ (P → Q) ↔ P ∧ Q by tauto] + simp_rw [← exists_and_left, ← not_lt] + refine exists_congr fun p ↦ ?_ + have H₁ : m ≠ 0 → p ∣ m → m < N.succ → p < N.succ := + fun h₁ h₂ h₃ ↦ (le_of_dvd (Nat.pos_of_ne_zero h₁) h₂).trans_lt h₃ + have H₂ : m ≠ 0 → p ∣ m → ¬ m < p := + fun h₁ h₂ ↦ not_lt.mpr <| le_of_dvd (Nat.pos_of_ne_zero h₁) h₂ + tauto + +/-- The cardinality of the set of `k`-rough numbers `≤ N` is bounded by the sum of `⌊N/p⌋` +over the primes `k ≤ p ≤ N`. -/ +lemma roughNumbersUpTo_card_le (N k : ℕ) : + (roughNumbersUpTo N k).card ≤ (N.succ.primesBelow \ k.primesBelow).sum (fun p ↦ N / p) := by + rw [roughNumbersUpTo_eq_biUnion] + exact Finset.card_biUnion_le.trans <| Finset.sum_le_sum fun p _ ↦ (card_multiples' N p).le + end Nat From 8788d9a43952b75c0e9a0640f273629f73b3b2b4 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Thu, 28 Dec 2023 06:17:56 +0000 Subject: [PATCH 266/353] feat(FieldTheory/SeparableDegree): further properties of separable degree of fields and polynomials (#9041) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Breaking changes: - remove `Field.sepDegree` since it is not quite correct for infinite case; will be added in later PR (see #8696) New definitions (non-exhaustive): - `Polynomial.natSepDegree`: the separable degree of a polynomial is a natural number, defined to be the number of distinct roots of it over its splitting field. New results (non-exhaustive): - `Polynomial.natSepDegree_le_natDegree`: the separable degree of a polynomial is smaller than its degree. - `Polynomial.natSepDegree_eq_natDegree_iff`: the separable degree of a non-zero polynomial is equal to its degree if and only if it is separable. - `Polynomial.natSepDegree_dvd_natDegree_of_irreducible`: the separable degree of an irreducible polynomial divides its degree. - `Field.finSepDegree_adjoin_simple_eq_natSepDegree`: the (finite) separable degree of `F⟮α⟯ / F` is equal to the separable degree of the minimal polynomial of `α` over `F`. - `Field.finSepDegree_dvd_finrank`: the separable degree of any field extension `E / F` divides the degree of `E / F`. - `Field.finSepDegree_le_finrank`: the separable degree of a finite extension `E / F` is smaller than the degree of `E / F`. - `Field.finSepDegree_eq_finrank_iff`: if `E / F` is a finite extension, then its separable degree is equal to its degree if and only if it is a separable extension. Co-authored-by: Johan Commelin --- Mathlib/FieldTheory/SeparableDegree.lean | 670 ++++++++++++++++++----- 1 file changed, 532 insertions(+), 138 deletions(-) diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean index e317fde0916ff..43ac871242137 100644 --- a/Mathlib/FieldTheory/SeparableDegree.lean +++ b/Mathlib/FieldTheory/SeparableDegree.lean @@ -18,78 +18,108 @@ This file contains basics about the separable degree of a field extension. ## Main definitions -- `Field.Emb F E`: the type of `F`-algebra homomorphisms from `E` to the algebraic closure of `E`. - Usually denoted by $\operatorname{Emb}_F(E)$ in textbooks. - -- `Field.sepDegree F E`: the separable degree $[E:F]_s$ of an algebraic extension `E / F` of fields, - defined to be the cardinal of `F`-algebra homomorphisms from `E` to the algebraic closure of `E`. - (Mathematically, it should be the algebraic closure of `F`, but in order to make the type - compatible with `Module.rank F E`, we use the algebraic closure of `E`.) +- `Field.Emb F E`: the type of `F`-algebra homomorphisms from `E` to the algebraic closure of `E` + (the algebraic closure of `F` is usually used in the literature, but our definition has the + advantage that `Field.Emb F E` lies in the same universe as `E` rather than the maximum over `F` + and `E`). Usually denoted by $\operatorname{Emb}_F(E)$ in textbooks. + + **Remark:** if `E / F` is not algebraic, then this definition makes no mathematical sense, + and if it is infinite, then its cardinality doesn't behave as expected (namely, not equal to the + field extension degree of `separableClosure F E / F`). For example, + $\operatorname{Emb}_{\mathbb{Q}}(\mathbb{Q}(\mu_{p^\infty}))\cong\mathbb{Z}_p^\times$ which is + uncountable, while $[\mathbb{Q}(\mu_{p^\infty}):\mathbb{Q}]$ is countable. + + **TODO:** prove or disprove that if `E / F` is algebraic and `Emb F E` is infinite, then + `Field.Emb F E` has cardinality `2 ^ Module.rank F (separableClosure F E)`. + +- `Field.finSepDegree F E`: the (finite) separable degree $[E:F]_s$ of an algebraic extension + `E / F` of fields, defined to be the number of `F`-algebra homomorphisms from `E` to the algebraic + closure of `E`, as a natural number. It is zero if `Field.Emb F E` is not finite. Note that if `E / F` is not algebraic, then this definition makes no mathematical sense. -- `Field.finSepDegree F E`: the separable degree $[E:F]_s$ of `E / F` as a natural number, - which is zero if `Field.sepDegree F E` is not finite. + **Remark:** the (infinite) separable degree `Field.sepDegree F E` for a general algebraic + extension `E / F` is defined to be the degree of `L / F`, where `L` is the (relative) separable + closure `separableClosure F E` of `E / F`, which is not defined in this file yet. Later we + will show that (`Field.finSepDegree_eq`), if `Field.Emb F E` is finite, then these two + definitions coincide. + +- `Polynomial.natSepDegree`: the separable degree of a polynomial is a natural number, + defined to be the number of distinct roots of it over its splitting field. ## Main results -- `Field.embEquivOfEquiv`, `Field.sepDegree_eq_of_equiv`, `Field.finSepDegree_eq_of_equiv`: +- `Field.embEquivOfEquiv`, `Field.finSepDegree_eq_of_equiv`: a random bijection between `Field.Emb F E` and `Field.Emb F K` when `E` and `K` are isomorphic - as `F`-algebras. In particular, they have the same cardinality (so their `Field.sepDegree` and + as `F`-algebras. In particular, they have the same cardinality (so their `Field.finSepDegree` are equal). -- `Field.embEquivOfAdjoinSplits`, `Field.sepDegree_eq_of_adjoin_splits`, +- `Field.embEquivOfAdjoinSplits`, `Field.finSepDegree_eq_of_adjoin_splits`: a random bijection between `Field.Emb F E` and `E →ₐ[F] K` if `E = F(S)` such that every element `s` of `S` is integral (= algebraic) over `F` and whose minimal polynomial splits in `K`. In particular, they have the same cardinality. -- `Field.embEquivOfIsAlgClosed`, `Field.sepDegree_eq_of_isAlgClosed`, +- `Field.embEquivOfIsAlgClosed`, `Field.finSepDegree_eq_of_isAlgClosed`: a random bijection between `Field.Emb F E` and `E →ₐ[F] K` when `E / F` is algebraic and `K / F` is algebraically closed. In particular, they have the same cardinality. -- `Field.embProdEmbOfIsAlgebraic`, `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`, - `Field.sepDegree_mul_sepDegree_of_isAlgebraic`, - `Field.finSepDegree_mul_finSepDegree_of_isAlgebraic`: +- `Field.embProdEmbOfIsAlgebraic`, `Field.finSepDegree_mul_finSepDegree_of_isAlgebraic`: if `K / E / F` is a field extension tower, such that `K / E` is algebraic, then there is a non-canonical bijection `Field.Emb F E × Field.Emb E K ≃ Field.Emb F K`. In particular, the separable degree satisfies the tower law: $[E:F]_s [K:E]_s = [K:F]_s$ - (see `lift_rank_mul_lift_rank`). + (see also `FiniteDimensional.finrank_mul_finrank'`). -## Tags +- `Polynomial.natSepDegree_le_natDegree`: the separable degree of a polynomial is smaller than + its degree. -separable degree, degree, polynomial +- `Polynomial.natSepDegree_eq_natDegree_iff`: the separable degree of a non-zero polynomial is + equal to its degree if and only if it is separable. + +- `Polynomial.natSepDegree_eq_of_splits`: if a polynomial splits over `E`, then its separable degree + is equal to the number of distinct roots of it over `E`. -## TODO +- `Polynomial.natSepDegree_eq_of_isAlgClosed`: the separable degree of a polynomial is equal to + the number of distinct roots of it over any algebraically closed field. -- If `E / F` is a finite extension, then $[E:F]_s \mid [E:F]$. Thus we can define the inseparable - degree $[E:F]_i$ to be $[E:F]$ divided by $[E:F]_s$. +- `Polynomial.natSepDegree_expand`: if a field `F` is of exponential characteristic + `q`, then `Polynomial.expand F (q ^ n) f` and `f` have the same separable degree. -- Define the separable degree of a polynomial over a field to be the number of distinct roots - in algebraic closure, and prove that it's equal to `Polynomial.HasSeparableContraction.degree`. +- `Polynomial.HasSeparableContraction.natSepDegree_eq`: if a polynomial has separable + contraction, then its separable degree is equal to its separable contraction degree. -- If `a` is an element algebraic over `F`, then $[F(a):F]_s$ is equal to the separable degree of - the minimal polynomial of `a` over `F`. In particular, `a` is separable over `F` if and only if - $[F(a):F]_s = [F(a):F]$. +- `Irreducible.natSepDegree_dvd_natDegree`: the separable degree of an irreducible + polynomial divides its degree. -- If `E / F` is a finite extension, then $[E:F]_s = [E:F]$ if and only if every element of `E` is - separable over `F`, namely, `E / F` is a separable extension. +- `IntermediateField.finSepDegree_adjoin_simple_eq_natSepDegree`: the (finite) separable degree of + `F⟮α⟯ / F` is equal to the separable degree of the minimal polynomial of `α` over `F`. -- As a corollary, if `S` is a subset of `E` consisting of separable elements, then `F(S) / F` is a - separable extension. +- `IntermediateField.finSepDegree_adjoin_simple_eq_finrank_iff`: if `α` is algebraic over `F`, then + the separable degree of `F⟮α⟯ / F` is equal to the degree of `F⟮α⟯ / F` if and only if `α` is a + separable element. -- Define maximal separable subextension (or called relative separable closure) - `separableClosure F E : IntermediateField F E` of `E / F`, and prove that its degree over `F` - is $[E:F]_s$ if `E / F` is finite. +- `Field.finSepDegree_dvd_finrank`: the separable degree of any field extension `E / F` divides + the degree of `E / F`. -- Prove that `separableClosure F (AlgebraicClosure F)` is a separable closure of `F`. +- `Field.finSepDegree_le_finrank`: the separable degree of a finite extension `E / F` is smaller + than the degree of `E / F`. -- Prove that `[E:F]_s = 1` if and only if `E / F` is purely inseparable. +- `Field.finSepDegree_eq_finrank_iff`: if `E / F` is a finite extension, then its separable degree + is equal to its degree if and only if it is a separable extension. + +- `IntermediateField.isSeparable_adjoin_simple_iff_separable`: `F⟮x⟯ / F` is a separable extension + if and only if `x` is a separable element. + +- `IsSeparable.trans`: if `E / F` and `K / E` are both separable, then `K / F` is also separable. + +## Tags + +separable degree, degree, polynomial -/ open scoped Classical Polynomial -open FiniteDimensional Polynomial IntermediateField +open FiniteDimensional Polynomial IntermediateField Field noncomputable section @@ -105,18 +135,14 @@ namespace Field of `E`. -/ def Emb := E →ₐ[F] AlgebraicClosure E -/-- If `E / F` is an algebraic extension, then the separable degree of `E / F` -is the number of `F`-algebra homomorphisms from `E` to the algebraic closure of `E`. +/-- If `E / F` is an algebraic extension, then the (finite) separable degree of `E / F` +is the number of `F`-algebra homomorphisms from `E` to the algebraic closure of `E`, +as a natural number. It is defined to be zero if there are infinitely many of them. Note that if `E / F` is not algebraic, then this definition makes no mathematical sense. -/ -def sepDegree := Cardinal.mk (Emb F E) - -/-- The separable degree of `E / F` as a natural number. -/ -def finSepDegree : ℕ := Cardinal.toNat (sepDegree F E) +def finSepDegree : ℕ := Nat.card (Emb F E) instance instNonemptyEmb : Nonempty (Emb F E) := ⟨IsScalarTower.toAlgHom F E _⟩ -instance instNeZeroSepDegree : NeZero (sepDegree F E) := ⟨Cardinal.mk_ne_zero _⟩ - instance instNeZeroFinSepDegree [FiniteDimensional F E] : NeZero (finSepDegree F E) := ⟨Nat.card_ne_zero.2 ⟨inferInstance, Fintype.finite <| minpoly.AlgHom.fintype _ _ _⟩⟩ @@ -132,75 +158,45 @@ def embEquivOfEquiv (i : E ≃ₐ[F] K) : rw [show ∀ y : E, (algebraMap E K) y = i.toAlgHom y from fun y ↦ rfl] at h simpa only [AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_coe, AlgEquiv.apply_symm_apply] using h -/-- If `E` and `K` are isomorphic as `F`-algebras, then they have the same separable degree -over `F`. -/ -theorem sepDegree_eq_of_equiv (i : E ≃ₐ[F] K) : - Cardinal.lift.{w} (sepDegree F E) = Cardinal.lift.{v} (sepDegree F K) := by - have := (Equiv.ulift.{w} (α := Emb F E)).trans - (embEquivOfEquiv F E K i) |>.trans - (Equiv.ulift.{v} (α := Emb F K)).symm |>.cardinal_eq - simpa only [Cardinal.mk_uLift] using this - /-- If `E` and `K` are isomorphic as `F`-algebras, then they have the same `Field.finSepDegree` over `F`. -/ theorem finSepDegree_eq_of_equiv (i : E ≃ₐ[F] K) : - finSepDegree F E = finSepDegree F K := by - simpa only [Cardinal.toNat_lift] using congr_arg Cardinal.toNat - (sepDegree_eq_of_equiv F E K i) - -@[simp] -theorem sepDegree_self : sepDegree F F = 1 := - le_antisymm (Cardinal.le_one_iff_subsingleton.2 AlgHom.subsingleton) - (Cardinal.one_le_iff_ne_zero.2 (instNeZeroSepDegree F F).out) + finSepDegree F E = finSepDegree F K := Nat.card_congr (embEquivOfEquiv F E K i) @[simp] theorem finSepDegree_self : finSepDegree F F = 1 := by - simp only [finSepDegree, sepDegree_self, Cardinal.one_toNat] + have : Cardinal.mk (Emb F F) = 1 := le_antisymm + (Cardinal.le_one_iff_subsingleton.2 AlgHom.subsingleton) + (Cardinal.one_le_iff_ne_zero.2 <| Cardinal.mk_ne_zero _) + rw [finSepDegree, Nat.card, this, Cardinal.one_toNat] -@[simp] -theorem sepDegree_bot : sepDegree F (⊥ : IntermediateField F E) = 1 := by - have := sepDegree_eq_of_equiv _ _ _ (botEquiv F E) - rwa [sepDegree_self, Cardinal.lift_one, ← Cardinal.lift_one.{u, v}, Cardinal.lift_inj] at this +end Field -@[simp] -theorem finSepDegree_bot : finSepDegree F (⊥ : IntermediateField F E) = 1 := by - simp only [finSepDegree, sepDegree_bot, Cardinal.one_toNat] +namespace IntermediateField @[simp] -theorem sepDegree_top : sepDegree F (⊤ : IntermediateField F E) = sepDegree F E := by - simpa only [Cardinal.lift_id] using sepDegree_eq_of_equiv F _ E topEquiv +theorem finSepDegree_bot : finSepDegree F (⊥ : IntermediateField F E) = 1 := by + rw [finSepDegree_eq_of_equiv _ _ _ (botEquiv F E), finSepDegree_self] -@[simp] -theorem finSepDegree_top : finSepDegree F (⊤ : IntermediateField F E) = finSepDegree F E := by - simp only [finSepDegree, sepDegree_top] +section Tower -section +variable {F} variable [Algebra E K] [IsScalarTower F E K] -theorem sepDegree_bot' : Cardinal.lift.{v} (sepDegree F (⊥ : IntermediateField E K)) = - Cardinal.lift.{w} (sepDegree F E) := - sepDegree_eq_of_equiv _ _ _ ((botEquiv E K).restrictScalars F) - @[simp] -theorem sepDegree_bot'' (K : Type v) [Field K] [Algebra F K] [Algebra E K] [IsScalarTower F E K] : - sepDegree F (⊥ : IntermediateField E K) = sepDegree F E := by - simpa only [Cardinal.lift_id] using sepDegree_bot' F E K +theorem finSepDegree_bot' : finSepDegree F (⊥ : IntermediateField E K) = finSepDegree F E := + finSepDegree_eq_of_equiv _ _ _ ((botEquiv E K).restrictScalars F) @[simp] -theorem finSepDegree_bot' : finSepDegree F (⊥ : IntermediateField E K) = finSepDegree F E := by - simpa only [Cardinal.toNat_lift] using congr_arg Cardinal.toNat (sepDegree_bot' F E K) +theorem finSepDegree_top : finSepDegree F (⊤ : IntermediateField E K) = finSepDegree F K := + finSepDegree_eq_of_equiv _ _ _ ((topEquiv (F := E) (E := K)).restrictScalars F) -@[simp] -theorem sepDegree_top' : sepDegree F (⊤ : IntermediateField E K) = sepDegree F K := by - simpa only [Cardinal.lift_id] using sepDegree_eq_of_equiv _ _ _ - ((topEquiv (F := E) (E := K)).restrictScalars F) +end Tower -@[simp] -theorem finSepDegree_top' : finSepDegree F (⊤ : IntermediateField E K) = finSepDegree F K := by - simp only [finSepDegree, sepDegree_top'] +end IntermediateField -end +namespace Field /-- A random bijection between `Field.Emb F E` and `E →ₐ[F] K` if `E = F(S)` such that every element `s` of `S` is integral (= algebraic) over `F` and whose minimal polynomial splits in `K`. @@ -215,23 +211,12 @@ def embEquivOfAdjoinSplits {S : Set E} (hS : adjoin F S = ⊤) (halg.algHomEmbeddingOfSplits (fun _ ↦ splits_of_mem_adjoin F (S := S) hK (hS ▸ mem_top)) _) (halg.algHomEmbeddingOfSplits (fun _ ↦ IsAlgClosed.splits_codomain _) _) -/-- The separable degree of `E / F` is equal to the cardinality of `E →ₐ[F] K` -if `E = F(S)` such that every element -`s` of `S` is integral (= algebraic) over `F` and whose minimal polynomial splits in `K`. -/ -theorem sepDegree_eq_of_adjoin_splits {S : Set E} (hS : adjoin F S = ⊤) - (hK : ∀ s ∈ S, IsIntegral F s ∧ Splits (algebraMap F K) (minpoly F s)) : - Cardinal.lift.{w} (sepDegree F E) = Cardinal.mk (E →ₐ[F] K) := by - simpa only [Cardinal.mk_uLift] using (Equiv.ulift.{w} (α := Emb F E)).trans - (embEquivOfAdjoinSplits F E K hS hK) |>.cardinal_eq - /-- The `Field.finSepDegree F E` is equal to the cardinality of `E →ₐ[F] K` if `E = F(S)` such that every element `s` of `S` is integral (= algebraic) over `F` and whose minimal polynomial splits in `K`. -/ theorem finSepDegree_eq_of_adjoin_splits {S : Set E} (hS : adjoin F S = ⊤) (hK : ∀ s ∈ S, IsIntegral F s ∧ Splits (algebraMap F K) (minpoly F s)) : - finSepDegree F E = Cardinal.toNat (Cardinal.mk (E →ₐ[F] K)) := by - simpa only [Cardinal.toNat_lift] using congr_arg Cardinal.toNat - (sepDegree_eq_of_adjoin_splits F E K hS hK) + finSepDegree F E = Nat.card (E →ₐ[F] K) := Nat.card_congr (embEquivOfAdjoinSplits F E K hS hK) /-- A random bijection between `Field.Emb F E` and `E →ₐ[F] K` when `E / F` is algebraic and `K / F` is algebraically closed. -/ @@ -240,19 +225,10 @@ def embEquivOfIsAlgClosed (halg : Algebra.IsAlgebraic F E) [IsAlgClosed K] : embEquivOfAdjoinSplits F E K (adjoin_univ F E) <| fun s _ ↦ ⟨(halg s).isIntegral, IsAlgClosed.splits_codomain _⟩ -/-- The separable degree of `E / F` is equal to the cardinality of `E →ₐ[F] K` when `E / F` -is algebraic and `K / F` is algebraically closed. -/ -theorem sepDegree_eq_of_isAlgClosed (halg : Algebra.IsAlgebraic F E) [IsAlgClosed K] : - Cardinal.lift.{w} (sepDegree F E) = Cardinal.mk (E →ₐ[F] K) := by - simpa only [Cardinal.mk_uLift] using (Equiv.ulift.{w} (α := Emb F E)).trans - (embEquivOfIsAlgClosed F E K halg) |>.cardinal_eq - /-- The `Field.finSepDegree F E` is equal to the cardinality of `E →ₐ[F] K` as a natural number, when `E / F` is algebraic and `K / F` is algebraically closed. -/ theorem finSepDegree_eq_of_isAlgClosed (halg : Algebra.IsAlgebraic F E) [IsAlgClosed K] : - finSepDegree F E = Cardinal.toNat (Cardinal.mk (E →ₐ[F] K)) := by - simpa only [Cardinal.toNat_lift] using congr_arg Cardinal.toNat - (sepDegree_eq_of_isAlgClosed F E K halg) + finSepDegree F E = Nat.card (E →ₐ[F] K) := Nat.card_congr (embEquivOfIsAlgClosed F E K halg) /-- If `K / E / F` is a field extension tower, such that `K / E` is algebraic, then there is a non-canonical bijection @@ -268,31 +244,449 @@ def embProdEmbOfIsAlgebraic [Algebra E K] [IsScalarTower F E K] (halg : Algebra. (IsAlgClosure.equivOfAlgebraic E K (AlgebraicClosure K) (AlgebraicClosure E) halg).restrictScalars F).symm -/-- If `K / E / F` is a field extension tower, such that `K / E` is algebraic, then -$[E:F]_s [K:E]_s = [K:F]_s$. See also `lift_rank_mul_lift_rank`. -/ -theorem lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic - [Algebra E K] [IsScalarTower F E K] (halg : Algebra.IsAlgebraic E K) : - Cardinal.lift.{w} (sepDegree F E) * Cardinal.lift.{v} (sepDegree E K) = - Cardinal.lift.{v} (sepDegree F K) := by - have := (embProdEmbOfIsAlgebraic F E K halg).trans - (Equiv.ulift.{v} (α := Emb F K)).symm |>.cardinal_eq - simpa only [Cardinal.mk_prod, Cardinal.mk_uLift] using this - -/-- The same-universe version of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`. -See also `rank_mul_rank`. -/ -theorem sepDegree_mul_sepDegree_of_isAlgebraic - (A : Type u) (B : Type u) [Field A] [Field B] [Algebra A B] - (C : Type u) [Field C] [Algebra A C] [Algebra B C] - [IsScalarTower A B C] (halg : Algebra.IsAlgebraic B C) : - sepDegree A B * sepDegree B C = sepDegree A C := by - simpa only [Cardinal.lift_id] using lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic A B C halg - -/-- The `Field.finSepDegree` version of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`. -See also `FiniteDimensional.finrank_mul_finrank'`. -/ +/-- If `K / E / F` is a field extension tower, such that `K / E` is algebraic, then their +(finite) separable degree satisfies the tower law +$[E:F]_s [K:E]_s = [K:F]_s$. See also `FiniteDimensional.finrank_mul_finrank'`. -/ theorem finSepDegree_mul_finSepDegree_of_isAlgebraic [Algebra E K] [IsScalarTower F E K] (halg : Algebra.IsAlgebraic E K) : finSepDegree F E * finSepDegree E K = finSepDegree F K := by - simpa only [Cardinal.toNat_mul, Cardinal.toNat_lift] using congr_arg Cardinal.toNat - (lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic F E K halg) + simpa only [Nat.card_prod] using Nat.card_congr (embProdEmbOfIsAlgebraic F E K halg) + +end Field + +namespace Polynomial + +variable {F E} + +variable (f : F[X]) + +/-- The separable degree `Polynomial.natSepDegree` of a polynomial is a natural number, +defined to be the number of distinct roots of it over its splitting field. +This is similar to `Polynomial.natDegree` but not to `Polynomial.degree`, namely, the separable +degree of `0` is `0`, not negative infinity. -/ +def natSepDegree : ℕ := (f.aroots f.SplittingField).toFinset.card + +/-- The separable degree of a polynomial is smaller than its degree. -/ +theorem natSepDegree_le_natDegree : f.natSepDegree ≤ f.natDegree := by + have := f.map (algebraMap F f.SplittingField) |>.card_roots' + rw [← aroots_def, natDegree_map] at this + exact (f.aroots f.SplittingField).toFinset_card_le.trans this + +@[simp] +theorem natSepDegree_X_sub_C (x : F) : (X - C x).natSepDegree = 1 := by + simp only [natSepDegree, aroots_X_sub_C, Multiset.toFinset_singleton, Finset.card_singleton] + +@[simp] +theorem natSepDegree_X : (X : F[X]).natSepDegree = 1 := by + simp only [natSepDegree, aroots_X, Multiset.toFinset_singleton, Finset.card_singleton] + +/-- A constant polynomial has zero separable degree. -/ +theorem natSepDegree_eq_zero (h : f.natDegree = 0) : f.natSepDegree = 0 := by + linarith only [natSepDegree_le_natDegree f, h] + +@[simp] +theorem natSepDegree_C (x : F) : (C x).natSepDegree = 0 := natSepDegree_eq_zero _ (natDegree_C _) + +@[simp] +theorem natSepDegree_zero : (0 : F[X]).natSepDegree = 0 := by + rw [← C_0, natSepDegree_C] + +@[simp] +theorem natSepDegree_one : (1 : F[X]).natSepDegree = 0 := by + rw [← C_1, natSepDegree_C] + +/-- A non-constant polynomial has non-zero separable degree. -/ +theorem natSepDegree_ne_zero (h : f.natDegree ≠ 0) : f.natSepDegree ≠ 0 := by + rw [natSepDegree, ne_eq, Finset.card_eq_zero, ← ne_eq, ← Finset.nonempty_iff_ne_empty] + use rootOfSplits _ (SplittingField.splits f) (ne_of_apply_ne _ h) + rw [Multiset.mem_toFinset, mem_aroots] + exact ⟨ne_of_apply_ne _ h, map_rootOfSplits _ (SplittingField.splits f) (ne_of_apply_ne _ h)⟩ + +/-- A polynomial has zero separable degree if and only if it is constant. -/ +theorem natSepDegree_eq_zero_iff : f.natSepDegree = 0 ↔ f.natDegree = 0 := + ⟨(natSepDegree_ne_zero f).mtr, natSepDegree_eq_zero f⟩ + +/-- A polynomial has non-zero separable degree if and only if it is non-constant. -/ +theorem natSepDegree_ne_zero_iff : f.natSepDegree ≠ 0 ↔ f.natDegree ≠ 0 := + Iff.not <| natSepDegree_eq_zero_iff f + +/-- The separable degree of a non-zero polynomial is equal to its degree if and only if +it is separable. -/ +theorem natSepDegree_eq_natDegree_iff (hf : f ≠ 0) : + f.natSepDegree = f.natDegree ↔ f.Separable := by + simp_rw [← card_rootSet_eq_natDegree_iff_of_splits hf (SplittingField.splits f), + rootSet_def, Finset.coe_sort_coe, Fintype.card_coe] + rfl + +/-- If a polynomial is separable, then its separable degree is equal to its degree. -/ +theorem natSepDegree_eq_natDegree_of_separable (h : f.Separable) : + f.natSepDegree = f.natDegree := + (natSepDegree_eq_natDegree_iff f h.ne_zero).2 h + +/-- If a polynomial splits over `E`, then its separable degree is equal to +the number of distinct roots of it over `E`. -/ +theorem natSepDegree_eq_of_splits (h : f.Splits (algebraMap F E)) : + f.natSepDegree = (f.aroots E).toFinset.card := by + rw [aroots, ← (SplittingField.lift f h).comp_algebraMap, ← map_map, + roots_map _ ((splits_id_iff_splits _).mpr <| SplittingField.splits f), + Multiset.toFinset_map, Finset.card_image_of_injective _ (RingHom.injective _)] + rfl + +variable (E) in +/-- The separable degree of a polynomial is equal to +the number of distinct roots of it over any algebraically closed field. -/ +theorem natSepDegree_eq_of_isAlgClosed [IsAlgClosed E] : + f.natSepDegree = (f.aroots E).toFinset.card := + natSepDegree_eq_of_splits f (IsAlgClosed.splits_codomain f) + +@[simp] +theorem natSepDegree_C_mul {x : F} (hx : x ≠ 0) : + (C x * f).natSepDegree = f.natSepDegree := by + simp only [natSepDegree_eq_of_isAlgClosed (AlgebraicClosure F), aroots_C_mul _ hx] + +@[simp] +theorem natSepDegree_smul_nonzero {x : F} (hx : x ≠ 0) : + (x • f).natSepDegree = f.natSepDegree := by + simp only [natSepDegree_eq_of_isAlgClosed (AlgebraicClosure F), aroots_smul_nonzero _ hx] + +@[simp] +theorem natSepDegree_pow {n : ℕ} : (f ^ n).natSepDegree = if n = 0 then 0 else f.natSepDegree := by + simp only [natSepDegree_eq_of_isAlgClosed (AlgebraicClosure F), aroots_pow] + by_cases h : n = 0 + · simp only [h, zero_smul, Multiset.toFinset_zero, Finset.card_empty, ite_true] + simp only [h, Multiset.toFinset_nsmul _ n h, ite_false] + +theorem natSepDegree_X_pow {n : ℕ} : (X ^ n : F[X]).natSepDegree = if n = 0 then 0 else 1 := by + simp only [natSepDegree_pow, natSepDegree_X] + +theorem natSepDegree_X_sub_C_pow {x : F} {n : ℕ} : + ((X - C x) ^ n).natSepDegree = if n = 0 then 0 else 1 := by + simp only [natSepDegree_pow, natSepDegree_X_sub_C] + +theorem natSepDegree_C_mul_X_sub_C_pow {x y : F} {n : ℕ} (hx : x ≠ 0) : + (C x * (X - C y) ^ n).natSepDegree = if n = 0 then 0 else 1 := by + simp only [natSepDegree_C_mul _ hx, natSepDegree_X_sub_C_pow] + +theorem natSepDegree_mul (g : F[X]) : + (f * g).natSepDegree ≤ f.natSepDegree + g.natSepDegree := by + by_cases h : f * g = 0 + · simp only [h, natSepDegree_zero, zero_le] + simp_rw [natSepDegree_eq_of_isAlgClosed (AlgebraicClosure F), aroots_mul h, Multiset.toFinset_add] + exact Finset.card_union_le _ _ + +theorem natSepDegree_le_of_dvd (g : F[X]) (h1 : f ∣ g) (h2 : g ≠ 0) : + f.natSepDegree ≤ g.natSepDegree := by + simp_rw [natSepDegree_eq_of_isAlgClosed (AlgebraicClosure F)] + exact Finset.card_le_card <| Multiset.toFinset_subset.mpr <| + Multiset.Le.subset <| roots.le_of_dvd (map_ne_zero h2) <| map_dvd _ h1 + +/-- If a field `F` is of exponential characteristic `q`, then `Polynomial.expand F (q ^ n) f` +and `f` have the same separable degree. -/ +theorem natSepDegree_expand (q : ℕ) [hF : ExpChar F q] {n : ℕ} : + (expand F (q ^ n) f).natSepDegree = f.natSepDegree := by + cases' hF with _ _ hprime _ + · simp only [one_pow, expand_one] + haveI := Fact.mk hprime + simpa only [natSepDegree_eq_of_isAlgClosed (AlgebraicClosure F), aroots_def, map_expand, + Fintype.card_coe] using Fintype.card_eq.2 + ⟨(f.map (algebraMap F (AlgebraicClosure F))).rootsExpandPowEquivRoots q n⟩ + +theorem natSepDegree_X_pow_char_sub_C (q : ℕ) [ExpChar F q] (n : ℕ) (y : F) : + (X ^ q ^ n - C y).natSepDegree = 1 := by + rw [← expand_X, ← expand_C (q ^ n), ← map_sub, natSepDegree_expand, natSepDegree_X_sub_C] + +variable {f} in +/-- If `g` is a separable contraction of `f`, then the separable degree of `f` is equal to +the degree of `g`. -/ +theorem IsSeparableContraction.natSepDegree_eq {g : Polynomial F} {q : ℕ} [ExpChar F q] + (h : IsSeparableContraction q f g) : f.natSepDegree = g.natDegree := by + obtain ⟨h1, m, h2⟩ := h + rw [← h2, natSepDegree_expand, natSepDegree_eq_natDegree_of_separable g h1] + +variable {f} in +/-- If a polynomial has separable contraction, then its separable degree is equal to the degree of +the given separable contraction. -/ +theorem HasSeparableContraction.natSepDegree_eq + {q : ℕ} [ExpChar F q] (hf : f.HasSeparableContraction q) : + f.natSepDegree = hf.degree := hf.isSeparableContraction.natSepDegree_eq + +end Polynomial + +namespace Irreducible + +variable {F} + +variable {f : F[X]} + +/-- The separable degree of an irreducible polynomial divides its degree. -/ +theorem natSepDegree_dvd_natDegree (h : Irreducible f) : + f.natSepDegree ∣ f.natDegree := by + obtain ⟨q, _⟩ := ExpChar.exists F + have hf := h.hasSeparableContraction q + rw [hf.natSepDegree_eq] + exact hf.dvd_degree + +/-- A monic irreducible polynomial over a field `F` of exponential characteristic `q` has +separable degree one if and only if it is of the form `Polynomial.expand F (q ^ n) (X - C y)` +for some `n : ℕ` and `y : F`. -/ +theorem natSepDegree_eq_one_iff_of_monic' (q : ℕ) [ExpChar F q] (hm : f.Monic) + (hi : Irreducible f) : f.natSepDegree = 1 ↔ + ∃ (n : ℕ) (y : F), f = expand F (q ^ n) (X - C y) := by + refine ⟨fun h ↦ ?_, fun ⟨n, y, h⟩ ↦ ?_⟩ + · obtain ⟨g, h1, n, rfl⟩ := hi.hasSeparableContraction q + have h2 : g.natDegree = 1 := by + rwa [natSepDegree_expand _ q, natSepDegree_eq_natDegree_of_separable g h1] at h + rw [((monic_expand_iff <| expChar_pow_pos F q n).mp hm).eq_X_add_C h2] + exact ⟨n, -(g.coeff 0), by rw [map_neg, sub_neg_eq_add]⟩ + rw [h, natSepDegree_expand _ q, natSepDegree_X_sub_C] + +/-- A monic irreducible polynomial over a field `F` of exponential characteristic `q` has +separable degree one if and only if it is of the form `X ^ (q ^ n) - C y` +for some `n : ℕ` and `y : F`. -/ +theorem natSepDegree_eq_one_iff_of_monic (q : ℕ) [ExpChar F q] (hm : f.Monic) + (hi : Irreducible f) : f.natSepDegree = 1 ↔ ∃ (n : ℕ) (y : F), f = X ^ q ^ n - C y := by + simp only [hi.natSepDegree_eq_one_iff_of_monic' q hm, map_sub, expand_X, expand_C] + +end Irreducible + +namespace minpoly + +variable {F E} + +variable (q : ℕ) [hF : ExpChar F q] {x : E} + +/-- The minimal polynomial of an element of `E / F` of exponential characteristic `q` has +separable degree one if and only if the minimal polynomial is of the form +`Polynomial.expand F (q ^ n) (X - C y)` for some `n : ℕ` and `y : F`. -/ +theorem natSepDegree_eq_one_iff_eq_expand_X_sub_C : (minpoly F x).natSepDegree = 1 ↔ + ∃ (n : ℕ) (y : F), minpoly F x = expand F (q ^ n) (X - C y) := by + refine ⟨fun h ↦ ?_, fun ⟨n, y, h⟩ ↦ ?_⟩ + · have halg : IsIntegral F x := by_contra fun h' ↦ by + simp only [eq_zero h', natSepDegree_zero, zero_ne_one] at h + exact (minpoly.irreducible halg).natSepDegree_eq_one_iff_of_monic' q + (minpoly.monic halg) |>.1 h + rw [h, natSepDegree_expand _ q, natSepDegree_X_sub_C] + +/-- The minimal polynomial of an element of `E / F` of exponential characteristic `q` has +separable degree one if and only if the minimal polynomial is of the form +`X ^ (q ^ n) - C y` for some `n : ℕ` and `y : F`. -/ +theorem natSepDegree_eq_one_iff_eq_X_pow_sub_C : (minpoly F x).natSepDegree = 1 ↔ + ∃ (n : ℕ) (y : F), minpoly F x = X ^ q ^ n - C y := by + simp only [minpoly.natSepDegree_eq_one_iff_eq_expand_X_sub_C q, map_sub, expand_X, expand_C] + +/-- The minimal polynomial of an element `x` of `E / F` of exponential characteristic `q` has +separable degree one if and only if `x ^ (q ^ n) ∈ F` for some `n : ℕ`. -/ +theorem natSepDegree_eq_one_iff_mem_pow : (minpoly F x).natSepDegree = 1 ↔ + ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by + convert_to _ ↔ ∃ (n : ℕ) (y : F), Polynomial.aeval x (X ^ q ^ n - C y) = 0 + · simp_rw [RingHom.mem_range, map_sub, map_pow, aeval_C, aeval_X, sub_eq_zero, eq_comm] + refine ⟨fun h ↦ ?_, fun ⟨n, y, h⟩ ↦ ?_⟩ + · obtain ⟨n, y, hx⟩ := (minpoly.natSepDegree_eq_one_iff_eq_X_pow_sub_C q).1 h + exact ⟨n, y, hx ▸ aeval F x⟩ + have hnezero := X_pow_sub_C_ne_zero (expChar_pow_pos F q n) y + refine ((natSepDegree_le_of_dvd _ _ (minpoly.dvd F x h) hnezero).trans_eq <| + natSepDegree_X_pow_char_sub_C q n y).antisymm ?_ + rw [Nat.one_le_iff_ne_zero, natSepDegree_ne_zero_iff, ← Nat.one_le_iff_ne_zero] + exact minpoly.natDegree_pos <| IsAlgebraic.isIntegral ⟨_, hnezero, h⟩ + +/-- The minimal polynomial of an element `x` of `E / F` of exponential characteristic `q` has +separable degree one if and only if the minimal polynomial is of the form +`(X - x) ^ (q ^ n)` for some `n : ℕ`. -/ +theorem natSepDegree_eq_one_iff_eq_X_sub_C_pow : (minpoly F x).natSepDegree = 1 ↔ + ∃ n : ℕ, (minpoly F x).map (algebraMap F E) = (X - C x) ^ q ^ n := by + haveI := expChar_of_injective_algebraMap (algebraMap F E).injective q + haveI := expChar_of_injective_algebraMap (NoZeroSMulDivisors.algebraMap_injective E E[X]) q + refine ⟨fun h ↦ ?_, fun ⟨n, h⟩ ↦ (natSepDegree_eq_one_iff_mem_pow q).2 ?_⟩ + · obtain ⟨n, y, h⟩ := (natSepDegree_eq_one_iff_eq_X_pow_sub_C q).1 h + have hx := congr_arg (Polynomial.aeval x) h.symm + rw [minpoly.aeval, map_sub, map_pow, aeval_X, aeval_C, sub_eq_zero, eq_comm] at hx + use n + rw [h, Polynomial.map_sub, Polynomial.map_pow, map_X, map_C, hx, map_pow, ← sub_pow_expChar_pow] + apply_fun constantCoeff at h + simp_rw [map_pow, map_sub, constantCoeff_apply, coeff_map, coeff_X_zero, coeff_C_zero] at h + rw [zero_sub, neg_pow, ExpChar.neg_one_pow_expChar_pow] at h + exact ⟨n, -(minpoly F x).coeff 0, by rw [map_neg, h]; ring1⟩ + +end minpoly + +namespace IntermediateField + +/-- The (finite) separable degree of `F⟮α⟯ / F` is equal to the separable degree of the +minimal polynomial of `α` over `F`. -/ +theorem finSepDegree_adjoin_simple_eq_natSepDegree {α : E} (halg : IsAlgebraic F α) : + finSepDegree F F⟮α⟯ = (minpoly F α).natSepDegree := by + have : finSepDegree F F⟮α⟯ = _ := Nat.card_congr + (algHomAdjoinIntegralEquiv F (K := AlgebraicClosure F⟮α⟯) halg.isIntegral) + rw [this, Nat.card_eq_fintype_card, natSepDegree_eq_of_isAlgClosed (E := AlgebraicClosure F⟮α⟯)] + exact Eq.trans (by simp only [Multiset.mem_toFinset]) (Fintype.card_coe _) + +-- The separable degree of `F⟮α⟯ / F` divides the degree of `F⟮α⟯ / F`. +-- Marked as `private` because it is a special case of `finSepDegree_dvd_finrank`. +private theorem finSepDegree_adjoin_simple_dvd_finrank (α : E) : + finSepDegree F F⟮α⟯ ∣ finrank F F⟮α⟯ := by + by_cases halg : IsAlgebraic F α + · rw [finSepDegree_adjoin_simple_eq_natSepDegree F E halg, adjoin.finrank halg.isIntegral] + exact (minpoly.irreducible halg.isIntegral).natSepDegree_dvd_natDegree + have : finrank F F⟮α⟯ = 0 := finrank_of_infinite_dimensional <| fun _ ↦ + halg ((AdjoinSimple.isIntegral_gen F α).1 (IsIntegral.of_finite F _)).isAlgebraic + rw [this] + exact dvd_zero _ + +/-- The separable degree of `F⟮α⟯ / F` is smaller than the degree of `F⟮α⟯ / F` if `α` is +algebraic over `F`. -/ +theorem finSepDegree_adjoin_simple_le_finrank (α : E) (halg : IsAlgebraic F α) : + finSepDegree F F⟮α⟯ ≤ finrank F F⟮α⟯ := by + haveI := adjoin.finiteDimensional halg.isIntegral + exact Nat.le_of_dvd finrank_pos <| finSepDegree_adjoin_simple_dvd_finrank F E α + +/-- If `α` is algebraic over `F`, then the separable degree of `F⟮α⟯ / F` is equal to the degree +of `F⟮α⟯ / F` if and only if `α` is a separable element. -/ +theorem finSepDegree_adjoin_simple_eq_finrank_iff (α : E) (halg : IsAlgebraic F α) : + finSepDegree F F⟮α⟯ = finrank F F⟮α⟯ ↔ (minpoly F α).Separable := by + rw [finSepDegree_adjoin_simple_eq_natSepDegree F E halg, adjoin.finrank halg.isIntegral, + natSepDegree_eq_natDegree_iff _ (minpoly.ne_zero halg.isIntegral)] + +end IntermediateField + +namespace Field + +/-- The separable degree of any field extension `E / F` divides the degree of `E / F`. -/ +theorem finSepDegree_dvd_finrank : finSepDegree F E ∣ finrank F E := by + by_cases hfd : FiniteDimensional F E + · rw [← finSepDegree_top F, ← finrank_top F E] + refine induction_on_adjoin (fun K : IntermediateField F E ↦ finSepDegree F K ∣ finrank F K) + (by simp_rw [finSepDegree_bot, IntermediateField.finrank_bot, one_dvd]) (fun L x h ↦ ?_) ⊤ + simp only at h ⊢ + have hdvd := mul_dvd_mul h <| finSepDegree_adjoin_simple_dvd_finrank L E x + set M := L⟮x⟯ + rwa [finSepDegree_mul_finSepDegree_of_isAlgebraic F L M (Algebra.IsAlgebraic.of_finite L M), + FiniteDimensional.finrank_mul_finrank F L M] at hdvd + rw [finrank_of_infinite_dimensional hfd] + exact dvd_zero _ + +/-- The separable degree of a finite extension `E / F` is smaller than the degree of `E / F`. -/ +theorem finSepDegree_le_finrank [FiniteDimensional F E] : + finSepDegree F E ≤ finrank F E := Nat.le_of_dvd finrank_pos <| finSepDegree_dvd_finrank F E + +/-- If `E / F` is a separable extension, then its separable degree is equal to its degree. +When `E / F` is infinite, it means that `Field.Emb F E` has infinitely many elements. +(But the cardinality of `Field.Emb F E` is not equal to `Module.rank F E` in general!) -/ +theorem finSepDegree_eq_finrank_of_isSeparable [IsSeparable F E] : + finSepDegree F E = finrank F E := by + wlog hfd : FiniteDimensional F E generalizing E with H + · rw [finrank_of_infinite_dimensional hfd] + have halg := IsSeparable.isAlgebraic F E + obtain ⟨L, h, h'⟩ := exists_lt_finrank_of_infinite_dimensional halg hfd (finSepDegree F E) + haveI : IsSeparable F L := isSeparable_tower_bot_of_isSeparable F L E + have hd := finSepDegree_mul_finSepDegree_of_isAlgebraic F L E (halg.tower_top L) + rw [H L h] at hd + by_cases hd' : finSepDegree L E = 0 + · rw [← hd, hd', mul_zero] + linarith only [h', hd, Nat.le_mul_of_pos_right (m := finrank F L) (Nat.pos_of_ne_zero hd')] + rw [← finSepDegree_top F, ← finrank_top F E] + refine induction_on_adjoin (fun K : IntermediateField F E ↦ finSepDegree F K = finrank F K) + (by simp_rw [finSepDegree_bot, IntermediateField.finrank_bot]) (fun L x h ↦ ?_) ⊤ + simp only at h ⊢ + have heq : _ * _ = _ * _ := congr_arg₂ (· * ·) h <| + (finSepDegree_adjoin_simple_eq_finrank_iff L E x (IsAlgebraic.of_finite L x)).2 <| + (IsSeparable.separable F x).map_minpoly L + set M := L⟮x⟯ + rwa [finSepDegree_mul_finSepDegree_of_isAlgebraic F L M (Algebra.IsAlgebraic.of_finite L M), + FiniteDimensional.finrank_mul_finrank F L M] at heq + +/-- If `E / F` is a finite extension, then its separable degree is equal to its degree if and +only if it is a separable extension. -/ +theorem finSepDegree_eq_finrank_iff [FiniteDimensional F E] : + finSepDegree F E = finrank F E ↔ IsSeparable F E := + ⟨fun heq ↦ ⟨fun x ↦ by + have halg := IsAlgebraic.of_finite F x + refine (finSepDegree_adjoin_simple_eq_finrank_iff F E x halg).1 <| le_antisymm + (finSepDegree_adjoin_simple_le_finrank F E x halg) <| le_of_not_lt fun h ↦ ?_ + have := Nat.mul_lt_mul h (finSepDegree_le_finrank F⟮x⟯ E) Fin.size_pos' + rw [finSepDegree_mul_finSepDegree_of_isAlgebraic F F⟮x⟯ E (Algebra.IsAlgebraic.of_finite _ E), + FiniteDimensional.finrank_mul_finrank F F⟮x⟯ E] at this + linarith only [heq, this]⟩, fun _ ↦ finSepDegree_eq_finrank_of_isSeparable F E⟩ + +end Field + +lemma IntermediateField.separable_of_mem_isSeparable {L : IntermediateField F E} [IsSeparable F L] + {x : E} (h : x ∈ L) : (minpoly F x).Separable := by + simpa only [minpoly_eq] using IsSeparable.separable F (K := L) ⟨x, h⟩ + +/-- `F⟮x⟯ / F` is a separable extension if and only if `x` is a separable element. +As a consequence, any rational function of `x` is also a separable element. -/ +theorem IntermediateField.isSeparable_adjoin_simple_iff_separable {x : E} : + IsSeparable F F⟮x⟯ ↔ (minpoly F x).Separable := by + refine ⟨fun _ ↦ ?_, fun hsep ↦ ?_⟩ + · exact separable_of_mem_isSeparable F E <| mem_adjoin_simple_self F x + · have h := hsep.isIntegral + haveI := adjoin.finiteDimensional h + rwa [← finSepDegree_eq_finrank_iff, + finSepDegree_adjoin_simple_eq_finrank_iff F E x h.isAlgebraic] + +/-- If `E / F` and `K / E` are both separable extensions, then `K / F` is also separable. -/ +theorem IsSeparable.trans [Algebra E K] [IsScalarTower F E K] + [IsSeparable F E] [IsSeparable E K] : IsSeparable F K := (isSeparable_def F K).2 fun x ↦ by + let f := minpoly E x + let E' : IntermediateField F E := adjoin F f.frange + haveI : FiniteDimensional F E' := finiteDimensional_adjoin fun x _ ↦ IsSeparable.isIntegral F x + let g : E'[X] := f.toSubring E'.toSubring (subset_adjoin F _) + have h : g.map (algebraMap E' E) = f := f.map_toSubring E'.toSubring (subset_adjoin F _) + clear_value g + have hx : x ∈ restrictScalars F E'⟮x⟯ := mem_adjoin_simple_self _ x + have hzero : aeval x g = 0 := by + simpa only [← h, aeval_map_algebraMap] using minpoly.aeval E x + have halg : IsIntegral E' x := (IsSeparable.isAlgebraic F E).trans + (IsSeparable.isAlgebraic E K) x |>.isIntegral.tower_top + have hsep : f.Separable := IsSeparable.separable E x + rw [← h, separable_map] at hsep + replace hsep := hsep.of_dvd <| minpoly.dvd _ _ hzero + haveI : IsSeparable F E' := isSeparable_tower_bot_of_isSeparable F E' E + haveI := (isSeparable_adjoin_simple_iff_separable _ _).2 hsep + haveI := adjoin.finiteDimensional halg + haveI : FiniteDimensional F E'⟮x⟯ := FiniteDimensional.trans F E' E'⟮x⟯ + have := finSepDegree_mul_finSepDegree_of_isAlgebraic F E' E'⟮x⟯ (IsSeparable.isAlgebraic _ _) + rw [finSepDegree_eq_finrank_of_isSeparable F E', + finSepDegree_eq_finrank_of_isSeparable E' E'⟮x⟯, + FiniteDimensional.finrank_mul_finrank F E' E'⟮x⟯, + eq_comm, finSepDegree_eq_finrank_iff F E'⟮x⟯] at this + change IsSeparable F (restrictScalars F E'⟮x⟯) at this + exact separable_of_mem_isSeparable F K hx + +/-- If `x` and `y` are both separable elements, then `F⟮x, y⟯ / F` is a separable extension. +As a consequence, any rational function of `x` and `y` is also a separable element. -/ +theorem IntermediateField.isSeparable_adjoin_pair_of_separable {x y : E} + (hx : (minpoly F x).Separable) (hy : (minpoly F y).Separable) : + IsSeparable F F⟮x, y⟯ := by + rw [← adjoin_simple_adjoin_simple] + replace hy := hy.map_minpoly F⟮x⟯ + rw [← isSeparable_adjoin_simple_iff_separable] at hx hy + exact IsSeparable.trans F F⟮x⟯ F⟮x⟯⟮y⟯ + +namespace Field + +/-- If `x` and `y` are both separable elements, then `x * y` is also a separable element. -/ +theorem separable_mul {x y : E} (hx : (minpoly F x).Separable) (hy : (minpoly F y).Separable) : + (minpoly F (x * y)).Separable := + haveI := isSeparable_adjoin_pair_of_separable F E hx hy + separable_of_mem_isSeparable F E <| F⟮x, y⟯.mul_mem (subset_adjoin F _ (.inl rfl)) + (subset_adjoin F _ (.inr rfl)) + +/-- If `x` and `y` are both separable elements, then `x + y` is also a separable element. -/ +theorem separable_add {x y : E} (hx : (minpoly F x).Separable) (hy : (minpoly F y).Separable) : + (minpoly F (x + y)).Separable := + haveI := isSeparable_adjoin_pair_of_separable F E hx hy + separable_of_mem_isSeparable F E <| F⟮x, y⟯.add_mem (subset_adjoin F _ (.inl rfl)) + (subset_adjoin F _ (.inr rfl)) + +/-- Any element `x` of `F` is a separable element of `E / F` when embedded into `E`. -/ +theorem separable_algebraMap (x : F) : (minpoly F ((algebraMap F E) x)).Separable := by + rw [minpoly.algebraMap_eq (algebraMap F E).injective] + exact IsSeparable.separable F x + +/-- If `x` is a separable element, then `x⁻¹` is also a separable element. -/ +theorem separable_inv (x : E) (hx : (minpoly F x).Separable) : (minpoly F x⁻¹).Separable := + haveI := (isSeparable_adjoin_simple_iff_separable F E).2 hx + separable_of_mem_isSeparable F E <| F⟮x⟯.inv_mem <| mem_adjoin_simple_self F x end Field From fb3fd7cd7a0004f3d9bc0daf99c3d767cf6e7600 Mon Sep 17 00:00:00 2001 From: Jujian Zhang Date: Thu, 28 Dec 2023 07:15:20 +0000 Subject: [PATCH 267/353] feat: add some constructions about `RelSeries` (`append`, `insert_nth`, `map`, `comap`) (#3858) - appending a relation series to another one - insert an element into a relation series to make a longer relation series - map a relation series across a relation preserving function - pullback a lt series across a surjective strictly co-monotonic function. (`f` is strictly co-monotonic if `f x < f y` implies `x < y`) --- Mathlib/Order/RelSeries.lean | 156 ++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 2 deletions(-) diff --git a/Mathlib/Order/RelSeries.lean b/Mathlib/Order/RelSeries.lean index fb4045836a226..2643882f0d9f4 100644 --- a/Mathlib/Order/RelSeries.lean +++ b/Mathlib/Order/RelSeries.lean @@ -1,11 +1,13 @@ /- Copyright (c) 2023 Jujian Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jujian Zhang +Authors: Jujian Zhang, Fangming Li -/ import Mathlib.Logic.Equiv.Fin import Mathlib.Data.List.Indexes import Mathlib.Data.Rel +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Abel /-! # Series of a relation @@ -16,6 +18,7 @@ If `r` is a relation on `α` then a relation series of length `n` is a series -/ variable {α : Type*} (r : Rel α α) +variable {β : Type*} (s : Rel β β) /-- Let `r` be a relation on `α`, a relation series of `r` of length `n` is a series @@ -154,6 +157,125 @@ protected noncomputable def withLength [r.InfiniteDimensional] (n : ℕ) : RelSe lemma nonempty_of_infiniteDimensional [r.InfiniteDimensional] : Nonempty α := ⟨RelSeries.withLength r 0 0⟩ +instance membership : Membership α (RelSeries r) := + ⟨(· ∈ Set.range ·)⟩ + +theorem mem_def {x : α} {s : RelSeries r} : x ∈ s ↔ x ∈ Set.range s := + Iff.rfl + +/-- Start of a series, i.e. for `a₀ -r→ a₁ -r→ ... -r→ aₙ`, its head is `a₀`. + +Since a relation series is assumed to be non-empty, this is well defined. -/ +def head (x : RelSeries r) : α := x 0 + +/-- End of a series, i.e. for `a₀ -r→ a₁ -r→ ... -r→ aₙ`, its last element is `aₙ`. + +Since a relation series is assumed to be non-empty, this is well defined. -/ +def last (x : RelSeries r) : α := x <| Fin.last _ + +lemma head_mem (x : RelSeries r) : x.head ∈ x := ⟨_, rfl⟩ + +lemma last_mem (x : RelSeries r) : x.last ∈ x := ⟨_, rfl⟩ + +/-- +If `a₀ -r→ a₁ -r→ ... -r→ aₙ` and `b₀ -r→ b₁ -r→ ... -r→ bₘ` are two strict series +such that `r aₙ b₀`, then there is a chain of length `n + m + 1` given by +`a₀ -r→ a₁ -r→ ... -r→ aₙ -r→ b₀ -r→ b₁ -r→ ... -r→ bₘ`. +-/ +@[simps] +def append (p q : RelSeries r) (connect : r p.last q.head) : RelSeries r where + length := p.length + q.length + 1 + toFun := Fin.append p q ∘ Fin.cast (by abel) + step i := by + obtain hi | rfl | hi := + lt_trichotomy i (Fin.castLE (by linarith) (Fin.last _ : Fin (p.length + 1))) + · convert p.step ⟨i.1, hi⟩ <;> convert Fin.append_left p q _ <;> rfl + · convert connect + · convert Fin.append_left p q _; rfl + · convert Fin.append_right p q _; rfl + · set x := _; set y := _ + change r (Fin.append p q x) (Fin.append p q y) + have hx : x = Fin.natAdd _ ⟨i - (p.length + 1), Nat.sub_lt_left_of_lt_add hi <| + i.2.trans <| by linarith!⟩ + · ext; dsimp; rw [Nat.add_sub_cancel']; exact hi + have hy : y = Fin.natAdd _ ⟨i - p.length, Nat.sub_lt_left_of_lt_add (le_of_lt hi) + (by exact i.2)⟩ + · ext + dsimp + conv_rhs => rw [Nat.add_comm p.length 1, add_assoc, + Nat.add_sub_cancel' <| le_of_lt (show p.length < i.1 from hi), add_comm] + rw [hx, Fin.append_right, hy, Fin.append_right] + convert q.step ⟨i - (p.length + 1), Nat.sub_lt_left_of_lt_add hi <| + by convert i.2 using 1; abel⟩ + rw [Fin.succ_mk, Nat.sub_eq_iff_eq_add (le_of_lt hi : p.length ≤ i), + Nat.add_assoc _ 1, add_comm 1, Nat.sub_add_cancel] + exact hi + +/-- +For two types `α, β` and relation on them `r, s`, if `f : α → β` preserves relation `r`, then an +`r`-series can be pushed out to an `s`-series by +`a₀ -r→ a₁ -r→ ... -r→ aₙ ↦ f a₀ -s→ f a₁ -s→ ... -s→ f aₙ` +-/ +@[simps] +def map (p : RelSeries r) + (f : α → β) (hf : ∀ ⦃x y : α⦄, r x y → s (f x) (f y)) : RelSeries s where + length := p.length + toFun := f.comp p + step := (hf <| p.step .) + +/-- +If `a₀ -r→ a₁ -r→ ... -r→ aₙ` is an `r`-series and `a` is such that +`aᵢ -r→ a -r→ a_ᵢ₊₁`, then +`a₀ -r→ a₁ -r→ ... -r→ a_i -r→ a -r→ aᵢ₊₁ -r→ ... -r→ aₙ` +is another `r`-series +-/ +@[simps] +def insertNth (p : RelSeries r) (i : Fin p.length) (a : α) + (prev_connect : r (p (Fin.castSucc i)) a) (connect_next : r a (p i.succ)) : RelSeries r where + toFun := (Fin.castSucc i.succ).insertNth a p + step m := by + set x := _; set y := _; change r x y + obtain hm | hm | hm := lt_trichotomy m.1 i.1 + · convert p.step ⟨m, hm.trans i.2⟩ + · show Fin.insertNth _ _ _ _ = _ + rw [Fin.insertNth_apply_below] + pick_goal 2; exact hm.trans (lt_add_one _) + simp + · show Fin.insertNth _ _ _ _ = _ + rw [Fin.insertNth_apply_below] + pick_goal 2; change m.1 + 1 < i.1 + 1; rwa [add_lt_add_iff_right] + simp; rfl + · rw [show x = p m from show Fin.insertNth _ _ _ _ = _ by + rw [Fin.insertNth_apply_below] + pick_goal 2; show m.1 < i.1 + 1; exact hm ▸ lt_add_one _ + simp] + convert prev_connect + · ext; exact hm + · change Fin.insertNth _ _ _ _ = _ + rw [show m.succ = i.succ.castSucc by ext; change _ + 1 = _ + 1; rw [hm], + Fin.insertNth_apply_same] + · rw [Nat.lt_iff_add_one_le, le_iff_lt_or_eq] at hm + obtain hm | hm := hm + · convert p.step ⟨m.1 - 1, Nat.sub_lt_right_of_lt_add (by linarith) m.2⟩ + · change Fin.insertNth _ _ _ _ = _ + rw [Fin.insertNth_apply_above (h := hm)] + aesop + · change Fin.insertNth _ _ _ _ = _ + rw [Fin.insertNth_apply_above] + swap; exact hm.trans (lt_add_one _) + simp only [Fin.val_succ, Nat.zero_eq, Fin.pred_succ, eq_rec_constant, ge_iff_le, + Fin.succ_mk] + congr + exact Fin.ext <| Eq.symm <| Nat.succ_pred_eq_of_pos (lt_trans (Nat.zero_lt_succ _) hm) + · convert connect_next + · change Fin.insertNth _ _ _ _ = _ + rw [show m.castSucc = i.succ.castSucc from Fin.ext hm.symm, Fin.insertNth_apply_same] + · change Fin.insertNth _ _ _ _ = _ + rw [Fin.insertNth_apply_above] + swap; change i.1 + 1 < m.1 + 1; rw [hm]; exact lt_add_one _ + simp only [Fin.pred_succ, eq_rec_constant] + congr; ext; exact hm.symm + end RelSeries /-- A type is finite dimensional if its `LTSeries` has bounded length. -/ @@ -166,7 +288,7 @@ abbrev InfiniteDimensionalOrder (γ : Type*) [Preorder γ] := section LTSeries -variable (α) [Preorder α] +variable (α) [Preorder α] [Preorder β] /-- If `α` is a preorder, a LTSeries is a relation series of the less than relation. -/ @@ -208,6 +330,36 @@ lemma strictMono (x : LTSeries α) : StrictMono x := lemma monotone (x : LTSeries α) : Monotone x := x.strictMono.monotone + +/-- An alternative constructor of `LTSeries` from a strictly monotone function. -/ +@[simps] +def mk (length : ℕ) (toFun : Fin (length + 1) → α) (strictMono : StrictMono toFun) : + LTSeries α where + toFun := toFun + step i := strictMono <| lt_add_one i.1 + +/-- +For two preorders `α, β`, if `f : α → β` is strictly monotonic, then a strict chain of `α` +can be pushed out to a strict chain of `β` by +`a₀ < a₁ < ... < aₙ ↦ f a₀ < f a₁ < ... < f aₙ` +-/ +@[simps!] +def map (p : LTSeries α) (f : α → β) (hf : StrictMono f) : LTSeries β := + LTSeries.mk p.length (f.comp p) (hf.comp p.strictMono) + +/-- +For two preorders `α, β`, if `f : α → β` is surjective and strictly comonotonic, then a +strict series of `β` can be pulled back to a strict chain of `α` by +`b₀ < b₁ < ... < bₙ ↦ f⁻¹ b₀ < f⁻¹ b₁ < ... < f⁻¹ bₙ` where `f⁻¹ bᵢ` is an arbitrary element in the +preimage of `f⁻¹ {bᵢ}`. +-/ +@[simps!] +noncomputable def comap (p : LTSeries β) (f : α → β) + (comap : ∀ ⦃x y⦄, f x < f y → x < y) + (surjective : Function.Surjective f) : + LTSeries α := mk p.length (fun i ↦ (surjective (p i)).choose) + (fun i j h ↦ comap (by simpa only [(surjective _).choose_spec] using p.strictMono h)) + end LTSeries end LTSeries From bf19b01fbf29417b81c0cc4d8357d5d37d9fff3c Mon Sep 17 00:00:00 2001 From: Jon Eugster Date: Thu, 28 Dec 2023 17:56:41 +0000 Subject: [PATCH 268/353] chore: remove `Name.isInternal'` in favour of `Name.isInternalDetail` (#9196) We can remove `Name.isInternal'` as it exists in `std` as `Name.isInternalDetail`. --- Mathlib/Lean/Expr/Basic.lean | 17 +---------------- Mathlib/Lean/Name.lean | 2 +- Mathlib/Tactic/Simps/Basic.lean | 2 +- Mathlib/Tactic/ToAdditive.lean | 2 +- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean index 3a14668d7fd41..68cbeaf94e739 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -85,21 +85,6 @@ def isPrefixOf? (pre nm : Name) : Option Name := | num p' a => (isPrefixOf? pre p').map (·.num a) | str p' s => (isPrefixOf? pre p').map (·.str s) -/-- Lean 4 makes declarations which are technically not internal -(that is, head string does not start with `_`) but which sometimes should -be treated as such. For example, the `to_additive` attribute needs to -transform `proof_1` constants generated by `Lean.Meta.mkAuxDefinitionFor`. -This might be better fixed in core, but until then, this method can act -as a polyfill. This method only looks at the name to decide whether it is probably internal. -Note: this declaration also occurs as `shouldIgnore` in the Lean 4 file `test/lean/run/printDecls`. --/ -def isInternal' (declName : Name) : Bool := - declName.isInternal || - match declName with - | .str _ s => "match_".isPrefixOf s || "proof_".isPrefixOf s - | _ => true - - open Meta -- from Lean.Server.Completion @@ -108,7 +93,7 @@ def isBlackListed {m} [Monad m] [MonadEnv m] (declName : Name) : m Bool := do if declName matches .str _ "inj" then return true if declName matches .str _ "noConfusionType" then return true let env ← getEnv - pure $ declName.isInternal' + pure $ declName.isInternalDetail || isAuxRecursor env declName || isNoConfusion env declName <||> isRec declName <||> isMatcher declName diff --git a/Mathlib/Lean/Name.lean b/Mathlib/Lean/Name.lean index 6dfe3923169cd..f79c010c65e1f 100644 --- a/Mathlib/Lean/Name.lean +++ b/Mathlib/Lean/Name.lean @@ -19,7 +19,7 @@ open Lean Meta Elab private def isBlackListed (declName : Name) : CoreM Bool := do if declName.toString.startsWith "Lean" then return true let env ← getEnv - pure $ declName.isInternal' + pure $ declName.isInternalDetail || isAuxRecursor env declName || isNoConfusion env declName <||> isRec declName <||> isMatcher declName diff --git a/Mathlib/Tactic/Simps/Basic.lean b/Mathlib/Tactic/Simps/Basic.lean index eaa82faf74ced..bf8227a2bae45 100644 --- a/Mathlib/Tactic/Simps/Basic.lean +++ b/Mathlib/Tactic/Simps/Basic.lean @@ -626,7 +626,7 @@ def checkForUnusedCustomProjs (stx : Syntax) (str : Name) (projs : Array ParsedP let nrCustomProjections := projs.toList.countP (·.isCustom) let env ← getEnv let customDeclarations := env.constants.map₂.foldl (init := #[]) fun xs nm _ => - if (str ++ `Simps).isPrefixOf nm && !nm.isInternal' then xs.push nm else xs + if (str ++ `Simps).isPrefixOf nm && !nm.isInternalDetail then xs.push nm else xs if nrCustomProjections < customDeclarations.size then Linter.logLintIf linter.simpsUnusedCustomDeclarations stx m!"Not all of the custom declarations {customDeclarations} are used. Double check the { diff --git a/Mathlib/Tactic/ToAdditive.lean b/Mathlib/Tactic/ToAdditive.lean index 25f0ea907a8bc..1e3e07a5bd8e0 100644 --- a/Mathlib/Tactic/ToAdditive.lean +++ b/Mathlib/Tactic/ToAdditive.lean @@ -544,7 +544,7 @@ partial def transformDeclAux return -- if this declaration is not `pre` and not an internal declaration, we return an error, -- since we should have already translated this declaration. - if src != pre && !src.isInternal' then + if src != pre && !src.isInternalDetail then throwError "The declaration {pre} depends on the declaration {src} which is in the namespace { pre}, but does not have the `@[to_additive]` attribute. This is not supported.\n{"" }Workaround: move {src} to a different namespace." From a58c4fe3559315020174ea26a99b59544c190361 Mon Sep 17 00:00:00 2001 From: Michael Stoll Date: Thu, 28 Dec 2023 19:05:58 +0000 Subject: [PATCH 269/353] feat(NumberTheory/SumPrimeReciprocals): the sum of 1/p over primes p diverges (#9313) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the fact that `∑ p prime, 1/p` diverges. We follow the elementary proof due to Erdős given in "THE BOOK". See [here](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Sum.20over.201.2Fp.20diverges/near/409835682) on Zulip. Co-authored-by: Michael Stoll <99838730+MichaelStollBayreuth@users.noreply.github.com> --- Mathlib.lean | 1 + Mathlib/NumberTheory/SumPrimeReciprocals.lean | 96 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 Mathlib/NumberTheory/SumPrimeReciprocals.lean diff --git a/Mathlib.lean b/Mathlib.lean index 805f2cd153727..72f713857128d 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2801,6 +2801,7 @@ import Mathlib.NumberTheory.RamificationInertia import Mathlib.NumberTheory.Rayleigh import Mathlib.NumberTheory.SmoothNumbers import Mathlib.NumberTheory.SumFourSquares +import Mathlib.NumberTheory.SumPrimeReciprocals import Mathlib.NumberTheory.SumTwoSquares import Mathlib.NumberTheory.VonMangoldt import Mathlib.NumberTheory.WellApproximable diff --git a/Mathlib/NumberTheory/SumPrimeReciprocals.lean b/Mathlib/NumberTheory/SumPrimeReciprocals.lean new file mode 100644 index 0000000000000..5f2005bdbe782 --- /dev/null +++ b/Mathlib/NumberTheory/SumPrimeReciprocals.lean @@ -0,0 +1,96 @@ +/- +Copyright (c) 2023 Michael Stoll. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Michael Stoll +-/ +import Mathlib.NumberTheory.SmoothNumbers +import Mathlib.Analysis.PSeries + +/-! +# The sum of the reciprocals of the primes diverges + +We show that the sum of `1/p`, where `p` runs through the prime numbers, diverges. +We follow the elementary proof by Erdős that is reproduced in "Proofs from THE BOOK". +There are two versions of the main result: `not_summable_one_div_on_primes`, which +expresses the sum as a sub-sum of the harmonic series, and `Nat.Primes.not_summable_one_div`, +which writes it as a sum over `Nat.Primes`. We also show that the sum of `p^r` for `r : ℝ` +converges if and only if `r < -1`; see `Nat.Primes.summable_rpow`. + +## References + +See the sixth proof for the infinity of primes in Chapter 1 of [aigner1999proofs]. +The proof is due to Erdős. +-/ + +/-- The cardinality of the set of `k`-rough numbers `≤ N` is bounded by `N` times the sum +of `1/p` over the primes `k ≤ p ≤ N`. -/ +-- This needs `Mathlib.Data.IsROrC.Basic`, so we put it here +-- instead of in `Mathlib.NumberTheory.SmoothNumbers`. +lemma Nat.roughNumbersUpTo_card_le' (N k : ℕ) : + (roughNumbersUpTo N k).card ≤ + N * (N.succ.primesBelow \ k.primesBelow).sum (fun p ↦ (1 : ℝ) / p) := by + simp_rw [Finset.mul_sum, mul_one_div] + exact (Nat.cast_le.mpr <| roughNumbersUpTo_card_le N k).trans <| + (cast_sum (β := ℝ) ..) ▸ Finset.sum_le_sum fun n _ ↦ cast_div_le + +open Set Nat BigOperators + +/-- The sum over primes `k ≤ p ≤ 4^(π(k-1)+1)` over `1/p` (as a real number) is at least `1/2`. -/ +lemma one_half_le_sum_primes_ge_one_div (k : ℕ) : + 1 / 2 ≤ ∑ p in (4 ^ (k.primesBelow.card + 1)).succ.primesBelow \ k.primesBelow, + (1 / p : ℝ) := by + set m : ℕ := 2 ^ k.primesBelow.card + set N₀ : ℕ := 2 * m ^ 2 with hN₀ + let S : ℝ := ((2 * N₀).succ.primesBelow \ k.primesBelow).sum (fun p ↦ (1 / p : ℝ)) + suffices : 1 / 2 ≤ S + · convert this using 5 + rw [show 4 = 2 ^ 2 by norm_num, pow_right_comm] + ring + suffices : 2 * N₀ ≤ m * (2 * N₀).sqrt + 2 * N₀ * S + · rwa [hN₀, ← mul_assoc, ← pow_two 2, ← mul_pow, sqrt_eq', ← sub_le_iff_le_add', + cast_mul, cast_mul, cast_pow, cast_two, + show (2 * (2 * m ^ 2) - m * (2 * m) : ℝ) = 2 * (2 * m ^ 2) * (1 / 2) by ring, + _root_.mul_le_mul_left <| by positivity] at this + calc (2 * N₀ : ℝ) + _ = ((2 * N₀).smoothNumbersUpTo k).card + ((2 * N₀).roughNumbersUpTo k).card := by + exact_mod_cast ((2 * N₀).smoothNumbersUpTo_card_add_roughNumbersUpTo_card k).symm + _ ≤ m * (2 * N₀).sqrt + ((2 * N₀).roughNumbersUpTo k).card := by + exact_mod_cast Nat.add_le_add_right ((2 * N₀).smoothNumbersUpTo_card_le k) _ + _ ≤ m * (2 * N₀).sqrt + 2 * N₀ * S := add_le_add_left ?_ _ + exact_mod_cast roughNumbersUpTo_card_le' (2 * N₀) k + +/-- The sum over the reciprocals of the primes diverges. -/ +theorem not_summable_one_div_on_primes : + ¬ Summable (indicator {p | p.Prime} (fun n : ℕ ↦ (1 : ℝ) / n)) := by + intro h + obtain ⟨k, hk⟩ := h.nat_tsum_vanishing (Iio_mem_nhds one_half_pos : Iio (1 / 2 : ℝ) ∈ nhds 0) + specialize hk ({p | Nat.Prime p} ∩ {p | k ≤ p}) <| inter_subset_right .. + rw [tsum_subtype, indicator_indicator, inter_eq_left.mpr <| fun n hn ↦ hn.1, mem_Iio] at hk + have h' : Summable (indicator ({p | Nat.Prime p} ∩ {p | k ≤ p}) fun n ↦ (1 : ℝ) / n) + · convert h.indicator {n : ℕ | k ≤ n} using 1 + simp only [indicator_indicator, inter_comm] + refine ((one_half_le_sum_primes_ge_one_div k).trans_lt <| LE.le.trans_lt ?_ hk).false + convert sum_le_tsum (primesBelow ((4 ^ (k.primesBelow.card + 1)).succ) \ primesBelow k) + (fun n _ ↦ indicator_nonneg (fun p _ ↦ by positivity) _) h' using 2 with p hp + obtain ⟨hp₁, hp₂⟩ := mem_setOf_eq ▸ Finset.mem_sdiff.mp hp + have hpp := prime_of_mem_primesBelow hp₁ + refine (indicator_of_mem (mem_def.mpr ⟨hpp, ?_⟩) fun n : ℕ ↦ (1 / n : ℝ)).symm + exact not_lt.mp <| (not_and_or.mp <| (not_congr mem_primesBelow).mp hp₂).neg_resolve_right hpp + +/-- The sum over the reciprocals of the primes diverges. -/ +theorem Nat.Primes.not_summable_one_div : ¬ Summable (fun p : Nat.Primes ↦ (1 / p : ℝ)) := by + convert summable_subtype_iff_indicator.mp.mt not_summable_one_div_on_primes + +/-- The series over `p^r` for primes `p` converges if and only if `r < -1`. -/ +theorem Nat.Primes.summable_rpow {r : ℝ} : + Summable (fun p : Nat.Primes ↦ (p : ℝ) ^ r) ↔ r < -1 := by + by_cases h : r < -1 + · -- case `r < -1` + simp only [h, iff_true] + exact (Real.summable_nat_rpow.mpr h).subtype _ + · -- case `-1 ≤ r` + simp only [h, iff_false] + refine fun H ↦ Nat.Primes.not_summable_one_div <| H.of_nonneg_of_le (fun _ ↦ by positivity) ?_ + intro p + rw [one_div, ← Real.rpow_neg_one] + exact Real.rpow_le_rpow_of_exponent_le (by exact_mod_cast p.prop.one_lt.le) <| not_lt.mp h From 288b6c5536e3a1c520aff20a999fe55a627c9637 Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Thu, 28 Dec 2023 21:07:40 +0000 Subject: [PATCH 270/353] doc(FieldTheory/SeparableDegree): fix the formula in docstring (#9318) --- Mathlib/FieldTheory/SeparableDegree.lean | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean index 43ac871242137..a401c7593796e 100644 --- a/Mathlib/FieldTheory/SeparableDegree.lean +++ b/Mathlib/FieldTheory/SeparableDegree.lean @@ -25,9 +25,10 @@ This file contains basics about the separable degree of a field extension. **Remark:** if `E / F` is not algebraic, then this definition makes no mathematical sense, and if it is infinite, then its cardinality doesn't behave as expected (namely, not equal to the - field extension degree of `separableClosure F E / F`). For example, - $\operatorname{Emb}_{\mathbb{Q}}(\mathbb{Q}(\mu_{p^\infty}))\cong\mathbb{Z}_p^\times$ which is - uncountable, while $[\mathbb{Q}(\mu_{p^\infty}):\mathbb{Q}]$ is countable. + field extension degree of `separableClosure F E / F`). For example, if $ F = \mathbb{Q} $ and + $ E = \mathbb{Q}( \mu_{p^\infty} ) $, then $ \operatorname{Emb}_F (E) $ is in bijection with + $\operatorname{Gal}(E/F)$, which is isomorphic to + $ \mathbb{Z}_p^\times $, which is uncountable, while $ [E:F] $ is countable. **TODO:** prove or disprove that if `E / F` is algebraic and `Emb F E` is infinite, then `Field.Emb F E` has cardinality `2 ^ Module.rank F (separableClosure F E)`. From 8f17470fada539b70956f0ae655a9bb9e5cd67fb Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 29 Dec 2023 06:46:33 +0000 Subject: [PATCH 271/353] refactor(*): change definition of `Set.image2` etc (#9275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Redefine `Set.image2` to use `∃ a ∈ s, ∃ b ∈ t, f a b = c` instead of `∃ a b, a ∈ s ∧ b ∈ t ∧ f a b = c`. - Redefine `Set.seq` as `Set.image2`. The new definition is equal to the old one but `rw [Set.seq]` gives a different result. - Redefine `Filter.map₂` to use `∃ u ∈ f, ∃ v ∈ g, image2 m u v ⊆ s` instead of `∃ u v, u ∈ f ∧ v ∈ g ∧ ...` - Update lemmas like `Set.mem_image2`, `Finset.mem_image₂`, `Set.mem_mul`, `Finset.mem_div` etc The two reasons to make the change are: - `∃ a ∈ s, ∃ b ∈ t, _` is a `simp`-normal form, and - it looks a bit nicer. --- Mathlib/Algebra/Algebra/Tower.lean | 4 +- Mathlib/Algebra/Group/UniqueProds.lean | 20 ++++----- Mathlib/Algebra/Module/Injective.lean | 2 +- .../Algebra/Module/Submodule/Bilinear.lean | 8 ++-- .../Algebra/Module/Submodule/Pointwise.lean | 9 ++-- Mathlib/Algebra/Order/CompleteField.lean | 4 +- Mathlib/Algebra/Pointwise/Stabilizer.lean | 4 +- Mathlib/Analysis/Convex/Basic.lean | 4 +- Mathlib/Analysis/Convex/Cone/Basic.lean | 16 +++---- Mathlib/Analysis/Convex/Side.lean | 20 ++++----- Mathlib/Analysis/Convex/Star.lean | 2 +- Mathlib/Analysis/Convex/Strict.lean | 2 +- Mathlib/Analysis/Convolution.lean | 6 +-- Mathlib/Analysis/Normed/Group/AddTorsor.lean | 6 +-- Mathlib/Analysis/Normed/Group/Pointwise.lean | 2 +- Mathlib/Analysis/NormedSpace/lpSpace.lean | 2 +- Mathlib/Analysis/Seminorm.lean | 4 +- .../Additive/PluenneckeRuzsa.lean | 2 +- .../Combinatorics/Additive/RuzsaCovering.lean | 4 +- Mathlib/Computability/DFA.lean | 6 +-- Mathlib/Computability/Language.lean | 6 +-- Mathlib/Data/Finset/MulAntidiagonal.lean | 6 +-- Mathlib/Data/Finset/NAry.lean | 4 +- Mathlib/Data/Finset/NatDivisors.lean | 2 +- Mathlib/Data/Finset/Pointwise.lean | 19 ++++----- Mathlib/Data/Set/Basic.lean | 3 +- Mathlib/Data/Set/Lattice.lean | 22 +++++----- Mathlib/Data/Set/NAry.lean | 42 +++++++++---------- Mathlib/Data/Set/Pointwise/Basic.lean | 26 ++++++------ Mathlib/Data/Set/Pointwise/BigOperators.lean | 2 +- Mathlib/Data/Set/Pointwise/Interval.lean | 22 +++++----- Mathlib/Data/Set/Pointwise/ListOfFn.lean | 2 +- Mathlib/Data/Set/Pointwise/SMul.lean | 14 +++---- Mathlib/Dynamics/OmegaLimit.lean | 8 ++-- Mathlib/FieldTheory/KrullTopology.lean | 2 +- Mathlib/Geometry/Manifold/ChartedSpace.lean | 2 +- .../Manifold/LocalInvariantProperties.lean | 2 +- .../Manifold/SmoothManifoldWithCorners.lean | 2 +- Mathlib/GroupTheory/Complement.lean | 2 +- Mathlib/GroupTheory/DoubleCoset.lean | 10 +++-- .../GroupAction/SubMulAction/Pointwise.lean | 11 +++-- Mathlib/GroupTheory/QuotientGroup.lean | 6 +-- Mathlib/GroupTheory/Schreier.lean | 10 ++--- Mathlib/GroupTheory/Subgroup/Pointwise.lean | 36 ++++++++-------- Mathlib/GroupTheory/Submonoid/Pointwise.lean | 12 +++--- .../AffineSpace/AffineSubspace.lean | 24 +++++------ Mathlib/LinearAlgebra/TensorProduct.lean | 2 +- .../Constructions/Prod/Basic.lean | 14 +++---- Mathlib/MeasureTheory/Function/Jacobian.lean | 2 +- Mathlib/MeasureTheory/Measure/Haar/Basic.lean | 5 +-- .../MeasureTheory/Measure/Haar/Unique.lean | 2 +- Mathlib/Order/Filter/NAry.lean | 20 ++++----- Mathlib/Order/Filter/Pointwise.lean | 38 ++++++++--------- .../Probability/Kernel/Disintegration.lean | 2 +- Mathlib/RingTheory/Adjoin/FG.lean | 2 +- Mathlib/RingTheory/Adjoin/Tower.lean | 2 +- Mathlib/RingTheory/HahnSeries.lean | 8 ++-- Mathlib/RingTheory/Ideal/Norm.lean | 2 +- Mathlib/Topology/Algebra/FilterBasis.lean | 4 +- Mathlib/Topology/Algebra/Group/Basic.lean | 18 ++++---- Mathlib/Topology/Algebra/Monoid.lean | 6 +-- .../Algebra/Nonarchimedean/AdicTopology.lean | 2 +- .../Algebra/Nonarchimedean/Bases.lean | 6 +-- .../Algebra/Nonarchimedean/Basic.lean | 2 +- Mathlib/Topology/Algebra/UniformGroup.lean | 2 +- Mathlib/Topology/Algebra/Valuation.lean | 2 +- Mathlib/Topology/Bases.lean | 2 +- Mathlib/Topology/EMetricSpace/Lipschitz.lean | 9 ++-- 68 files changed, 283 insertions(+), 293 deletions(-) diff --git a/Mathlib/Algebra/Algebra/Tower.lean b/Mathlib/Algebra/Algebra/Tower.lean index a15de8f06bf3c..99a994bf4f4b0 100644 --- a/Mathlib/Algebra/Algebra/Tower.lean +++ b/Mathlib/Algebra/Algebra/Tower.lean @@ -299,7 +299,7 @@ open IsScalarTower theorem smul_mem_span_smul_of_mem {s : Set S} {t : Set A} {k : S} (hks : k ∈ span R s) {x : A} (hx : x ∈ t) : k • x ∈ span R (s • t) := - span_induction hks (fun c hc => subset_span <| Set.mem_smul.2 ⟨c, x, hc, hx, rfl⟩) + span_induction hks (fun c hc => subset_span <| Set.smul_mem_smul hc hx) (by rw [zero_smul]; exact zero_mem _) (fun c₁ c₂ ih₁ ih₂ => by rw [add_smul]; exact add_mem ih₁ ih₂) fun b c hc => by rw [IsScalarTower.smul_assoc]; exact smul_mem _ _ hc @@ -319,7 +319,7 @@ theorem smul_mem_span_smul' {s : Set S} (hs : span R s = ⊤) {t : Set A} {k : S (hx : x ∈ span R (s • t)) : k • x ∈ span R (s • t) := span_induction hx (fun x hx => by - let ⟨p, q, _hp, hq, hpq⟩ := Set.mem_smul.1 hx + let ⟨p, _hp, q, hq, hpq⟩ := Set.mem_smul.1 hx rw [← hpq, smul_smul] exact smul_mem_span_smul_of_mem (hs.symm ▸ mem_top) hq) (by rw [smul_zero]; exact zero_mem _) diff --git a/Mathlib/Algebra/Group/UniqueProds.lean b/Mathlib/Algebra/Group/UniqueProds.lean index 704c4439e4810..e1185c20cc2a5 100644 --- a/Mathlib/Algebra/Group/UniqueProds.lean +++ b/Mathlib/Algebra/Group/UniqueProds.lean @@ -375,8 +375,8 @@ open MulOpposite in uniqueMul_of_nonempty {A B} hA hB := by classical obtain ⟨g1, h1, g2, h2, hu⟩ := h (hB.mul hA) - obtain ⟨b1, a1, hb1, ha1, rfl⟩ := mem_mul.mp h1 - obtain ⟨b2, a2, hb2, ha2, rfl⟩ := mem_mul.mp h2 + obtain ⟨b1, hb1, a1, ha1, rfl⟩ := mem_mul.mp h1 + obtain ⟨b2, hb2, a2, ha2, rfl⟩ := mem_mul.mp h2 refine ⟨a1, ha1, b2, hb2, fun a b ha hb he => ?_⟩ specialize hu (mul_mem_mul hb1 ha) (mul_mem_mul hb ha2) _ · rw [mul_assoc b1, ← mul_assoc a, he, mul_assoc a1, ← mul_assoc b1] @@ -414,26 +414,26 @@ open MulOpposite in · obtain ⟨e, he, f, hf, hu⟩ := this clear_value C D simp only [UniqueMul, mem_mul, mem_image] at he hf hu - obtain ⟨_, c1, ⟨d1, hd1, rfl⟩, hc1, rfl⟩ := he - obtain ⟨d2, _, hd2, ⟨c2, hc2, rfl⟩, rfl⟩ := hf + obtain ⟨_, ⟨d1, hd1, rfl⟩, c1, hc1, rfl⟩ := he + obtain ⟨d2, hd2, _, ⟨c2, hc2, rfl⟩, rfl⟩ := hf by_cases h12 : c1 ≠ 1 ∨ d2 ≠ 1 · refine ⟨c1, hc1, d2, hd2, h12, fun c3 d3 hc3 hd3 he => ?_⟩ - specialize hu ⟨_, _, ⟨_, hd1, rfl⟩, hc3, rfl⟩ ⟨_, _, hd3, ⟨_, hc2, rfl⟩, rfl⟩ + specialize hu ⟨_, ⟨_, hd1, rfl⟩, _, hc3, rfl⟩ ⟨_, hd3, _, ⟨_, hc2, rfl⟩, rfl⟩ rw [mul_left_cancel_iff, mul_right_cancel_iff, mul_assoc, ← mul_assoc c3, he, mul_assoc, mul_assoc] at hu; exact hu rfl push_neg at h12; obtain ⟨rfl, rfl⟩ := h12 by_cases h21 : c2 ≠ 1 ∨ d1 ≠ 1 · refine ⟨c2, hc2, d1, hd1, h21, fun c4 d4 hc4 hd4 he => ?_⟩ - specialize hu ⟨_, _, ⟨_, hd4, rfl⟩, hC, rfl⟩ ⟨_, _, hD, ⟨_, hc4, rfl⟩, rfl⟩ + specialize hu ⟨_, ⟨_, hd4, rfl⟩, _, hC, rfl⟩ ⟨_, hD, _, ⟨_, hc4, rfl⟩, rfl⟩ simpa only [mul_one, one_mul, ← mul_inv_rev, he, true_imp_iff, inv_inj, and_comm] using hu push_neg at h21; obtain ⟨rfl, rfl⟩ := h21 rcases hcard with hC | hD · obtain ⟨c, hc, hc1⟩ := exists_ne_of_one_lt_card hC 1 refine (hc1 ?_).elim - simpa using hu ⟨_, _, ⟨_, hD, rfl⟩, hc, rfl⟩ ⟨_, _, hD, ⟨_, hc, rfl⟩, rfl⟩ + simpa using hu ⟨_, ⟨_, hD, rfl⟩, _, hc, rfl⟩ ⟨_, hD, _, ⟨_, hc, rfl⟩, rfl⟩ · obtain ⟨d, hd, hd1⟩ := exists_ne_of_one_lt_card hD 1 refine (hd1 ?_).elim - simpa using hu ⟨_, _, ⟨_, hd, rfl⟩, hC, rfl⟩ ⟨_, _, hd, ⟨_, hC, rfl⟩, rfl⟩ + simpa using hu ⟨_, ⟨_, hd, rfl⟩, _, hC, rfl⟩ ⟨_, hd, _, ⟨_, hC, rfl⟩, rfl⟩ all_goals apply_rules [Nonempty.mul, Nonempty.image, Finset.Nonempty.map, hc.1, hc.2.1] open UniqueMul in @@ -571,8 +571,8 @@ instance (priority := 100) of_covariant_right [IsRightCancelMul G] obtain ⟨hA, hB, -⟩ := Nat.one_lt_mul_iff.mp hc rw [card_pos] at hA hB rw [← card_product] at hc - obtain ⟨a0, b0, ha0, hb0, he0⟩ := mem_mul.mp (max'_mem _ <| hA.mul hB) - obtain ⟨a1, b1, ha1, hb1, he1⟩ := mem_mul.mp (min'_mem _ <| hA.mul hB) + obtain ⟨a0, ha0, b0, hb0, he0⟩ := mem_mul.mp (max'_mem _ <| hA.mul hB) + obtain ⟨a1, ha1, b1, hb1, he1⟩ := mem_mul.mp (min'_mem _ <| hA.mul hB) have : UniqueMul A B a0 b0 · intro a b ha hb he obtain hl | rfl | hl := lt_trichotomy b b0 diff --git a/Mathlib/Algebra/Module/Injective.lean b/Mathlib/Algebra/Module/Injective.lean index 04617cfcdb57b..25c87fefc1689 100644 --- a/Mathlib/Algebra/Module/Injective.lean +++ b/Mathlib/Algebra/Module/Injective.lean @@ -260,7 +260,7 @@ private theorem extensionOfMax_adjoin.aux1 {y : N} (x : supExtensionOfMaxSinglet ∃ (a : (extensionOfMax i f).domain) (b : R), x.1 = a.1 + b • y := by have mem1 : x.1 ∈ (_ : Set _) := x.2 rw [Submodule.coe_sup] at mem1 - rcases mem1 with ⟨a, b, a_mem, b_mem : b ∈ (Submodule.span R _ : Submodule R N), eq1⟩ + rcases mem1 with ⟨a, a_mem, b, b_mem : b ∈ (Submodule.span R _ : Submodule R N), eq1⟩ rw [Submodule.mem_span_singleton] at b_mem rcases b_mem with ⟨z, eq2⟩ exact ⟨⟨a, a_mem⟩, z, by rw [← eq1, ← eq2]⟩ diff --git a/Mathlib/Algebra/Module/Submodule/Bilinear.lean b/Mathlib/Algebra/Module/Submodule/Bilinear.lean index 4ff2c3d72e210..8450fa7fa5411 100644 --- a/Mathlib/Algebra/Module/Submodule/Bilinear.lean +++ b/Mathlib/Algebra/Module/Submodule/Bilinear.lean @@ -68,12 +68,12 @@ theorem map₂_span_span (f : M →ₗ[R] N →ₗ[R] P) (s : Set M) (t : Set N) intro a ha apply @span_induction' R N _ _ _ t intro b hb - exact subset_span ⟨_, _, ‹_›, ‹_›, rfl⟩ + exact subset_span ⟨_, ‹_›, _, ‹_›, rfl⟩ all_goals intros; simp only [*, add_mem, smul_mem, zero_mem, _root_.map_zero, map_add, LinearMap.zero_apply, LinearMap.add_apply, LinearMap.smul_apply, map_smul] - · rw [span_le] - rintro _ ⟨a, b, ha, hb, rfl⟩ + · rw [span_le, image2_subset_iff] + intro a ha b hb exact apply_mem_map₂ _ (subset_span ha) (subset_span hb) #align submodule.map₂_span_span Submodule.map₂_span_span variable {R} @@ -132,7 +132,7 @@ theorem map₂_sup_left (f : M →ₗ[R] N →ₗ[R] P) (p₁ p₂ : Submodule R theorem image2_subset_map₂ (f : M →ₗ[R] N →ₗ[R] P) (p : Submodule R M) (q : Submodule R N) : Set.image2 (fun m n => f m n) (↑p : Set M) (↑q : Set N) ⊆ (↑(map₂ f p q) : Set P) := by - rintro _ ⟨i, j, hi, hj, rfl⟩ + rintro _ ⟨i, hi, j, hj, rfl⟩ exact apply_mem_map₂ _ hi hj #align submodule.image2_subset_map₂ Submodule.image2_subset_map₂ diff --git a/Mathlib/Algebra/Module/Submodule/Pointwise.lean b/Mathlib/Algebra/Module/Submodule/Pointwise.lean index 712607fa38d87..a35af4ec0aaf7 100644 --- a/Mathlib/Algebra/Module/Submodule/Pointwise.lean +++ b/Mathlib/Algebra/Module/Submodule/Pointwise.lean @@ -508,14 +508,13 @@ protected def pointwiseSetMulAction [SMulCommClass R R M] : fun h => ⟨m, h, (one_smul _ _).symm⟩⟩ mul_smul s t x := le_antisymm (set_smul_le _ _ _ <| by rintro _ _ ⟨_, _, _, _, rfl⟩ _; rw [mul_smul]; aesop) - (set_smul_le _ _ _ <| by - rintro r m hr hm + (set_smul_le _ _ _ <| fun r m hr hm ↦ by have : SMulCommClass R R x := ⟨fun r s m => Subtype.ext <| smul_comm _ _ _⟩ obtain ⟨c, hc1, rfl⟩ := mem_set_smul _ _ _ |>.mp hm simp only [Finsupp.sum, AddSubmonoid.coe_finset_sum, coe_toAddSubmonoid, SetLike.val_smul, - Finset.smul_sum] - exact Submodule.sum_mem _ fun r' hr' ↦ mul_smul r r' (c r' : M) ▸ - mem_set_smul_of_mem_mem (mem1 := ⟨r, r', hr, hc1 hr', rfl⟩) (mem2 := (c _).2)) + Finset.smul_sum, smul_smul] + exact Submodule.sum_mem _ fun r' hr' ↦ + mem_set_smul_of_mem_mem (Set.mul_mem_mul hr (hc1 hr')) (c _).2) scoped[Pointwise] attribute [instance] Submodule.pointwiseSetMulAction diff --git a/Mathlib/Algebra/Order/CompleteField.lean b/Mathlib/Algebra/Order/CompleteField.lean index 453f2cae49456..f52ab85b0b9df 100644 --- a/Mathlib/Algebra/Order/CompleteField.lean +++ b/Mathlib/Algebra/Order/CompleteField.lean @@ -150,11 +150,11 @@ theorem cutMap_add (a b : α) : cutMap β (a + b) = cutMap β a + cutMap β b := refine (image_subset_iff.2 fun q hq => ?_).antisymm ?_ · rw [mem_setOf_eq, ← sub_lt_iff_lt_add] at hq obtain ⟨q₁, hq₁q, hq₁ab⟩ := exists_rat_btwn hq - refine ⟨q₁, q - q₁, by rwa [coe_mem_cutMap_iff], ?_, add_sub_cancel'_right _ _⟩ + refine ⟨q₁, by rwa [coe_mem_cutMap_iff], q - q₁, ?_, add_sub_cancel'_right _ _⟩ · norm_cast rw [coe_mem_cutMap_iff] exact mod_cast sub_lt_comm.mp hq₁q - · rintro _ ⟨_, _, ⟨qa, ha, rfl⟩, ⟨qb, hb, rfl⟩, rfl⟩ + · rintro _ ⟨_, ⟨qa, ha, rfl⟩, _, ⟨qb, hb, rfl⟩, rfl⟩ -- After leanprover/lean4#2734, `norm_cast` needs help with beta reduction. refine' ⟨qa + qb, _, by beta_reduce; norm_cast⟩ rw [mem_setOf_eq, cast_add] diff --git a/Mathlib/Algebra/Pointwise/Stabilizer.lean b/Mathlib/Algebra/Pointwise/Stabilizer.lean index e1208f005f674..e28e090d6d7bb 100644 --- a/Mathlib/Algebra/Pointwise/Stabilizer.lean +++ b/Mathlib/Algebra/Pointwise/Stabilizer.lean @@ -47,8 +47,8 @@ lemma map_stabilizer_le (f : G →* H) (s : Set G) : @[to_additive (attr := simp)] lemma stabilizer_mul_self (s : Set G) : (stabilizer G s : Set G) * s = s := by ext - refine ⟨?_, fun h ↦ ⟨_, _, (stabilizer G s).one_mem, h, one_mul _⟩⟩ - rintro ⟨a, b, ha, hb, rfl⟩ + refine ⟨?_, fun h ↦ ⟨_, (stabilizer G s).one_mem, _, h, one_mul _⟩⟩ + rintro ⟨a, ha, b, hb, rfl⟩ rw [← mem_stabilizer_iff.1 ha] exact smul_mem_smul_set hb diff --git a/Mathlib/Analysis/Convex/Basic.lean b/Mathlib/Analysis/Convex/Basic.lean index 14702e7480347..8e51042295a55 100644 --- a/Mathlib/Analysis/Convex/Basic.lean +++ b/Mathlib/Analysis/Convex/Basic.lean @@ -77,7 +77,7 @@ theorem convex_iff_pointwise_add_subset : Convex 𝕜 s ↔ ∀ ⦃a b : 𝕜⦄, 0 ≤ a → 0 ≤ b → a + b = 1 → a • s + b • s ⊆ s := Iff.intro (by - rintro hA a b ha hb hab w ⟨au, bv, ⟨u, hu, rfl⟩, ⟨v, hv, rfl⟩, rfl⟩ + rintro hA a b ha hb hab w ⟨au, ⟨u, hu, rfl⟩, bv, ⟨v, hv, rfl⟩, rfl⟩ exact hA hu hv ha hb hab) fun h x hx y hy a b ha hb hab => (h ha hb hab) (Set.add_mem_add ⟨_, hx, rfl⟩ ⟨_, hy, rfl⟩) #align convex_iff_pointwise_add_subset convex_iff_pointwise_add_subset @@ -599,7 +599,7 @@ theorem Convex.exists_mem_add_smul_eq (h : Convex 𝕜 s) {x y : E} {p q : 𝕜} theorem Convex.add_smul (h_conv : Convex 𝕜 s) {p q : 𝕜} (hp : 0 ≤ p) (hq : 0 ≤ q) : (p + q) • s = p • s + q • s := (add_smul_subset _ _ _).antisymm <| by - rintro _ ⟨_, _, ⟨v₁, h₁, rfl⟩, ⟨v₂, h₂, rfl⟩, rfl⟩ + rintro _ ⟨_, ⟨v₁, h₁, rfl⟩, _, ⟨v₂, h₂, rfl⟩, rfl⟩ exact h_conv.exists_mem_add_smul_eq h₁ h₂ hp hq #align convex.add_smul Convex.add_smul diff --git a/Mathlib/Analysis/Convex/Cone/Basic.lean b/Mathlib/Analysis/Convex/Cone/Basic.lean index f2dd36c35b564..0cc64be8ab22c 100644 --- a/Mathlib/Analysis/Convex/Cone/Basic.lean +++ b/Mathlib/Analysis/Convex/Cone/Basic.lean @@ -443,19 +443,19 @@ theorem pointed_zero : (0 : ConvexCone 𝕜 E).Pointed := by rw [Pointed, mem_ze instance instAdd : Add (ConvexCone 𝕜 E) := ⟨fun K₁ K₂ => - { carrier := { z | ∃ x y : E, x ∈ K₁ ∧ y ∈ K₂ ∧ x + y = z } + { carrier := { z | ∃ x ∈ K₁, ∃ y ∈ K₂, x + y = z } smul_mem' := by - rintro c hc _ ⟨x, y, hx, hy, rfl⟩ + rintro c hc _ ⟨x, hx, y, hy, rfl⟩ rw [smul_add] - use c • x, c • y, K₁.smul_mem hc hx, K₂.smul_mem hc hy + use c • x, K₁.smul_mem hc hx, c • y, K₂.smul_mem hc hy add_mem' := by - rintro _ ⟨x₁, x₂, hx₁, hx₂, rfl⟩ y ⟨y₁, y₂, hy₁, hy₂, rfl⟩ - use x₁ + y₁, x₂ + y₂, K₁.add_mem hx₁ hy₁, K₂.add_mem hx₂ hy₂ + rintro _ ⟨x₁, hx₁, x₂, hx₂, rfl⟩ y ⟨y₁, hy₁, y₂, hy₂, rfl⟩ + use x₁ + y₁, K₁.add_mem hx₁ hy₁, x₂ + y₂, K₂.add_mem hx₂ hy₂ abel }⟩ @[simp] theorem mem_add {K₁ K₂ : ConvexCone 𝕜 E} {a : E} : - a ∈ K₁ + K₂ ↔ ∃ x y : E, x ∈ K₁ ∧ y ∈ K₂ ∧ x + y = a := + a ∈ K₁ + K₂ ↔ ∃ x ∈ K₁, ∃ y ∈ K₂, x + y = a := Iff.rfl #align convex_cone.mem_add ConvexCone.mem_add @@ -465,8 +465,8 @@ instance instAddZeroClass : AddZeroClass (ConvexCone 𝕜 E) where instance instAddCommSemigroup : AddCommSemigroup (ConvexCone 𝕜 E) where add := Add.add - add_assoc _ _ _ := SetLike.coe_injective <| Set.addCommSemigroup.add_assoc _ _ _ - add_comm _ _ := SetLike.coe_injective <| Set.addCommSemigroup.add_comm _ _ + add_assoc _ _ _ := SetLike.coe_injective <| add_assoc _ _ _ + add_comm _ _ := SetLike.coe_injective <| add_comm _ _ end Module diff --git a/Mathlib/Analysis/Convex/Side.lean b/Mathlib/Analysis/Convex/Side.lean index 02b4eb7b3b161..30d5510c6a15f 100644 --- a/Mathlib/Analysis/Convex/Side.lean +++ b/Mathlib/Analysis/Convex/Side.lean @@ -775,12 +775,12 @@ theorem setOf_wSameSide_eq_image2 {s : AffineSubspace R P} {x p : P} (hx : x ∉ · rw [vsub_eq_zero_iff_eq] at h exact False.elim (hx (h.symm ▸ hp)) · rw [vsub_eq_zero_iff_eq] at h - refine' ⟨0, p₂, le_refl _, hp₂, _⟩ + refine' ⟨0, le_rfl, p₂, hp₂, _⟩ simp [h] - · refine' ⟨r₁ / r₂, p₂, (div_pos hr₁ hr₂).le, hp₂, _⟩ + · refine' ⟨r₁ / r₂, (div_pos hr₁ hr₂).le, p₂, hp₂, _⟩ rw [div_eq_inv_mul, ← smul_smul, h, smul_smul, inv_mul_cancel hr₂.ne.symm, one_smul, vsub_vadd] - · rintro ⟨t, p', ht, hp', rfl⟩ + · rintro ⟨t, ht, p', hp', rfl⟩ exact wSameSide_smul_vsub_vadd_right x hp hp' ht #align affine_subspace.set_of_w_same_side_eq_image2 AffineSubspace.setOf_wSameSide_eq_image2 @@ -795,10 +795,10 @@ theorem setOf_sSameSide_eq_image2 {s : AffineSubspace R P} {x p : P} (hx : x ∉ exact False.elim (hx (h.symm ▸ hp)) · rw [vsub_eq_zero_iff_eq] at h exact False.elim (hy (h.symm ▸ hp₂)) - · refine' ⟨r₁ / r₂, p₂, div_pos hr₁ hr₂, hp₂, _⟩ + · refine' ⟨r₁ / r₂, div_pos hr₁ hr₂, p₂, hp₂, _⟩ rw [div_eq_inv_mul, ← smul_smul, h, smul_smul, inv_mul_cancel hr₂.ne.symm, one_smul, vsub_vadd] - · rintro ⟨t, p', ht, hp', rfl⟩ + · rintro ⟨t, ht, p', hp', rfl⟩ exact sSameSide_smul_vsub_vadd_right hx hp hp' ht #align affine_subspace.set_of_s_same_side_eq_image2 AffineSubspace.setOf_sSameSide_eq_image2 @@ -812,12 +812,12 @@ theorem setOf_wOppSide_eq_image2 {s : AffineSubspace R P} {x p : P} (hx : x ∉ · rw [vsub_eq_zero_iff_eq] at h exact False.elim (hx (h.symm ▸ hp)) · rw [vsub_eq_zero_iff_eq] at h - refine' ⟨0, p₂, le_refl _, hp₂, _⟩ + refine' ⟨0, le_rfl, p₂, hp₂, _⟩ simp [h] - · refine' ⟨-r₁ / r₂, p₂, (div_neg_of_neg_of_pos (Left.neg_neg_iff.2 hr₁) hr₂).le, hp₂, _⟩ + · refine' ⟨-r₁ / r₂, (div_neg_of_neg_of_pos (Left.neg_neg_iff.2 hr₁) hr₂).le, p₂, hp₂, _⟩ rw [div_eq_inv_mul, ← smul_smul, neg_smul, h, smul_neg, smul_smul, inv_mul_cancel hr₂.ne.symm, one_smul, neg_vsub_eq_vsub_rev, vsub_vadd] - · rintro ⟨t, p', ht, hp', rfl⟩ + · rintro ⟨t, ht, p', hp', rfl⟩ exact wOppSide_smul_vsub_vadd_right x hp hp' ht #align affine_subspace.set_of_w_opp_side_eq_image2 AffineSubspace.setOf_wOppSide_eq_image2 @@ -832,10 +832,10 @@ theorem setOf_sOppSide_eq_image2 {s : AffineSubspace R P} {x p : P} (hx : x ∉ exact False.elim (hx (h.symm ▸ hp)) · rw [vsub_eq_zero_iff_eq] at h exact False.elim (hy (h ▸ hp₂)) - · refine' ⟨-r₁ / r₂, p₂, div_neg_of_neg_of_pos (Left.neg_neg_iff.2 hr₁) hr₂, hp₂, _⟩ + · refine' ⟨-r₁ / r₂, div_neg_of_neg_of_pos (Left.neg_neg_iff.2 hr₁) hr₂, p₂, hp₂, _⟩ rw [div_eq_inv_mul, ← smul_smul, neg_smul, h, smul_neg, smul_smul, inv_mul_cancel hr₂.ne.symm, one_smul, neg_vsub_eq_vsub_rev, vsub_vadd] - · rintro ⟨t, p', ht, hp', rfl⟩ + · rintro ⟨t, ht, p', hp', rfl⟩ exact sOppSide_smul_vsub_vadd_right hx hp hp' ht #align affine_subspace.set_of_s_opp_side_eq_image2 AffineSubspace.setOf_sOppSide_eq_image2 diff --git a/Mathlib/Analysis/Convex/Star.lean b/Mathlib/Analysis/Convex/Star.lean index 7c49f4010d7ef..de0bad248947f 100644 --- a/Mathlib/Analysis/Convex/Star.lean +++ b/Mathlib/Analysis/Convex/Star.lean @@ -94,7 +94,7 @@ theorem starConvex_iff_pointwise_add_subset : refine' ⟨_, fun h y hy a b ha hb hab => h ha hb hab (add_mem_add (smul_mem_smul_set <| mem_singleton _) ⟨_, hy, rfl⟩)⟩ - rintro hA a b ha hb hab w ⟨au, bv, ⟨u, rfl : u = x, rfl⟩, ⟨v, hv, rfl⟩, rfl⟩ + rintro hA a b ha hb hab w ⟨au, ⟨u, rfl : u = x, rfl⟩, bv, ⟨v, hv, rfl⟩, rfl⟩ exact hA hv ha hb hab #align star_convex_iff_pointwise_add_subset starConvex_iff_pointwise_add_subset diff --git a/Mathlib/Analysis/Convex/Strict.lean b/Mathlib/Analysis/Convex/Strict.lean index 849894c7255be..9b05030853bbd 100644 --- a/Mathlib/Analysis/Convex/Strict.lean +++ b/Mathlib/Analysis/Convex/Strict.lean @@ -244,7 +244,7 @@ variable [ContinuousAdd E] {s t : Set E} theorem StrictConvex.add (hs : StrictConvex 𝕜 s) (ht : StrictConvex 𝕜 t) : StrictConvex 𝕜 (s + t) := by - rintro _ ⟨v, w, hv, hw, rfl⟩ _ ⟨x, y, hx, hy, rfl⟩ h a b ha hb hab + rintro _ ⟨v, hv, w, hw, rfl⟩ _ ⟨x, hx, y, hy, rfl⟩ h a b ha hb hab rw [smul_add, smul_add, add_add_add_comm] obtain rfl | hvx := eq_or_ne v x · refine' interior_mono (add_subset_add (singleton_subset_iff.2 hv) Subset.rfl) _ diff --git a/Mathlib/Analysis/Convolution.lean b/Mathlib/Analysis/Convolution.lean index 40a9654ab48bf..8dc0cece4f998 100644 --- a/Mathlib/Analysis/Convolution.lean +++ b/Mathlib/Analysis/Convolution.lean @@ -124,7 +124,7 @@ theorem convolution_integrand_bound_right_of_le_of_subset {C : ℝ} (hC : ∀ i, · apply_rules [L.le_of_op_norm₂_le_of_le, le_rfl] · have : x - t ∉ support g := by refine mt (fun hxt => hu ?_) ht - refine' ⟨_, _, Set.neg_mem_neg.mpr (subset_closure hxt), hx, _⟩ + refine' ⟨_, Set.neg_mem_neg.mpr (subset_closure hxt), _, hx, _⟩ simp only [neg_sub, sub_add_cancel] simp only [nmem_support.mp this, (L _).map_zero, norm_zero, le_rfl] #align convolution_integrand_bound_right_of_le_of_subset convolution_integrand_bound_right_of_le_of_subset @@ -560,7 +560,7 @@ theorem support_convolution_subset_swap : support (f ⋆[L, μ] g) ⊆ support g intro x h2x by_contra hx apply h2x - simp_rw [Set.mem_add, not_exists, not_and_or, nmem_support] at hx + simp_rw [Set.mem_add, ← exists_and_left, not_exists, not_and_or, nmem_support] at hx rw [convolution_def] convert integral_zero G F using 2 ext t @@ -641,7 +641,7 @@ theorem continuousOn_convolution_right_with_param {g : P → G → E'} {s : Set rintro ⟨p, x⟩ y ⟨hp, hx⟩ hy apply hgs p _ hp contrapose! hy - exact ⟨y - x, x, by simpa using hy, hx, by simp⟩ + exact ⟨y - x, by simpa using hy, x, hx, by simp⟩ apply ContinuousWithinAt.mono_of_mem (B (q₀, x₀) ⟨hq₀, mem_of_mem_nhds ht⟩) exact mem_nhdsWithin_prod_iff.2 ⟨s, self_mem_nhdsWithin, t, nhdsWithin_le_nhds ht, Subset.rfl⟩ #align continuous_on_convolution_right_with_param' continuousOn_convolution_right_with_param diff --git a/Mathlib/Analysis/Normed/Group/AddTorsor.lean b/Mathlib/Analysis/Normed/Group/AddTorsor.lean index 3ce4aa579472c..b2b7b816cf7cd 100644 --- a/Mathlib/Analysis/Normed/Group/AddTorsor.lean +++ b/Mathlib/Analysis/Normed/Group/AddTorsor.lean @@ -326,10 +326,10 @@ theorem IsClosed.vadd_right_of_isCompact {s : Set V} {t : Set P} (hs : IsClosed -- This result is still true for any `AddTorsor` where `-ᵥ` is continuous, -- but we don't yet have a nice way to state it. refine IsSeqClosed.isClosed (fun u p husv hup ↦ ?_) - choose! a v ha hv hav using husv + choose! a ha v hv hav using husv rcases ht.isSeqCompact hv with ⟨q, hqt, φ, φ_mono, hφq⟩ - refine ⟨p -ᵥ q, q, hs.mem_of_tendsto ((hup.comp φ_mono.tendsto_atTop).vsub hφq) - (eventually_of_forall fun n ↦ ?_), hqt, vsub_vadd _ _⟩ + refine ⟨p -ᵥ q, hs.mem_of_tendsto ((hup.comp φ_mono.tendsto_atTop).vsub hφq) + (eventually_of_forall fun n ↦ ?_), q, hqt, vsub_vadd _ _⟩ convert ha (φ n) using 1 exact (eq_vadd_iff_vsub_eq _ _ _).mp (hav (φ n)).symm diff --git a/Mathlib/Analysis/Normed/Group/Pointwise.lean b/Mathlib/Analysis/Normed/Group/Pointwise.lean index 652c3b14b6159..c8dc8408ed21a 100644 --- a/Mathlib/Analysis/Normed/Group/Pointwise.lean +++ b/Mathlib/Analysis/Normed/Group/Pointwise.lean @@ -31,7 +31,7 @@ theorem Bornology.IsBounded.mul (hs : IsBounded s) (ht : IsBounded t) : IsBounde obtain ⟨Rs, hRs⟩ : ∃ R, ∀ x ∈ s, ‖x‖ ≤ R := hs.exists_norm_le' obtain ⟨Rt, hRt⟩ : ∃ R, ∀ x ∈ t, ‖x‖ ≤ R := ht.exists_norm_le' refine' isBounded_iff_forall_norm_le'.2 ⟨Rs + Rt, _⟩ - rintro z ⟨x, y, hx, hy, rfl⟩ + rintro z ⟨x, hx, y, hy, rfl⟩ exact norm_mul_le_of_le (hRs x hx) (hRt y hy) #align metric.bounded.mul Bornology.IsBounded.mul #align metric.bounded.add Bornology.IsBounded.add diff --git a/Mathlib/Analysis/NormedSpace/lpSpace.lean b/Mathlib/Analysis/NormedSpace/lpSpace.lean index 4e63558c7b96c..cf39125f6e249 100644 --- a/Mathlib/Analysis/NormedSpace/lpSpace.lean +++ b/Mathlib/Analysis/NormedSpace/lpSpace.lean @@ -509,7 +509,7 @@ instance normedAddCommGroup [hp : Fact (1 ≤ p)] : NormedAddCommGroup (lp E p) refine' (lp.isLUB_norm (f + g)).2 _ rintro x ⟨i, rfl⟩ refine' le_trans _ (add_mem_upperBounds_add - (lp.isLUB_norm f).1 (lp.isLUB_norm g).1 ⟨_, _, ⟨i, rfl⟩, ⟨i, rfl⟩, rfl⟩) + (lp.isLUB_norm f).1 (lp.isLUB_norm g).1 ⟨_, ⟨i, rfl⟩, _, ⟨i, rfl⟩, rfl⟩) exact norm_add_le (f i) (g i) · have hp'' : 0 < p.toReal := zero_lt_one.trans_le hp' have hf₁ : ∀ i, 0 ≤ ‖f i‖ := fun i => norm_nonneg _ diff --git a/Mathlib/Analysis/Seminorm.lean b/Mathlib/Analysis/Seminorm.lean index acb6dba4a8452..7edf4981f3efe 100644 --- a/Mathlib/Analysis/Seminorm.lean +++ b/Mathlib/Analysis/Seminorm.lean @@ -792,14 +792,14 @@ theorem closedBall_antitone {p q : Seminorm 𝕜 E} (h : q ≤ p) : theorem ball_add_ball_subset (p : Seminorm 𝕜 E) (r₁ r₂ : ℝ) (x₁ x₂ : E) : p.ball (x₁ : E) r₁ + p.ball (x₂ : E) r₂ ⊆ p.ball (x₁ + x₂) (r₁ + r₂) := by - rintro x ⟨y₁, y₂, hy₁, hy₂, rfl⟩ + rintro x ⟨y₁, hy₁, y₂, hy₂, rfl⟩ rw [mem_ball, add_sub_add_comm] exact (map_add_le_add p _ _).trans_lt (add_lt_add hy₁ hy₂) #align seminorm.ball_add_ball_subset Seminorm.ball_add_ball_subset theorem closedBall_add_closedBall_subset (p : Seminorm 𝕜 E) (r₁ r₂ : ℝ) (x₁ x₂ : E) : p.closedBall (x₁ : E) r₁ + p.closedBall (x₂ : E) r₂ ⊆ p.closedBall (x₁ + x₂) (r₁ + r₂) := by - rintro x ⟨y₁, y₂, hy₁, hy₂, rfl⟩ + rintro x ⟨y₁, hy₁, y₂, hy₂, rfl⟩ rw [mem_closedBall, add_sub_add_comm] exact (map_add_le_add p _ _).trans (add_le_add hy₁ hy₂) #align seminorm.closed_ball_add_closed_ball_subset Seminorm.closedBall_add_closedBall_subset diff --git a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean index 77af26cadd1a4..3341bd2d1636e 100644 --- a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean +++ b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean @@ -47,7 +47,7 @@ theorem card_div_mul_le_card_div_mul_card_div (A B C : Finset α) : refine' card_mul_le_card_mul (fun b ac ↦ ac.1 * ac.2 = b) (fun x hx ↦ _) fun x _ ↦ card_le_one_iff.2 fun hu hv ↦ ((mem_bipartiteBelow _).1 hu).2.symm.trans ((mem_bipartiteBelow _).1 hv).2 - obtain ⟨a, c, ha, hc, rfl⟩ := mem_div.1 hx + obtain ⟨a, ha, c, hc, rfl⟩ := mem_div.1 hx refine' card_le_card_of_inj_on (fun b ↦ (a / b, b / c)) (fun b hb ↦ _) fun b₁ _ b₂ _ h ↦ _ · rw [mem_bipartiteAbove] exact ⟨mk_mem_product (div_mem_div ha hb) (div_mem_div hb hc), div_mul_div_cancel' _ _ _⟩ diff --git a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean index 33a24846b4381..f8da630fb788b 100644 --- a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean +++ b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean @@ -49,8 +49,8 @@ theorem exists_subset_mul_div (ht : t.Nonempty) : push_neg at H simp_rw [not_disjoint_iff, ← inv_smul_mem_iff] at H obtain ⟨b, hb, c, hc₁, hc₂⟩ := H - refine' mem_mul.2 ⟨b, a / b, hb, _, by simp⟩ - exact mem_div.2 ⟨_, _, hc₂, hc₁, by simp [div_eq_mul_inv a b, mul_comm]⟩ + refine' mem_mul.2 ⟨b, hb, a / b, _, by simp⟩ + exact mem_div.2 ⟨_, hc₂, _, hc₁, by simp [inv_mul_eq_div]⟩ #align finset.exists_subset_mul_div Finset.exists_subset_mul_div #align finset.exists_subset_add_sub Finset.exists_subset_add_sub diff --git a/Mathlib/Computability/DFA.lean b/Mathlib/Computability/DFA.lean index 142a0e5ab6d48..3a403e4b36002 100644 --- a/Mathlib/Computability/DFA.lean +++ b/Mathlib/Computability/DFA.lean @@ -153,13 +153,13 @@ theorem pumping_lemma [Fintype σ] {x : List α} (hx : x ∈ M.accepts) ∃ a b c, x = a ++ b ++ c ∧ a.length + b.length ≤ Fintype.card σ ∧ b ≠ [] ∧ {a} * {b}∗ * {c} ≤ M.accepts := by - obtain ⟨_, a, b, c, hx, hlen, hnil, rfl, hb, hc⟩ := M.evalFrom_split hlen rfl + obtain ⟨_, a, b, c, hx, hlen, hnil, rfl, hb, hc⟩ := M.evalFrom_split (s := M.start) hlen rfl use a, b, c, hx, hlen, hnil intro y hy rw [Language.mem_mul] at hy - rcases hy with ⟨ab, c', hab, hc', rfl⟩ + rcases hy with ⟨ab, hab, c', hc', rfl⟩ rw [Language.mem_mul] at hab - rcases hab with ⟨a', b', ha', hb', rfl⟩ + rcases hab with ⟨a', ha', b', hb', rfl⟩ rw [Set.mem_singleton_iff] at ha' hc' substs ha' hc' have h := M.evalFrom_of_pow hb hb' diff --git a/Mathlib/Computability/Language.lean b/Mathlib/Computability/Language.lean index 41378c7724bf4..af50e1601fa07 100644 --- a/Mathlib/Computability/Language.lean +++ b/Mathlib/Computability/Language.lean @@ -110,7 +110,7 @@ theorem mem_add (l m : Language α) (x : List α) : x ∈ l + m ↔ x ∈ l ∨ Iff.rfl #align language.mem_add Language.mem_add -theorem mem_mul : x ∈ l * m ↔ ∃ a b, a ∈ l ∧ b ∈ m ∧ a ++ b = x := +theorem mem_mul : x ∈ l * m ↔ ∃ a ∈ l, ∃ b ∈ m, a ++ b = x := mem_image2 #align language.mem_mul Language.mem_mul @@ -240,11 +240,11 @@ theorem mem_pow {l : Language α} {x : List α} {n : ℕ} : rfl · simp only [pow_succ, mem_mul, ihn] constructor - · rintro ⟨a, b, ha, ⟨S, rfl, rfl, hS⟩, rfl⟩ + · rintro ⟨a, ha, b, ⟨S, rfl, rfl, hS⟩, rfl⟩ exact ⟨a :: S, rfl, rfl, forall_mem_cons.2 ⟨ha, hS⟩⟩ · rintro ⟨_ | ⟨a, S⟩, rfl, hn, hS⟩ <;> cases hn rw [forall_mem_cons] at hS - exact ⟨a, _, hS.1, ⟨S, rfl, rfl, hS.2⟩, rfl⟩ + exact ⟨a, hS.1, _, ⟨S, rfl, rfl, hS.2⟩, rfl⟩ #align language.mem_pow Language.mem_pow theorem kstar_eq_iSup_pow (l : Language α) : l∗ = ⨆ i : ℕ, l ^ i := by diff --git a/Mathlib/Data/Finset/MulAntidiagonal.lean b/Mathlib/Data/Finset/MulAntidiagonal.lean index 36b685a3d6b28..1abc6eea244d8 100644 --- a/Mathlib/Data/Finset/MulAntidiagonal.lean +++ b/Mathlib/Data/Finset/MulAntidiagonal.lean @@ -39,9 +39,9 @@ theorem IsWf.mul (hs : s.IsWf) (ht : t.IsWf) : IsWf (s * t) := @[to_additive] theorem IsWf.min_mul (hs : s.IsWf) (ht : t.IsWf) (hsn : s.Nonempty) (htn : t.Nonempty) : (hs.mul ht).min (hsn.mul htn) = hs.min hsn * ht.min htn := by - refine' le_antisymm (IsWf.min_le _ _ (mem_mul.2 ⟨_, _, hs.min_mem _, ht.min_mem _, rfl⟩)) _ + refine' le_antisymm (IsWf.min_le _ _ (mem_mul.2 ⟨_, hs.min_mem _, _, ht.min_mem _, rfl⟩)) _ rw [IsWf.le_min_iff] - rintro _ ⟨x, y, hx, hy, rfl⟩ + rintro _ ⟨x, hx, y, hy, rfl⟩ exact mul_le_mul' (hs.min_le _ hx) (ht.min_le _ hy) #align set.is_wf.min_mul Set.IsWf.min_mul #align set.is_wf.min_add Set.IsWf.min_add @@ -101,7 +101,7 @@ theorem swap_mem_mulAntidiagonal : theorem support_mulAntidiagonal_subset_mul : { a | (mulAntidiagonal hs ht a).Nonempty } ⊆ s * t := fun a ⟨b, hb⟩ => by rw [mem_mulAntidiagonal] at hb - exact ⟨b.1, b.2, hb⟩ + exact ⟨b.1, hb.1, b.2, hb.2⟩ #align finset.support_mul_antidiagonal_subset_mul Finset.support_mulAntidiagonal_subset_mul #align finset.support_add_antidiagonal_subset_add Finset.support_addAntidiagonal_subset_add diff --git a/Mathlib/Data/Finset/NAry.lean b/Mathlib/Data/Finset/NAry.lean index b6af4b1c54a4b..9637e38b97341 100644 --- a/Mathlib/Data/Finset/NAry.lean +++ b/Mathlib/Data/Finset/NAry.lean @@ -41,7 +41,7 @@ def image₂ (f : α → β → γ) (s : Finset α) (t : Finset β) : Finset γ #align finset.image₂ Finset.image₂ @[simp] -theorem mem_image₂ : c ∈ image₂ f s t ↔ ∃ a b, a ∈ s ∧ b ∈ t ∧ f a b = c := by +theorem mem_image₂ : c ∈ image₂ f s t ↔ ∃ a ∈ s, ∃ b ∈ t, f a b = c := by simp [image₂, and_assoc] #align finset.mem_image₂ Finset.mem_image₂ @@ -68,7 +68,7 @@ theorem card_image₂ (hf : Injective2 f) (s : Finset α) (t : Finset β) : #align finset.card_image₂ Finset.card_image₂ theorem mem_image₂_of_mem (ha : a ∈ s) (hb : b ∈ t) : f a b ∈ image₂ f s t := - mem_image₂.2 ⟨a, b, ha, hb, rfl⟩ + mem_image₂.2 ⟨a, ha, b, hb, rfl⟩ #align finset.mem_image₂_of_mem Finset.mem_image₂_of_mem theorem mem_image₂_iff (hf : Injective2 f) : f a b ∈ image₂ f s t ↔ a ∈ s ∧ b ∈ t := by diff --git a/Mathlib/Data/Finset/NatDivisors.lean b/Mathlib/Data/Finset/NatDivisors.lean index 73c5802787941..fbd3060800350 100644 --- a/Mathlib/Data/Finset/NatDivisors.lean +++ b/Mathlib/Data/Finset/NatDivisors.lean @@ -21,7 +21,7 @@ open scoped Pointwise BigOperators factors. -/ lemma Nat.divisors_mul (m n : ℕ) : divisors (m * n) = divisors m * divisors n := by ext k - simp_rw [mem_mul, mem_divisors, dvd_mul, mul_ne_zero_iff, ← exists_and_right] + simp_rw [mem_mul, mem_divisors, dvd_mul, mul_ne_zero_iff, ← exists_and_left, ← exists_and_right] simp only [and_assoc, and_comm, and_left_comm] /-- `Nat.divisors` as a `MonoidHom`. -/ diff --git a/Mathlib/Data/Finset/Pointwise.lean b/Mathlib/Data/Finset/Pointwise.lean index 5113284439635..7c3ca6d6c5bba 100644 --- a/Mathlib/Data/Finset/Pointwise.lean +++ b/Mathlib/Data/Finset/Pointwise.lean @@ -328,8 +328,7 @@ theorem image_mul_product : ((s ×ˢ t).image fun x : α × α => x.fst * x.snd) #align finset.image_add_product Finset.image_add_product @[to_additive] -theorem mem_mul {x : α} : x ∈ s * t ↔ ∃ y z, y ∈ s ∧ z ∈ t ∧ y * z = x := - mem_image₂ +theorem mem_mul {x : α} : x ∈ s * t ↔ ∃ y ∈ s, ∃ z ∈ t, y * z = x := mem_image₂ #align finset.mem_mul Finset.mem_mul #align finset.mem_add Finset.mem_add @@ -556,7 +555,7 @@ theorem image_div_product : ((s ×ˢ t).image fun x : α × α => x.fst / x.snd) #align finset.add_image_prod Finset.image_sub_product @[to_additive] -theorem mem_div : a ∈ s / t ↔ ∃ b c, b ∈ s ∧ c ∈ t ∧ b / c = a := +theorem mem_div : a ∈ s / t ↔ ∃ b ∈ s, ∃ c ∈ t, b / c = a := mem_image₂ #align finset.mem_div Finset.mem_div #align finset.mem_sub Finset.mem_sub @@ -800,13 +799,13 @@ scoped[Pointwise] attribute [instance] Finset.semigroup Finset.addSemigroup Fins @[to_additive] theorem subset_mul_left (s : Finset α) {t : Finset α} (ht : (1 : α) ∈ t) : s ⊆ s * t := fun a ha => - mem_mul.2 ⟨a, 1, ha, ht, mul_one _⟩ + mem_mul.2 ⟨a, ha, 1, ht, mul_one _⟩ #align finset.subset_mul_left Finset.subset_mul_left #align finset.subset_add_left Finset.subset_add_left @[to_additive] theorem subset_mul_right {s : Finset α} (t : Finset α) (hs : (1 : α) ∈ s) : t ⊆ s * t := fun a ha => - mem_mul.2 ⟨1, a, hs, ha, one_mul _⟩ + mem_mul.2 ⟨1, hs, a, ha, one_mul _⟩ #align finset.subset_mul_right Finset.subset_mul_right #align finset.subset_add_right Finset.subset_add_right @@ -940,13 +939,13 @@ theorem empty_pow (hn : n ≠ 0) : (∅ : Finset α) ^ n = ∅ := by @[to_additive] theorem mul_univ_of_one_mem [Fintype α] (hs : (1 : α) ∈ s) : s * univ = univ := - eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, _, hs, mem_univ _, one_mul _⟩ + eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, hs, _, mem_univ _, one_mul _⟩ #align finset.mul_univ_of_one_mem Finset.mul_univ_of_one_mem #align finset.add_univ_of_zero_mem Finset.add_univ_of_zero_mem @[to_additive] theorem univ_mul_of_one_mem [Fintype α] (ht : (1 : α) ∈ t) : univ * t = univ := - eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, _, mem_univ _, ht, mul_one _⟩ + eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, mem_univ _, _, ht, mul_one _⟩ #align finset.univ_mul_of_one_mem Finset.univ_mul_of_one_mem #align finset.univ_add_of_zero_mem Finset.univ_add_of_zero_mem @@ -1136,7 +1135,7 @@ theorem not_one_mem_div_iff : (1 : α) ∉ s / t ↔ Disjoint s t := @[to_additive] theorem Nonempty.one_mem_div (h : s.Nonempty) : (1 : α) ∈ s / s := let ⟨a, ha⟩ := h - mem_div.2 ⟨a, a, ha, ha, div_self' _⟩ + mem_div.2 ⟨a, ha, a, ha, div_self' _⟩ #align finset.nonempty.one_mem_div Finset.Nonempty.one_mem_div #align finset.nonempty.zero_mem_sub Finset.Nonempty.zero_mem_sub @@ -1287,7 +1286,7 @@ theorem image_smul_product : ((s ×ˢ t).image fun x : α × β => x.fst • x.s #align finset.image_vadd_product Finset.image_vadd_product @[to_additive] -theorem mem_smul {x : β} : x ∈ s • t ↔ ∃ y z, y ∈ s ∧ z ∈ t ∧ y • z = x := +theorem mem_smul {x : β} : x ∈ s • t ↔ ∃ y ∈ s, ∃ z ∈ t, y • z = x := mem_image₂ #align finset.mem_smul Finset.mem_smul #align finset.mem_vadd Finset.mem_vadd @@ -1461,7 +1460,7 @@ theorem image_vsub_product : image₂ (· -ᵥ ·) s t = s -ᵥ t := rfl #align finset.image_vsub_product Finset.image_vsub_product -theorem mem_vsub : a ∈ s -ᵥ t ↔ ∃ b c, b ∈ s ∧ c ∈ t ∧ b -ᵥ c = a := +theorem mem_vsub : a ∈ s -ᵥ t ↔ ∃ b ∈ s, ∃ c ∈ t, b -ᵥ c = a := mem_image₂ #align finset.mem_vsub Finset.mem_vsub diff --git a/Mathlib/Data/Set/Basic.lean b/Mathlib/Data/Set/Basic.lean index 4a54da2144a88..678c9abb7a4f3 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -393,8 +393,9 @@ theorem not_subset : ¬s ⊆ t ↔ ∃ a ∈ s, a ∉ t := by simp only [subset_def, not_forall, exists_prop] #align set.not_subset Set.not_subset -/-! ### Definition of strict subsets `s ⊂ t` and basic properties. -/ +lemma eq_of_forall_subset_iff (h : ∀ u, s ⊆ u ↔ t ⊆ u) : s = t := eq_of_forall_ge_iff h +/-! ### Definition of strict subsets `s ⊂ t` and basic properties. -/ protected theorem eq_or_ssubset_of_subset (h : s ⊆ t) : s = t ∨ s ⊂ t := eq_or_lt_of_le h diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index 68cc9bac00df1..f034e42438bae 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -2081,8 +2081,7 @@ section Seq /-- Given a set `s` of functions `α → β` and `t : Set α`, `seq s t` is the union of `f '' t` over all `f ∈ s`. -/ -def seq (s : Set (α → β)) (t : Set α) : Set β := - { b | ∃ f ∈ s, ∃ a ∈ t, (f : α → β) a = b } +def seq (s : Set (α → β)) (t : Set α) : Set β := image2 (fun f ↦ f) s t #align set.seq Set.seq @[simp] @@ -2091,29 +2090,28 @@ theorem mem_seq_iff {s : Set (α → β)} {t : Set α} {b : β} : Iff.rfl #align set.mem_seq_iff Set.mem_seq_iff -lemma seq_eq_image2 (s : Set (α → β)) (t : Set α) : seq s t = image2 (fun f a ↦ f a) s t := by - ext; simp +lemma seq_eq_image2 (s : Set (α → β)) (t : Set α) : seq s t = image2 (fun f a ↦ f a) s t := rfl theorem seq_def {s : Set (α → β)} {t : Set α} : seq s t = ⋃ f ∈ s, f '' t := by rw [seq_eq_image2, iUnion_image_left] #align set.seq_def Set.seq_def theorem seq_subset {s : Set (α → β)} {t : Set α} {u : Set β} : - seq s t ⊆ u ↔ ∀ f ∈ s, ∀ a ∈ t, (f : α → β) a ∈ u := by - rw [seq_eq_image2, image2_subset_iff] + seq s t ⊆ u ↔ ∀ f ∈ s, ∀ a ∈ t, (f : α → β) a ∈ u := + image2_subset_iff #align set.seq_subset Set.seq_subset @[gcongr] theorem seq_mono {s₀ s₁ : Set (α → β)} {t₀ t₁ : Set α} (hs : s₀ ⊆ s₁) (ht : t₀ ⊆ t₁) : - seq s₀ t₀ ⊆ seq s₁ t₁ := fun _ ⟨f, hf, a, ha, eq⟩ => ⟨f, hs hf, a, ht ha, eq⟩ + seq s₀ t₀ ⊆ seq s₁ t₁ := image2_subset hs ht #align set.seq_mono Set.seq_mono -theorem singleton_seq {f : α → β} {t : Set α} : Set.seq ({f} : Set (α → β)) t = f '' t := by - rw [seq_eq_image2, image2_singleton_left] +theorem singleton_seq {f : α → β} {t : Set α} : Set.seq ({f} : Set (α → β)) t = f '' t := + image2_singleton_left #align set.singleton_seq Set.singleton_seq -theorem seq_singleton {s : Set (α → β)} {a : α} : Set.seq s {a} = (fun f : α → β => f a) '' s := by - rw [seq_eq_image2, image2_singleton_right] +theorem seq_singleton {s : Set (α → β)} {a : α} : Set.seq s {a} = (fun f : α → β => f a) '' s := + image2_singleton_right #align set.seq_singleton Set.seq_singleton theorem seq_seq {s : Set (β → γ)} {t : Set (α → β)} {u : Set α} : @@ -2124,7 +2122,7 @@ theorem seq_seq {s : Set (β → γ)} {t : Set (α → β)} {u : Set α} : theorem image_seq {f : β → γ} {s : Set (α → β)} {t : Set α} : f '' seq s t = seq ((f ∘ ·) '' s) t := by - rw [← singleton_seq, ← singleton_seq, seq_seq, image_singleton] + simp only [seq, image_image2, image2_image_left, comp_apply] #align set.image_seq Set.image_seq theorem prod_eq_seq {s : Set α} {t : Set β} : s ×ˢ t = (Prod.mk '' s).seq t := by diff --git a/Mathlib/Data/Set/NAry.lean b/Mathlib/Data/Set/NAry.lean index 033d089ee0410..78db75413ff78 100644 --- a/Mathlib/Data/Set/NAry.lean +++ b/Mathlib/Data/Set/NAry.lean @@ -29,28 +29,28 @@ variable {s s' : Set α} {t t' : Set β} {u u' : Set γ} {v : Set δ} {a a' : α /-- The image of a binary function `f : α → β → γ` as a function `Set α → Set β → Set γ`. Mathematically this should be thought of as the image of the corresponding function `α × β → γ`.-/ def image2 (f : α → β → γ) (s : Set α) (t : Set β) : Set γ := - { c | ∃ a b, a ∈ s ∧ b ∈ t ∧ f a b = c } + { c | ∃ a ∈ s, ∃ b ∈ t, f a b = c } #align set.image2 Set.image2 @[simp] -theorem mem_image2 : c ∈ image2 f s t ↔ ∃ a b, a ∈ s ∧ b ∈ t ∧ f a b = c := +theorem mem_image2 : c ∈ image2 f s t ↔ ∃ a ∈ s, ∃ b ∈ t, f a b = c := Iff.rfl #align set.mem_image2 Set.mem_image2 theorem mem_image2_of_mem (ha : a ∈ s) (hb : b ∈ t) : f a b ∈ image2 f s t := - ⟨a, b, ha, hb, rfl⟩ + ⟨a, ha, b, hb, rfl⟩ #align set.mem_image2_of_mem Set.mem_image2_of_mem theorem mem_image2_iff (hf : Injective2 f) : f a b ∈ image2 f s t ↔ a ∈ s ∧ b ∈ t := ⟨by - rintro ⟨a', b', ha', hb', h⟩ + rintro ⟨a', ha', b', hb', h⟩ rcases hf h with ⟨rfl, rfl⟩ exact ⟨ha', hb'⟩, fun ⟨ha, hb⟩ => mem_image2_of_mem ha hb⟩ #align set.mem_image2_iff Set.mem_image2_iff /-- image2 is monotone with respect to `⊆`. -/ theorem image2_subset (hs : s ⊆ s') (ht : t ⊆ t') : image2 f s t ⊆ image2 f s' t' := by - rintro _ ⟨a, b, ha, hb, rfl⟩ + rintro _ ⟨a, ha, b, hb, rfl⟩ exact mem_image2_of_mem (hs ha) (ht hb) #align set.image2_subset Set.image2_subset @@ -72,7 +72,7 @@ theorem image_subset_image2_right (ha : a ∈ s) : f a '' t ⊆ image2 f s t := theorem forall_image2_iff {p : γ → Prop} : (∀ z ∈ image2 f s t, p z) ↔ ∀ x ∈ s, ∀ y ∈ t, p (f x y) := - ⟨fun h x hx y hy => h _ ⟨x, y, hx, hy, rfl⟩, fun h _ ⟨x, y, hx, hy, hz⟩ => hz ▸ h x hx y hy⟩ + ⟨fun h x hx y hy => h _ ⟨x, hx, y, hy, rfl⟩, fun h _ ⟨x, hx, y, hy, hz⟩ => hz ▸ h x hx y hy⟩ #align set.forall_image2_iff Set.forall_image2_iff @[simp] @@ -92,16 +92,14 @@ variable (f) -- Porting note: Removing `simp` - LHS does not simplify lemma image_prod : (fun x : α × β ↦ f x.1 x.2) '' s ×ˢ t = image2 f s t := - ext $ fun a ↦ - ⟨ by rintro ⟨_, _, rfl⟩; exact ⟨_, _, (mem_prod.1 ‹_›).1, (mem_prod.1 ‹_›).2, rfl⟩, - by rintro ⟨_, _, _, _, rfl⟩; exact ⟨(_, _), ⟨‹_›, ‹_›⟩, rfl⟩⟩ + ext fun _ ↦ by simp [and_assoc] #align set.image_prod Set.image_prod @[simp] lemma image_uncurry_prod (s : Set α) (t : Set β) : uncurry f '' s ×ˢ t = image2 f s t := image_prod _ #align set.image_uncurry_prod Set.image_uncurry_prod -@[simp] lemma image2_mk_eq_prod : image2 Prod.mk s t = s ×ˢ t := ext $ by simp +@[simp] lemma image2_mk_eq_prod : image2 Prod.mk s t = s ×ˢ t := ext <| by simp #align set.image2_mk_eq_prod Set.image2_mk_eq_prod -- Porting note: Removing `simp` - LHS does not simplify @@ -112,7 +110,7 @@ lemma image2_curry (f : α × β → γ) (s : Set α) (t : Set β) : theorem image2_swap (s : Set α) (t : Set β) : image2 f s t = image2 (fun a b => f b a) t s := by ext - constructor <;> rintro ⟨a, b, ha, hb, rfl⟩ <;> exact ⟨b, a, hb, ha, rfl⟩ + constructor <;> rintro ⟨a, ha, b, hb, rfl⟩ <;> exact ⟨b, hb, a, ha, rfl⟩ #align set.image2_swap Set.image2_swap variable {f} @@ -151,7 +149,7 @@ theorem Nonempty.image2 : s.Nonempty → t.Nonempty → (image2 f s t).Nonempty @[simp] theorem image2_nonempty_iff : (image2 f s t).Nonempty ↔ s.Nonempty ∧ t.Nonempty := - ⟨fun ⟨_, a, b, ha, hb, _⟩ => ⟨⟨a, ha⟩, b, hb⟩, fun h => h.1.image2 h.2⟩ + ⟨fun ⟨_, a, ha, b, hb, _⟩ => ⟨⟨a, ha⟩, b, hb⟩, fun h => h.1.image2 h.2⟩ #align set.image2_nonempty_iff Set.image2_nonempty_iff theorem Nonempty.of_image2_left (h : (Set.image2 f s t).Nonempty) : s.Nonempty := @@ -207,7 +205,7 @@ theorem image2_insert_right : image2 f s (insert b t) = (fun a => f a b) '' s @[congr] theorem image2_congr (h : ∀ a ∈ s, ∀ b ∈ t, f a b = f' a b) : image2 f s t = image2 f' s t := by ext - constructor <;> rintro ⟨a, b, ha, hb, rfl⟩ <;> refine' ⟨a, b, ha, hb, by rw [h a ha b hb]⟩ + constructor <;> rintro ⟨a, ha, b, hb, rfl⟩ <;> exact ⟨a, ha, b, hb, by rw [h a ha b hb]⟩ #align set.image2_congr Set.image2_congr /-- A common special case of `image2_congr` -/ @@ -254,10 +252,8 @@ lemma image2_range (f : α' → β' → γ) (g : α → α') (h : β → β') : theorem image2_assoc {f : δ → γ → ε} {g : α → β → δ} {f' : α → ε' → ε} {g' : β → γ → ε'} (h_assoc : ∀ a b c, f (g a b) c = f' a (g' b c)) : - image2 f (image2 g s t) u = image2 f' s (image2 g' t u) := by - rw [← image_prod g, ← image_prod g', image2_image_left, image2_image_right] - ext - simp only [mem_image2, Prod.exists, h_assoc, prod_mk_mem_set_prod_eq, and_assoc] + image2 f (image2 g s t) u = image2 f' s (image2 g' t u) := + eq_of_forall_subset_iff fun _ ↦ by simp only [image2_subset_iff, forall_image2_iff, h_assoc] #align set.image2_assoc Set.image2_assoc theorem image2_comm {g : β → α → γ} (h_comm : ∀ a b, f a b = g b a) : image2 f s t = image2 g t s := @@ -283,10 +279,10 @@ theorem image2_image2_image2_comm {f : ε → ζ → ν} {g : α → β → ε} (h_comm : ∀ a b c d, f (g a b) (h c d) = f' (g' a c) (h' b d)) : image2 f (image2 g s t) (image2 h u v) = image2 f' (image2 g' s u) (image2 h' t v) := by ext; constructor - · rintro ⟨_, _, ⟨a, b, ha, hb, rfl⟩, ⟨c, d, hc, hd, rfl⟩, rfl⟩ - exact ⟨_, _, ⟨a, c, ha, hc, rfl⟩, ⟨b, d, hb, hd, rfl⟩, (h_comm _ _ _ _).symm⟩ - · rintro ⟨_, _, ⟨a, c, ha, hc, rfl⟩, ⟨b, d, hb, hd, rfl⟩, rfl⟩ - exact ⟨_, _, ⟨a, b, ha, hb, rfl⟩, ⟨c, d, hc, hd, rfl⟩, h_comm _ _ _ _⟩ + · rintro ⟨_, ⟨a, ha, b, hb, rfl⟩, _, ⟨c, hc, d, hd, rfl⟩, rfl⟩ + exact ⟨_, ⟨a, ha, c, hc, rfl⟩, _, ⟨b, hb, d, hd, rfl⟩, (h_comm _ _ _ _).symm⟩ + · rintro ⟨_, ⟨a, ha, c, hc, rfl⟩, _, ⟨b, hb, d, hd, rfl⟩, rfl⟩ + exact ⟨_, ⟨a, ha, b, hb, rfl⟩, _, ⟨c, hc, d, hd, rfl⟩, h_comm _ _ _ _⟩ #align set.image2_image2_image2_comm Set.image2_image2_image2_comm theorem image_image2_distrib {g : γ → δ} {f' : α' → β' → δ} {g₁ : α → α'} {g₂ : β → β'} @@ -327,7 +323,7 @@ theorem image_image2_right_comm {f : α → β' → γ} {g : β → β'} {f' : theorem image2_distrib_subset_left {f : α → δ → ε} {g : β → γ → δ} {f₁ : α → β → β'} {f₂ : α → γ → γ'} {g' : β' → γ' → ε} (h_distrib : ∀ a b c, f a (g b c) = g' (f₁ a b) (f₂ a c)) : image2 f s (image2 g t u) ⊆ image2 g' (image2 f₁ s t) (image2 f₂ s u) := by - rintro _ ⟨a, _, ha, ⟨b, c, hb, hc, rfl⟩, rfl⟩ + rintro _ ⟨a, ha, _, ⟨b, hb, c, hc, rfl⟩, rfl⟩ rw [h_distrib] exact mem_image2_of_mem (mem_image2_of_mem ha hb) (mem_image2_of_mem ha hc) #align set.image2_distrib_subset_left Set.image2_distrib_subset_left @@ -336,7 +332,7 @@ theorem image2_distrib_subset_left {f : α → δ → ε} {g : β → γ → δ} theorem image2_distrib_subset_right {f : δ → γ → ε} {g : α → β → δ} {f₁ : α → γ → α'} {f₂ : β → γ → β'} {g' : α' → β' → ε} (h_distrib : ∀ a b c, f (g a b) c = g' (f₁ a c) (f₂ b c)) : image2 f (image2 g s t) u ⊆ image2 g' (image2 f₁ s u) (image2 f₂ t u) := by - rintro _ ⟨_, c, ⟨a, b, ha, hb, rfl⟩, hc, rfl⟩ + rintro _ ⟨_, ⟨a, ha, b, hb, rfl⟩, c, hc, rfl⟩ rw [h_distrib] exact mem_image2_of_mem (mem_image2_of_mem ha hc) (mem_image2_of_mem hb hc) #align set.image2_distrib_subset_right Set.image2_distrib_subset_right diff --git a/Mathlib/Data/Set/Pointwise/Basic.lean b/Mathlib/Data/Set/Pointwise/Basic.lean index a690e8cbf3791..5a7d07805a9b8 100644 --- a/Mathlib/Data/Set/Pointwise/Basic.lean +++ b/Mathlib/Data/Set/Pointwise/Basic.lean @@ -333,7 +333,7 @@ theorem image2_mul : image2 (· * ·) s t = s * t := #align set.image2_add Set.image2_add @[to_additive] -theorem mem_mul : a ∈ s * t ↔ ∃ x y, x ∈ s ∧ y ∈ t ∧ x * y = a := +theorem mem_mul : a ∈ s * t ↔ ∃ x ∈ s, ∃ y ∈ t, x * y = a := Iff.rfl #align set.mem_mul Set.mem_mul #align set.mem_add Set.mem_add @@ -599,7 +599,7 @@ theorem image2_div : image2 Div.div s t = s / t := #align set.image2_sub Set.image2_sub @[to_additive] -theorem mem_div : a ∈ s / t ↔ ∃ x y, x ∈ s ∧ y ∈ t ∧ x / y = a := +theorem mem_div : a ∈ s / t ↔ ∃ x ∈ s, ∃ y ∈ t, x / y = a := Iff.rfl #align set.mem_div Set.mem_div #align set.mem_sub Set.mem_sub @@ -893,13 +893,13 @@ scoped[Pointwise] @[to_additive] theorem subset_mul_left (s : Set α) {t : Set α} (ht : (1 : α) ∈ t) : s ⊆ s * t := fun x hx => - ⟨x, 1, hx, ht, mul_one _⟩ + ⟨x, hx, 1, ht, mul_one _⟩ #align set.subset_mul_left Set.subset_mul_left #align set.subset_add_left Set.subset_add_left @[to_additive] theorem subset_mul_right {s : Set α} (t : Set α) (hs : (1 : α) ∈ s) : t ⊆ s * t := fun x hx => - ⟨1, x, hs, hx, one_mul _⟩ + ⟨1, hs, x, hx, one_mul _⟩ #align set.subset_mul_right Set.subset_mul_right #align set.subset_add_right Set.subset_add_right @@ -979,13 +979,13 @@ theorem empty_pow {n : ℕ} (hn : n ≠ 0) : (∅ : Set α) ^ n = ∅ := by @[to_additive] theorem mul_univ_of_one_mem (hs : (1 : α) ∈ s) : s * univ = univ := - eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, _, hs, mem_univ _, one_mul _⟩ + eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, hs, _, mem_univ _, one_mul _⟩ #align set.mul_univ_of_one_mem Set.mul_univ_of_one_mem #align set.add_univ_of_zero_mem Set.add_univ_of_zero_mem @[to_additive] theorem univ_mul_of_one_mem (ht : (1 : α) ∈ t) : univ * t = univ := - eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, _, mem_univ _, ht, mul_one _⟩ + eq_univ_iff_forall.2 fun _ => mem_mul.2 ⟨_, mem_univ _, _, ht, mul_one _⟩ #align set.univ_mul_of_one_mem Set.univ_mul_of_one_mem #align set.univ_add_of_zero_mem Set.univ_add_of_zero_mem @@ -1180,7 +1180,7 @@ attribute [to_additive] Disjoint.one_not_mem_div_set @[to_additive] theorem Nonempty.one_mem_div (h : s.Nonempty) : (1 : α) ∈ s / s := let ⟨a, ha⟩ := h - mem_div.2 ⟨a, a, ha, ha, div_self' _⟩ + mem_div.2 ⟨a, ha, a, ha, div_self' _⟩ #align set.nonempty.one_mem_div Set.Nonempty.one_mem_div #align set.nonempty.zero_mem_sub Set.Nonempty.zero_mem_sub @@ -1255,14 +1255,14 @@ theorem preimage_mul_right_one' : (· * b⁻¹) ⁻¹' 1 = {b} := by simp @[to_additive (attr := simp)] theorem mul_univ (hs : s.Nonempty) : s * (univ : Set α) = univ := let ⟨a, ha⟩ := hs - eq_univ_of_forall fun b => ⟨a, a⁻¹ * b, ha, trivial, mul_inv_cancel_left _ _⟩ + eq_univ_of_forall fun b => ⟨a, ha, a⁻¹ * b, trivial, mul_inv_cancel_left _ _⟩ #align set.mul_univ Set.mul_univ #align set.add_univ Set.add_univ @[to_additive (attr := simp)] theorem univ_mul (ht : t.Nonempty) : (univ : Set α) * t = univ := let ⟨a, ha⟩ := ht - eq_univ_of_forall fun b => ⟨b * a⁻¹, a, trivial, ha, inv_mul_cancel_right _ _⟩ + eq_univ_of_forall fun b => ⟨b * a⁻¹, trivial, a, ha, inv_mul_cancel_right _ _⟩ #align set.univ_mul Set.univ_mul #align set.univ_add Set.univ_add @@ -1300,7 +1300,7 @@ theorem image_mul : m '' (s * t) = m '' s * m '' t := @[to_additive] lemma mul_subset_range {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) : s * t ⊆ range m := by - rintro _ ⟨a, b, ha, hb, rfl⟩; + rintro _ ⟨a, ha, b, hb, rfl⟩; obtain ⟨a, rfl⟩ := hs ha obtain ⟨b, rfl⟩ := ht hb exact ⟨a * b, map_mul _ _ _⟩ @@ -1308,7 +1308,7 @@ lemma mul_subset_range {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) @[to_additive] theorem preimage_mul_preimage_subset {s t : Set β} : m ⁻¹' s * m ⁻¹' t ⊆ m ⁻¹' (s * t) := by rintro _ ⟨_, _, _, _, rfl⟩ - exact ⟨_, _, ‹_›, ‹_›, (map_mul m _ _).symm⟩ + exact ⟨_, ‹_›, _, ‹_›, (map_mul m _ _).symm⟩ #align set.preimage_mul_preimage_subset Set.preimage_mul_preimage_subset #align set.preimage_add_preimage_subset Set.preimage_add_preimage_subset @@ -1333,7 +1333,7 @@ theorem image_div : m '' (s / t) = m '' s / m '' t := @[to_additive] lemma div_subset_range {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) : s / t ⊆ range m := by - rintro _ ⟨a, b, ha, hb, rfl⟩; + rintro _ ⟨a, ha, b, hb, rfl⟩; obtain ⟨a, rfl⟩ := hs ha obtain ⟨b, rfl⟩ := ht hb exact ⟨a / b, map_div _ _ _⟩ @@ -1341,7 +1341,7 @@ lemma div_subset_range {s t : Set β} (hs : s ⊆ range m) (ht : t ⊆ range m) @[to_additive] theorem preimage_div_preimage_subset {s t : Set β} : m ⁻¹' s / m ⁻¹' t ⊆ m ⁻¹' (s / t) := by rintro _ ⟨_, _, _, _, rfl⟩ - exact ⟨_, _, ‹_›, ‹_›, (map_div m _ _).symm⟩ + exact ⟨_, ‹_›, _, ‹_›, (map_div m _ _).symm⟩ #align set.preimage_div_preimage_subset Set.preimage_div_preimage_subset #align set.preimage_sub_preimage_subset Set.preimage_sub_preimage_subset diff --git a/Mathlib/Data/Set/Pointwise/BigOperators.lean b/Mathlib/Data/Set/Pointwise/BigOperators.lean index 4644e5b3bfe4e..1abf2febb2f70 100644 --- a/Mathlib/Data/Set/Pointwise/BigOperators.lean +++ b/Mathlib/Data/Set/Pointwise/BigOperators.lean @@ -77,7 +77,7 @@ theorem mem_finset_prod (t : Finset ι) (f : ι → Set α) (a : α) : exact hg hj · rw [Finset.prod_update_of_not_mem hi, Function.update_same] · rintro ⟨g, hg, rfl⟩ - exact ⟨g i, is.prod g, hg (is.mem_insert_self _), + exact ⟨g i, hg (is.mem_insert_self _), is.prod g, ⟨⟨g, fun hi ↦ hg (Finset.mem_insert_of_mem hi), rfl⟩, rfl⟩⟩ #align set.mem_finset_prod Set.mem_finset_prod #align set.mem_finset_sum Set.mem_finset_sum diff --git a/Mathlib/Data/Set/Pointwise/Interval.lean b/Mathlib/Data/Set/Pointwise/Interval.lean index 0f347211555d3..652aed22d34ad 100644 --- a/Mathlib/Data/Set/Pointwise/Interval.lean +++ b/Mathlib/Data/Set/Pointwise/Interval.lean @@ -44,17 +44,17 @@ variable [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (Fun @[to_additive Icc_add_Icc_subset] theorem Icc_mul_Icc_subset' (a b c d : α) : Icc a b * Icc c d ⊆ Icc (a * c) (b * d) := by - rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_le_mul' hya hzc, mul_le_mul' hyb hzd⟩ @[to_additive Iic_add_Iic_subset] theorem Iic_mul_Iic_subset' (a b : α) : Iic a * Iic b ⊆ Iic (a * b) := by - rintro x ⟨y, z, hya, hzb, rfl⟩ + rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_le_mul' hya hzb @[to_additive Ici_add_Ici_subset] theorem Ici_mul_Ici_subset' (a b : α) : Ici a * Ici b ⊆ Ici (a * b) := by - rintro x ⟨y, z, hya, hzb, rfl⟩ + rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_le_mul' hya hzb end ContravariantLE @@ -67,49 +67,49 @@ variable [CovariantClass α α (· * ·) (· < ·)] [CovariantClass α α (Funct @[to_additive Icc_add_Ico_subset] theorem Icc_mul_Ico_subset' (a b c d : α) : Icc a b * Ico c d ⊆ Ico (a * c) (b * d) := by haveI := covariantClass_le_of_lt - rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_le_mul' hya hzc, mul_lt_mul_of_le_of_lt hyb hzd⟩ @[to_additive Ico_add_Icc_subset] theorem Ico_mul_Icc_subset' (a b c d : α) : Ico a b * Icc c d ⊆ Ico (a * c) (b * d) := by haveI := covariantClass_le_of_lt - rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_le_mul' hya hzc, mul_lt_mul_of_lt_of_le hyb hzd⟩ @[to_additive Ioc_add_Ico_subset] theorem Ioc_mul_Ico_subset' (a b c d : α) : Ioc a b * Ico c d ⊆ Ioo (a * c) (b * d) := by haveI := covariantClass_le_of_lt - rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_lt_mul_of_lt_of_le hya hzc, mul_lt_mul_of_le_of_lt hyb hzd⟩ @[to_additive Ico_add_Ioc_subset] theorem Ico_mul_Ioc_subset' (a b c d : α) : Ico a b * Ioc c d ⊆ Ioo (a * c) (b * d) := by haveI := covariantClass_le_of_lt - rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + rintro x ⟨y, ⟨hya, hyb⟩, z, ⟨hzc, hzd⟩, rfl⟩ exact ⟨mul_lt_mul_of_le_of_lt hya hzc, mul_lt_mul_of_lt_of_le hyb hzd⟩ @[to_additive Iic_add_Iio_subset] theorem Iic_mul_Iio_subset' (a b : α) : Iic a * Iio b ⊆ Iio (a * b) := by haveI := covariantClass_le_of_lt - rintro x ⟨y, z, hya, hzb, rfl⟩ + rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_lt_mul_of_le_of_lt hya hzb @[to_additive Iio_add_Iic_subset] theorem Iio_mul_Iic_subset' (a b : α) : Iio a * Iic b ⊆ Iio (a * b) := by haveI := covariantClass_le_of_lt - rintro x ⟨y, z, hya, hzb, rfl⟩ + rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_lt_mul_of_lt_of_le hya hzb @[to_additive Ioi_add_Ici_subset] theorem Ioi_mul_Ici_subset' (a b : α) : Ioi a * Ici b ⊆ Ioi (a * b) := by haveI := covariantClass_le_of_lt - rintro x ⟨y, z, hya, hzb, rfl⟩ + rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_lt_mul_of_lt_of_le hya hzb @[to_additive Ici_add_Ioi_subset] theorem Ici_mul_Ioi_subset' (a b : α) : Ici a * Ioi b ⊆ Ioi (a * b) := by haveI := covariantClass_le_of_lt - rintro x ⟨y, z, hya, hzb, rfl⟩ + rintro x ⟨y, hya, z, hzb, rfl⟩ exact mul_lt_mul_of_le_of_lt hya hzb end ContravariantLT diff --git a/Mathlib/Data/Set/Pointwise/ListOfFn.lean b/Mathlib/Data/Set/Pointwise/ListOfFn.lean index 5127ebb149acd..4e489a1b2a322 100644 --- a/Mathlib/Data/Set/Pointwise/ListOfFn.lean +++ b/Mathlib/Data/Set/Pointwise/ListOfFn.lean @@ -28,7 +28,7 @@ theorem mem_prod_list_ofFn {a : α} {s : Fin n → Set α} : induction' n with n ih generalizing a · simp_rw [List.ofFn_zero, List.prod_nil, Fin.exists_fin_zero_pi, eq_comm, Set.mem_one] · simp_rw [List.ofFn_succ, List.prod_cons, Fin.exists_fin_succ_pi, Fin.cons_zero, Fin.cons_succ, - mem_mul, @ih, exists_and_left, exists_exists_eq_and, SetCoe.exists, exists_prop] + mem_mul, @ih, exists_exists_eq_and, SetCoe.exists, exists_prop] #align set.mem_prod_list_of_fn Set.mem_prod_list_ofFn #align set.mem_sum_list_of_fn Set.mem_sum_list_ofFn diff --git a/Mathlib/Data/Set/Pointwise/SMul.lean b/Mathlib/Data/Set/Pointwise/SMul.lean index 2c5838d00df39..53ad2ad7ce78e 100644 --- a/Mathlib/Data/Set/Pointwise/SMul.lean +++ b/Mathlib/Data/Set/Pointwise/SMul.lean @@ -89,7 +89,7 @@ theorem image_smul_prod : (fun x : α × β ↦ x.fst • x.snd) '' s ×ˢ t = s #align set.image_smul_prod Set.image_smul_prod @[to_additive] -theorem mem_smul : b ∈ s • t ↔ ∃ x y, x ∈ s ∧ y ∈ t ∧ x • y = b := +theorem mem_smul : b ∈ s • t ↔ ∃ x ∈ s, ∃ y ∈ t, x • y = b := Iff.rfl #align set.mem_smul Set.mem_smul #align set.mem_vadd Set.mem_vadd @@ -612,7 +612,7 @@ theorem image_vsub_prod : (fun x : β × β ↦ x.fst -ᵥ x.snd) '' s ×ˢ t = image_prod _ #align set.image_vsub_prod Set.image_vsub_prod -theorem mem_vsub : a ∈ s -ᵥ t ↔ ∃ x y, x ∈ s ∧ y ∈ t ∧ x -ᵥ y = a := +theorem mem_vsub : a ∈ s -ᵥ t ↔ ∃ x ∈ s, ∃ y ∈ t, x -ᵥ y = a := Iff.rfl #align set.mem_vsub Set.mem_vsub @@ -835,13 +835,13 @@ variable [NoZeroSMulDivisors α β] {a : α} theorem zero_mem_smul_iff : (0 : β) ∈ s • t ↔ (0 : α) ∈ s ∧ t.Nonempty ∨ (0 : β) ∈ t ∧ s.Nonempty := by constructor - · rintro ⟨a, b, ha, hb, h⟩ + · rintro ⟨a, ha, b, hb, h⟩ obtain rfl | rfl := eq_zero_or_eq_zero_of_smul_eq_zero h · exact Or.inl ⟨ha, b, hb⟩ · exact Or.inr ⟨hb, a, ha⟩ · rintro (⟨hs, b, hb⟩ | ⟨ht, a, ha⟩) - · exact ⟨0, b, hs, hb, zero_smul _ _⟩ - · exact ⟨a, 0, ha, ht, smul_zero _⟩ + · exact ⟨0, hs, b, hb, zero_smul _ _⟩ + · exact ⟨a, ha, 0, ht, smul_zero _⟩ #align set.zero_mem_smul_iff Set.zero_mem_smul_iff theorem zero_mem_smul_set_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by @@ -960,7 +960,7 @@ theorem smul_set_univ : a • (univ : Set β) = univ := @[to_additive (attr := simp)] theorem smul_univ {s : Set α} (hs : s.Nonempty) : s • (univ : Set β) = univ := let ⟨a, ha⟩ := hs - eq_univ_of_forall fun b ↦ ⟨a, a⁻¹ • b, ha, trivial, smul_inv_smul _ _⟩ + eq_univ_of_forall fun b ↦ ⟨a, ha, a⁻¹ • b, trivial, smul_inv_smul _ _⟩ #align set.smul_univ Set.smul_univ #align set.vadd_univ Set.vadd_univ @@ -1076,7 +1076,7 @@ theorem smul_set_univ₀ (ha : a ≠ 0) : a • (univ : Set β) = univ := theorem smul_univ₀ {s : Set α} (hs : ¬s ⊆ 0) : s • (univ : Set β) = univ := let ⟨a, ha, ha₀⟩ := not_subset.1 hs - eq_univ_of_forall fun b ↦ ⟨a, a⁻¹ • b, ha, trivial, smul_inv_smul₀ ha₀ _⟩ + eq_univ_of_forall fun b ↦ ⟨a, ha, a⁻¹ • b, trivial, smul_inv_smul₀ ha₀ _⟩ #align set.smul_univ₀ Set.smul_univ₀ theorem smul_univ₀' {s : Set α} (hs : s.Nontrivial) : s • (univ : Set β) = univ := diff --git a/Mathlib/Dynamics/OmegaLimit.lean b/Mathlib/Dynamics/OmegaLimit.lean index ea4b9548bdd08..ffc148b51fe6a 100644 --- a/Mathlib/Dynamics/OmegaLimit.lean +++ b/Mathlib/Dynamics/OmegaLimit.lean @@ -134,11 +134,11 @@ theorem mem_omegaLimit_iff_frequently (y : β) : simp_rw [frequently_iff, omegaLimit_def, mem_iInter, mem_closure_iff_nhds] constructor · intro h _ hn _ hu - rcases h _ hu _ hn with ⟨_, _, _, _, ht, hx, hϕtx⟩ - exact ⟨_, ht, _, hx, by rwa [mem_preimage, hϕtx]⟩ + rcases h _ hu _ hn with ⟨_, _, _, ht, _, hx, rfl⟩ + exact ⟨_, ht, _, hx, by rwa [mem_preimage]⟩ · intro h _ hu _ hn rcases h _ hn hu with ⟨_, ht, _, hx, hϕtx⟩ - exact ⟨_, hϕtx, _, _, ht, hx, rfl⟩ + exact ⟨_, hϕtx, _, ht, _, hx, rfl⟩ #align mem_omega_limit_iff_frequently mem_omegaLimit_iff_frequently /-- An element `y` is in the ω-limit set of `s` w.r.t. `f` if the @@ -391,7 +391,7 @@ theorem omegaLimit_omegaLimit (hf : ∀ t, Tendsto (t + ·) f f) : ω f ϕ (ω f have l₃ : (o ∩ image2 ϕ u s).Nonempty := by rcases l₂ with ⟨b, hb₁, hb₂⟩ exact mem_closure_iff_nhds.mp hb₁ o (IsOpen.mem_nhds ho₂ hb₂) - rcases l₃ with ⟨ϕra, ho, ⟨_, _, hr, ha, hϕra⟩⟩ + rcases l₃ with ⟨ϕra, ho, ⟨_, hr, _, ha, hϕra⟩⟩ exact ⟨_, hr, ϕra, ⟨_, ha, hϕra⟩, ho₁ ho⟩ #align flow.omega_limit_omega_limit Flow.omegaLimit_omegaLimit diff --git a/Mathlib/FieldTheory/KrullTopology.lean b/Mathlib/FieldTheory/KrullTopology.lean index 02ac509847b9a..5e48cc47f304a 100644 --- a/Mathlib/FieldTheory/KrullTopology.lean +++ b/Mathlib/FieldTheory/KrullTopology.lean @@ -158,7 +158,7 @@ def galGroupBasis (K L : Type*) [Field K] [Field L] [Algebra K L] : mul' {U} hU := ⟨U, hU, by rcases hU with ⟨H, _, rfl⟩ - rintro x ⟨a, b, haH, hbH, rfl⟩ + rintro x ⟨a, haH, b, hbH, rfl⟩ exact H.mul_mem haH hbH⟩ inv' {U} hU := ⟨U, hU, by diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index 01cb9e37d880a..e519a641f3a3e 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -703,7 +703,7 @@ def ChartedSpace.comp (H : Type*) [TopologicalSpace H] (H' : Type*) [Topological atlas := image2 PartialHomeomorph.trans (atlas H' M) (atlas H H') chartAt p := (chartAt H' p).trans (chartAt H (chartAt H' p p)) mem_chart_source p := by simp only [mfld_simps] - chart_mem_atlas p := ⟨chartAt _ p, chartAt _ _, chart_mem_atlas _ p, chart_mem_atlas _ _, rfl⟩ + chart_mem_atlas p := ⟨chartAt _ p, chart_mem_atlas _ p, chartAt _ _, chart_mem_atlas _ _, rfl⟩ #align charted_space.comp ChartedSpace.comp theorem chartAt_comp (H : Type*) [TopologicalSpace H] (H' : Type*) [TopologicalSpace H'] diff --git a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean index b3e90c4818b14..40c1e59e1ec26 100644 --- a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean +++ b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean @@ -693,7 +693,7 @@ theorem HasGroupoid.comp @HasGroupoid H₁ _ H₃ _ (ChartedSpace.comp H₁ H₂ H₃) G₁ := let _ := ChartedSpace.comp H₁ H₂ H₃ -- Porting note: need this to synthesize `ChartedSpace H₁ H₃` { compatible := by - rintro _ _ ⟨e, f, he, hf, rfl⟩ ⟨e', f', he', hf', rfl⟩ + rintro _ _ ⟨e, he, f, hf, rfl⟩ ⟨e', he', f', hf', rfl⟩ apply G₁.locality intro x hx simp only [mfld_simps] at hx diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index fe6b1396c5b8f..7612e907c11ae 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -889,7 +889,7 @@ instance prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedA [SmoothManifoldWithCorners I M] (M' : Type*) [TopologicalSpace M'] [ChartedSpace H' M'] [SmoothManifoldWithCorners I' M'] : SmoothManifoldWithCorners (I.prod I') (M × M') where compatible := by - rintro f g ⟨f1, f2, hf1, hf2, rfl⟩ ⟨g1, g2, hg1, hg2, rfl⟩ + rintro f g ⟨f1, hf1, f2, hf2, rfl⟩ ⟨g1, hg1, g2, hg2, rfl⟩ rw [PartialHomeomorph.prod_symm, PartialHomeomorph.prod_trans] have h1 := (contDiffGroupoid ⊤ I).compatible hf1 hg1 have h2 := (contDiffGroupoid ⊤ I').compatible hf2 hg2 diff --git a/Mathlib/GroupTheory/Complement.lean b/Mathlib/GroupTheory/Complement.lean index 495fd1930c643..ca50d6979627c 100644 --- a/Mathlib/GroupTheory/Complement.lean +++ b/Mathlib/GroupTheory/Complement.lean @@ -713,7 +713,7 @@ theorem IsComplement'.card_mul [Fintype G] [Fintype H] [Fintype K] (h : IsComple theorem isComplement'_of_disjoint_and_mul_eq_univ (h1 : Disjoint H K) (h2 : ↑H * ↑K = (Set.univ : Set G)) : IsComplement' H K := by refine' ⟨mul_injective_of_disjoint h1, fun g => _⟩ - obtain ⟨h, k, hh, hk, hg⟩ := Set.eq_univ_iff_forall.mp h2 g + obtain ⟨h, hh, k, hk, hg⟩ := Set.eq_univ_iff_forall.mp h2 g exact ⟨(⟨h, hh⟩, ⟨k, hk⟩), hg⟩ #align subgroup.is_complement'_of_disjoint_and_mul_eq_univ Subgroup.isComplement'_of_disjoint_and_mul_eq_univ diff --git a/Mathlib/GroupTheory/DoubleCoset.lean b/Mathlib/GroupTheory/DoubleCoset.lean index 93cfb1a4205f1..3d2435e0762c9 100644 --- a/Mathlib/GroupTheory/DoubleCoset.lean +++ b/Mathlib/GroupTheory/DoubleCoset.lean @@ -39,9 +39,11 @@ def doset (a : α) (s t : Set α) : Set α := s * {a} * t #align doset Doset.doset -theorem mem_doset {s t : Set α} {a b : α} : b ∈ doset a s t ↔ ∃ x ∈ s, ∃ y ∈ t, b = x * a * y := - ⟨fun ⟨_, y, ⟨x, _, hx, rfl, rfl⟩, hy, h⟩ => ⟨x, hx, y, hy, h.symm⟩, fun ⟨x, hx, y, hy, h⟩ => - ⟨x * a, y, ⟨x, a, hx, rfl, rfl⟩, hy, h.symm⟩⟩ +lemma doset_eq_image2 (a : α) (s t : Set α) : doset a s t = Set.image2 (· * a * ·) s t := by + simp_rw [doset, Set.mul_singleton, ← Set.image2_mul, Set.image2_image_left] + +theorem mem_doset {s t : Set α} {a b : α} : b ∈ doset a s t ↔ ∃ x ∈ s, ∃ y ∈ t, b = x * a * y := by + simp only [doset_eq_image2, Set.mem_image2, eq_comm] #align doset.mem_doset Doset.mem_doset theorem mem_doset_self (H K : Subgroup G) (a : G) : a ∈ doset a H K := @@ -50,7 +52,7 @@ theorem mem_doset_self (H K : Subgroup G) (a : G) : a ∈ doset a H K := theorem doset_eq_of_mem {H K : Subgroup G} {a b : G} (hb : b ∈ doset a H K) : doset b H K = doset a H K := by - obtain ⟨_, k, ⟨h, a, hh, rfl : _ = _, rfl⟩, hk, rfl⟩ := hb + obtain ⟨h, hh, k, hk, rfl⟩ := mem_doset.1 hb rw [doset, doset, ← Set.singleton_mul_singleton, ← Set.singleton_mul_singleton, mul_assoc, mul_assoc, Subgroup.singleton_mul_subgroup hk, ← mul_assoc, ← mul_assoc, Subgroup.subgroup_mul_singleton hh] diff --git a/Mathlib/GroupTheory/GroupAction/SubMulAction/Pointwise.lean b/Mathlib/GroupTheory/GroupAction/SubMulAction/Pointwise.lean index b6e86fff267fc..9e5db5adf89bf 100644 --- a/Mathlib/GroupTheory/GroupAction/SubMulAction/Pointwise.lean +++ b/Mathlib/GroupTheory/GroupAction/SubMulAction/Pointwise.lean @@ -55,7 +55,7 @@ variable [Monoid R] [MulAction R M] [Mul M] [IsScalarTower R M M] instance : Mul (SubMulAction R M) where mul p q := { carrier := Set.image2 (· * ·) p q - smul_mem' := fun r _ ⟨m₁, m₂, hm₁, hm₂, h⟩ => + smul_mem' := fun r _ ⟨m₁, hm₁, m₂, hm₂, h⟩ => h ▸ smul_mul_assoc r m₁ m₂ ▸ Set.mul_mem_mul (p.smul_mem _ hm₁) hm₂ } @[norm_cast] @@ -63,7 +63,7 @@ theorem coe_mul (p q : SubMulAction R M) : ↑(p * q) = (p * q : Set M) := rfl #align sub_mul_action.coe_mul SubMulAction.coe_mul -theorem mem_mul {p q : SubMulAction R M} {x : M} : x ∈ p * q ↔ ∃ y z, y ∈ p ∧ z ∈ q ∧ y * z = x := +theorem mem_mul {p q : SubMulAction R M} {x : M} : x ∈ p * q ↔ ∃ y ∈ p, ∃ z ∈ q, y * z = x := Set.mem_mul #align sub_mul_action.mem_mul SubMulAction.mem_mul @@ -74,13 +74,12 @@ section MulOneClass variable [Monoid R] [MulAction R M] [MulOneClass M] [IsScalarTower R M M] [SMulCommClass R M M] -- porting note: giving the instance the name `mulOneClass` -instance mulOneClass : MulOneClass (SubMulAction R M) - where +instance mulOneClass : MulOneClass (SubMulAction R M) where mul := (· * ·) one := 1 mul_one a := by ext x - simp only [mem_mul, mem_one, mul_smul_comm, exists_and_left, exists_exists_eq_and, mul_one] + simp only [mem_mul, mem_one, mul_smul_comm, exists_exists_eq_and, mul_one] constructor · rintro ⟨y, hy, r, rfl⟩ exact smul_mem _ _ hy @@ -88,7 +87,7 @@ instance mulOneClass : MulOneClass (SubMulAction R M) exact ⟨x, hx, 1, one_smul _ _⟩ one_mul a := by ext x - simp only [mem_mul, mem_one, smul_mul_assoc, exists_and_left, exists_exists_eq_and, one_mul] + simp only [mem_mul, mem_one, smul_mul_assoc, exists_exists_eq_and, one_mul] refine' ⟨_, fun hx => ⟨1, x, hx, one_smul _ _⟩⟩ rintro ⟨r, y, hy, rfl⟩ exact smul_mem _ _ hy diff --git a/Mathlib/GroupTheory/QuotientGroup.lean b/Mathlib/GroupTheory/QuotientGroup.lean index 378904b0d9f61..944dba4dea68d 100644 --- a/Mathlib/GroupTheory/QuotientGroup.lean +++ b/Mathlib/GroupTheory/QuotientGroup.lean @@ -304,9 +304,9 @@ lemma preimage_image_coe (s : Set G) : ((↑) : G → Q) ⁻¹' ((↑) '' s) = N ext a constructor · rintro ⟨b, hb, h⟩ - refine ⟨a / b, b, (QuotientGroup.eq_one_iff _).1 ?_, hb, div_mul_cancel' _ _⟩ + refine ⟨a / b, (QuotientGroup.eq_one_iff _).1 ?_, b, hb, div_mul_cancel' _ _⟩ simp only [h, QuotientGroup.mk_div, div_self'] - · rintro ⟨a, b, ha, hb, rfl⟩ + · rintro ⟨a, ha, b, hb, rfl⟩ refine ⟨b, hb, ?_⟩ simpa only [QuotientGroup.mk_mul, self_eq_mul_left, QuotientGroup.eq_one_iff] @@ -622,7 +622,7 @@ noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Norma rintro ⟨y, hy : y ∈ (H ⊔ N)⟩; rw [← SetLike.mem_coe] at hy rw [mul_normal H N] at hy - rcases hy with ⟨h, n, hh, hn, rfl⟩ + rcases hy with ⟨h, hh, n, hn, rfl⟩ use ⟨h, hh⟩ let _ : Setoid ↑(H ⊔ N) := (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N))) diff --git a/Mathlib/GroupTheory/Schreier.lean b/Mathlib/GroupTheory/Schreier.lean index ec755ac9c39ce..9e65e7672d958 100644 --- a/Mathlib/GroupTheory/Schreier.lean +++ b/Mathlib/GroupTheory/Schreier.lean @@ -42,12 +42,12 @@ theorem closure_mul_image_mul_eq_top change (closure U : Set G) * R = ⊤ refine' top_le_iff.mp fun g _ => _ apply closure_induction_right (eq_top_iff.mp hS (mem_top g)) - · exact ⟨1, 1, (closure U).one_mem, hR1, one_mul 1⟩ - · rintro - s hs ⟨u, r, hu, hr, rfl⟩ + · exact ⟨1, (closure U).one_mem, 1, hR1, one_mul 1⟩ + · rintro - s hs ⟨u, hu, r, hr, rfl⟩ rw [show u * r * s = u * (r * s * (f (r * s) : G)⁻¹) * f (r * s) by group] refine' Set.mul_mem_mul ((closure U).mul_mem hu _) (f (r * s)).coe_prop exact subset_closure ⟨r * s, Set.mul_mem_mul hr hs, rfl⟩ - · rintro - s hs ⟨u, r, hu, hr, rfl⟩ + · rintro - s hs ⟨u, hu, r, hr, rfl⟩ rw [show u * r * s⁻¹ = u * (f (r * s⁻¹) * s * r⁻¹)⁻¹ * f (r * s⁻¹) by group] refine' Set.mul_mem_mul ((closure U).mul_mem hu ((closure U).inv_mem _)) (f (r * s⁻¹)).2 refine' subset_closure ⟨f (r * s⁻¹) * s, Set.mul_mem_mul (f (r * s⁻¹)).2 hs, _⟩ @@ -58,7 +58,7 @@ theorem closure_mul_image_mul_eq_top exact toFun_mul_inv_mem hR (r * s⁻¹) #align subgroup.closure_mul_image_mul_eq_top Subgroup.closure_mul_image_mul_eq_top -/-- **Schreier's Lemma**: If `R : Set G` is a `rightTransversal of` `H : Subgroup G` +/-- **Schreier's Lemma**: If `R : Set G` is a `rightTransversal` 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 (fun g ↦ g * (toFun hR g)⁻¹)`. -/ theorem closure_mul_image_eq (hR : R ∈ rightTransversals (H : Set G)) (hR1 : (1 : G) ∈ R) @@ -68,7 +68,7 @@ theorem closure_mul_image_eq (hR : R ∈ rightTransversals (H : Set G)) (hR1 : ( rintro - ⟨g, -, rfl⟩ exact mul_inv_toFun_mem hR g refine' le_antisymm hU fun h hh => _ - obtain ⟨g, r, hg, hr, rfl⟩ := + obtain ⟨g, hg, r, hr, rfl⟩ := show h ∈ _ from eq_top_iff.mp (closure_mul_image_mul_eq_top hR hR1 hS) (mem_top h) suffices (⟨r, hr⟩ : R) = (⟨1, hR1⟩ : R) by simpa only [show r = 1 from Subtype.ext_iff.mp this, mul_one] diff --git a/Mathlib/GroupTheory/Subgroup/Pointwise.lean b/Mathlib/GroupTheory/Subgroup/Pointwise.lean index fd92511d3bd72..e531ddb411249 100644 --- a/Mathlib/GroupTheory/Subgroup/Pointwise.lean +++ b/Mathlib/GroupTheory/Subgroup/Pointwise.lean @@ -148,7 +148,7 @@ theorem iSup_induction' {ι : Sort*} (S : ι → Subgroup G) {C : ∀ x, (x ∈ @[to_additive] theorem closure_mul_le (S T : Set G) : closure (S * T) ≤ closure S ⊔ closure T := - sInf_le fun _x ⟨_s, _t, hs, ht, hx⟩ => hx ▸ + sInf_le fun _x ⟨_s, hs, _t, ht, hx⟩ => hx ▸ (closure S ⊔ closure T).mul_mem (SetLike.le_def.mp le_sup_left <| subset_closure hs) (SetLike.le_def.mp le_sup_right <| subset_closure ht) #align subgroup.closure_mul_le Subgroup.closure_mul_le @@ -157,8 +157,8 @@ theorem closure_mul_le (S T : Set G) : closure (S * T) ≤ closure S ⊔ closure @[to_additive] theorem sup_eq_closure_mul (H K : Subgroup G) : H ⊔ K = closure ((H : Set G) * (K : Set G)) := le_antisymm - (sup_le (fun h hh => subset_closure ⟨h, 1, hh, K.one_mem, mul_one h⟩) fun k hk => - subset_closure ⟨1, k, H.one_mem, hk, one_mul k⟩) + (sup_le (fun h hh => subset_closure ⟨h, hh, 1, K.one_mem, mul_one h⟩) fun k hk => + subset_closure ⟨1, H.one_mem, k, hk, one_mul k⟩) ((closure_mul_le _ _).trans <| by rw [closure_eq, closure_eq]) #align subgroup.sup_eq_closure Subgroup.sup_eq_closure_mul #align add_subgroup.sup_eq_closure AddSubgroup.sup_eq_closure_add @@ -176,14 +176,14 @@ theorem mul_normal (H N : Subgroup G) [hN : N.Normal] : (↑(H ⊔ N) : Set G) = rw [sup_eq_closure_mul] refine Set.Subset.antisymm (fun x hx => ?_) subset_closure refine closure_induction'' (p := fun x => x ∈ (H : Set G) * (N : Set G)) hx ?_ ?_ ?_ ?_ - · rintro _ ⟨x, y, hx, hy, rfl⟩ + · rintro _ ⟨x, hx, y, hy, rfl⟩ exact mul_mem_mul hx hy - · rintro _ ⟨x, y, hx, hy, rfl⟩ + · rintro _ ⟨x, hx, y, hy, rfl⟩ simpa only [mul_inv_rev, mul_assoc, inv_inv, inv_mul_cancel_left] using mul_mem_mul (inv_mem hx) (hN.conj_mem _ (inv_mem hy) x) - · exact ⟨1, 1, one_mem _, one_mem _, mul_one 1⟩ - · rintro _ _ ⟨x, y, hx, hy, rfl⟩ ⟨x', y', hx', hy', rfl⟩ - refine ⟨x * x', x'⁻¹ * y * x' * y', mul_mem hx hx', mul_mem ?_ hy', ?_⟩ + · exact ⟨1, one_mem _, 1, one_mem _, mul_one 1⟩ + · rintro _ _ ⟨x, hx, y, hy, rfl⟩ ⟨x', hx', y', hy', rfl⟩ + refine ⟨x * x', mul_mem hx hx', x'⁻¹ * y * x' * y', mul_mem ?_ hy', ?_⟩ · simpa using hN.conj_mem _ hy x'⁻¹ · simp only [mul_assoc, mul_inv_cancel_left] #align subgroup.mul_normal Subgroup.mul_normal @@ -203,11 +203,11 @@ theorem mul_inf_assoc (A B C : Subgroup G) (h : A ≤ C) : ext simp only [coe_inf, Set.mem_mul, Set.mem_inter_iff] constructor - · rintro ⟨y, z, hy, ⟨hzB, hzC⟩, rfl⟩ + · rintro ⟨y, hy, z, ⟨hzB, hzC⟩, rfl⟩ refine' ⟨_, mul_mem (h hy) hzC⟩ - exact ⟨y, z, hy, hzB, rfl⟩ - rintro ⟨⟨y, z, hy, hz, rfl⟩, hyz⟩ - refine' ⟨y, z, hy, ⟨hz, _⟩, rfl⟩ + exact ⟨y, hy, z, hzB, rfl⟩ + rintro ⟨⟨y, hy, z, hz, rfl⟩, hyz⟩ + refine' ⟨y, hy, z, ⟨hz, _⟩, rfl⟩ suffices y⁻¹ * (y * z) ∈ C by simpa exact mul_mem (inv_mem (h hy)) hyz #align subgroup.mul_inf_assoc Subgroup.mul_inf_assoc @@ -219,11 +219,11 @@ theorem inf_mul_assoc (A B C : Subgroup G) (h : C ≤ A) : ext simp only [coe_inf, Set.mem_mul, Set.mem_inter_iff] constructor - · rintro ⟨y, z, ⟨hyA, hyB⟩, hz, rfl⟩ + · rintro ⟨y, ⟨hyA, hyB⟩, z, hz, rfl⟩ refine' ⟨A.mul_mem hyA (h hz), _⟩ - exact ⟨y, z, hyB, hz, rfl⟩ - rintro ⟨hyz, y, z, hy, hz, rfl⟩ - refine' ⟨y, z, ⟨_, hy⟩, hz, rfl⟩ + exact ⟨y, hyB, z, hz, rfl⟩ + rintro ⟨hyz, y, hy, z, hz, rfl⟩ + refine' ⟨y, ⟨_, hy⟩, z, hz, rfl⟩ suffices y * z * z⁻¹ ∈ A by simpa exact mul_mem hyz (inv_mem (h hz)) #align subgroup.inf_mul_assoc Subgroup.inf_mul_assoc @@ -233,8 +233,8 @@ theorem inf_mul_assoc (A B C : Subgroup G) (h : C ≤ A) : instance sup_normal (H K : Subgroup G) [hH : H.Normal] [hK : K.Normal] : (H ⊔ K).Normal where conj_mem n hmem g := by rw [← SetLike.mem_coe, normal_mul] at hmem ⊢ - rcases hmem with ⟨h, k, hh, hk, rfl⟩ - refine ⟨g * h * g⁻¹, g * k * g⁻¹, hH.conj_mem h hh g, hK.conj_mem k hk g, ?_⟩ + rcases hmem with ⟨h, hh, k, hk, rfl⟩ + refine ⟨g * h * g⁻¹, hH.conj_mem h hh g, g * k * g⁻¹, hK.conj_mem k hk g, ?_⟩ simp only [mul_assoc, inv_mul_cancel_left] #align subgroup.sup_normal Subgroup.sup_normal diff --git a/Mathlib/GroupTheory/Submonoid/Pointwise.lean b/Mathlib/GroupTheory/Submonoid/Pointwise.lean index 9097eb3cbed15..4edc0bf5cea8e 100644 --- a/Mathlib/GroupTheory/Submonoid/Pointwise.lean +++ b/Mathlib/GroupTheory/Submonoid/Pointwise.lean @@ -71,15 +71,15 @@ theorem mul_subset_closure (hs : s ⊆ u) (ht : t ⊆ u) : s * t ⊆ Submonoid.c @[to_additive] theorem coe_mul_self_eq (s : Submonoid M) : (s : Set M) * s = s := by ext x - refine' ⟨_, fun h => ⟨x, 1, h, s.one_mem, mul_one x⟩⟩ - rintro ⟨a, b, ha, hb, rfl⟩ + refine' ⟨_, fun h => ⟨x, h, 1, s.one_mem, mul_one x⟩⟩ + rintro ⟨a, ha, b, hb, rfl⟩ exact s.mul_mem ha hb #align submonoid.coe_mul_self_eq Submonoid.coe_mul_self_eq #align add_submonoid.coe_add_self_eq AddSubmonoid.coe_add_self_eq @[to_additive] theorem closure_mul_le (S T : Set M) : closure (S * T) ≤ closure S ⊔ closure T := - sInf_le fun _x ⟨_s, _t, hs, ht, hx⟩ => hx ▸ + sInf_le fun _x ⟨_s, hs, _t, ht, hx⟩ => hx ▸ (closure S ⊔ closure T).mul_mem (SetLike.le_def.mp le_sup_left <| subset_closure hs) (SetLike.le_def.mp le_sup_right <| subset_closure ht) #align submonoid.closure_mul_le Submonoid.closure_mul_le @@ -88,8 +88,8 @@ theorem closure_mul_le (S T : Set M) : closure (S * T) ≤ closure S ⊔ closure @[to_additive] theorem sup_eq_closure_mul (H K : Submonoid M) : H ⊔ K = closure ((H : Set M) * (K : Set M)) := le_antisymm - (sup_le (fun h hh => subset_closure ⟨h, 1, hh, K.one_mem, mul_one h⟩) fun k hk => - subset_closure ⟨1, k, H.one_mem, hk, one_mul k⟩) + (sup_le (fun h hh => subset_closure ⟨h, hh, 1, K.one_mem, mul_one h⟩) fun k hk => + subset_closure ⟨1, H.one_mem, k, hk, one_mul k⟩) ((closure_mul_le _ _).trans <| by rw [closure_eq, closure_eq]) #align submonoid.sup_eq_closure Submonoid.sup_eq_closure_mul #align add_submonoid.sup_eq_closure AddSubmonoid.sup_eq_closure_add @@ -557,7 +557,7 @@ theorem closure_mul_closure (S T : Set R) : closure S * closure T = closure (S * change a' * b' ∈ closure (S * T) exact subset_closure (Set.mul_mem_mul ha' hb') · rw [closure_le] - rintro _ ⟨a, b, ha, hb, rfl⟩ + rintro _ ⟨a, ha, b, hb, rfl⟩ exact mul_mem_mul (subset_closure ha) (subset_closure hb) #align add_submonoid.closure_mul_closure AddSubmonoid.closure_mul_closure diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean index 4c1fe9ed28b1f..445981c716895 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean @@ -214,13 +214,13 @@ def directionOfNonempty {s : AffineSubspace k P} (h : (s : Set P).Nonempty) : Su cases' h with p hp exact vsub_self p ▸ vsub_mem_vsub hp hp add_mem' := by - rintro _ _ ⟨p1, p2, hp1, hp2, rfl⟩ ⟨p3, p4, hp3, hp4, rfl⟩ + rintro _ _ ⟨p1, hp1, p2, hp2, rfl⟩ ⟨p3, hp3, p4, hp4, rfl⟩ rw [← vadd_vsub_assoc] refine' vsub_mem_vsub _ hp4 convert s.smul_vsub_vadd_mem 1 hp1 hp2 hp3 rw [one_smul] smul_mem' := by - rintro c _ ⟨p1, p2, hp1, hp2, rfl⟩ + rintro c _ ⟨p1, hp1, p2, hp2, rfl⟩ rw [← vadd_vsub (c • (p1 -ᵥ p2)) p2] refine' vsub_mem_vsub _ hp2 exact s.smul_vsub_vadd_mem c hp1 hp2 hp2 @@ -245,10 +245,8 @@ theorem coe_direction_eq_vsub_set {s : AffineSubspace k P} (h : (s : Set P).None of two vectors in the subspace. -/ theorem mem_direction_iff_eq_vsub {s : AffineSubspace k P} (h : (s : Set P).Nonempty) (v : V) : v ∈ s.direction ↔ ∃ p1 ∈ s, ∃ p2 ∈ s, v = p1 -ᵥ p2 := by - rw [← SetLike.mem_coe, coe_direction_eq_vsub_set h] - exact - ⟨fun ⟨p1, p2, hp1, hp2, hv⟩ => ⟨p1, hp1, p2, hp2, hv.symm⟩, fun ⟨p1, hp1, p2, hp2, hv⟩ => - ⟨p1, p2, hp1, hp2, hv.symm⟩⟩ + rw [← SetLike.mem_coe, coe_direction_eq_vsub_set h, Set.mem_vsub] + simp only [SetLike.mem_coe, eq_comm] #align affine_subspace.mem_direction_iff_eq_vsub AffineSubspace.mem_direction_iff_eq_vsub /-- Adding a vector in the direction to a point in the subspace produces a point in the @@ -291,10 +289,10 @@ theorem coe_direction_eq_vsub_set_right {s : AffineSubspace k P} {p : P} (hp : p (s.direction : Set V) = (· -ᵥ p) '' s := by rw [coe_direction_eq_vsub_set ⟨p, hp⟩] refine' le_antisymm _ _ - · rintro v ⟨p1, p2, hp1, hp2, rfl⟩ + · rintro v ⟨p1, hp1, p2, hp2, rfl⟩ exact ⟨p1 -ᵥ p2 +ᵥ p, vadd_mem_of_mem_direction (vsub_mem_direction hp1 hp2) hp, vadd_vsub _ _⟩ · rintro v ⟨p2, hp2, rfl⟩ - exact ⟨p2, p, hp2, hp, rfl⟩ + exact ⟨p2, hp2, p, hp, rfl⟩ #align affine_subspace.coe_direction_eq_vsub_set_right AffineSubspace.coe_direction_eq_vsub_set_right /-- Given a point in an affine subspace, the set of vectors in its direction equals the set of @@ -567,7 +565,7 @@ theorem subset_affineSpan (s : Set P) : s ⊆ affineSpan k s := theorem direction_affineSpan (s : Set P) : (affineSpan k s).direction = vectorSpan k s := by apply le_antisymm · refine' Submodule.span_le.2 _ - rintro v ⟨p1, p3, ⟨p2, hp2, v1, hv1, hp1⟩, ⟨p4, hp4, v2, hv2, hp3⟩, rfl⟩ + rintro v ⟨p1, ⟨p2, hp2, v1, hv1, hp1⟩, p3, ⟨p4, hp4, v2, hv2, hp3⟩, rfl⟩ simp only [SetLike.mem_coe] rw [hp1, hp3, vsub_vadd_eq_vsub_sub, vadd_vsub_assoc] exact @@ -1048,12 +1046,12 @@ theorem vectorSpan_eq_span_vsub_set_left {s : Set P} {p : P} (hp : p ∈ s) : rw [vectorSpan_def] refine' le_antisymm _ (Submodule.span_mono _) · rw [Submodule.span_le] - rintro v ⟨p1, p2, hp1, hp2, hv⟩ + rintro v ⟨p1, hp1, p2, hp2, hv⟩ simp_rw [← vsub_sub_vsub_cancel_left p1 p2 p] at hv rw [← hv, SetLike.mem_coe, Submodule.mem_span] exact fun m hm => Submodule.sub_mem _ (hm ⟨p2, hp2, rfl⟩) (hm ⟨p1, hp1, rfl⟩) · rintro v ⟨p2, hp2, hv⟩ - exact ⟨p, p2, hp, hp2, hv⟩ + exact ⟨p, hp, p2, hp2, hv⟩ #align vector_span_eq_span_vsub_set_left vectorSpan_eq_span_vsub_set_left /-- The `vectorSpan` is the span of the pairwise subtractions with a given point on the right. -/ @@ -1062,12 +1060,12 @@ theorem vectorSpan_eq_span_vsub_set_right {s : Set P} {p : P} (hp : p ∈ s) : rw [vectorSpan_def] refine' le_antisymm _ (Submodule.span_mono _) · rw [Submodule.span_le] - rintro v ⟨p1, p2, hp1, hp2, hv⟩ + rintro v ⟨p1, hp1, p2, hp2, hv⟩ simp_rw [← vsub_sub_vsub_cancel_right p1 p2 p] at hv rw [← hv, SetLike.mem_coe, Submodule.mem_span] exact fun m hm => Submodule.sub_mem _ (hm ⟨p1, hp1, rfl⟩) (hm ⟨p2, hp2, rfl⟩) · rintro v ⟨p2, hp2, hv⟩ - exact ⟨p2, p, hp2, hp, hv⟩ + exact ⟨p2, hp2, p, hp, hv⟩ #align vector_span_eq_span_vsub_set_right vectorSpan_eq_span_vsub_set_right /-- The `vectorSpan` is the span of the pairwise subtractions with a given point on the left, diff --git a/Mathlib/LinearAlgebra/TensorProduct.lean b/Mathlib/LinearAlgebra/TensorProduct.lean index 751e18aadec67..e0c263c692f81 100644 --- a/Mathlib/LinearAlgebra/TensorProduct.lean +++ b/Mathlib/LinearAlgebra/TensorProduct.lean @@ -489,7 +489,7 @@ theorem span_tmul_eq_top : Submodule.span R { t : M ⊗[R] N | ∃ m n, m ⊗ₜ @[simp] theorem map₂_mk_top_top_eq_top : Submodule.map₂ (mk R M N) ⊤ ⊤ = ⊤ := by rw [← top_le_iff, ← span_tmul_eq_top, Submodule.map₂_eq_span_image2] - exact Submodule.span_mono fun _ ⟨m, n, h⟩ => ⟨m, n, trivial, trivial, h⟩ + exact Submodule.span_mono fun _ ⟨m, n, h⟩ => ⟨m, trivial, n, trivial, h⟩ #align tensor_product.map₂_mk_top_top_eq_top TensorProduct.map₂_mk_top_top_eq_top theorem exists_eq_tmul_of_forall (x : TensorProduct R M N) diff --git a/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean b/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean index 72fb2c01d96f1..decdc84c54ed3 100644 --- a/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean @@ -71,7 +71,7 @@ variable {α α' β β' γ E : Type*} /-- Rectangles formed by π-systems form a π-system. -/ theorem IsPiSystem.prod {C : Set (Set α)} {D : Set (Set β)} (hC : IsPiSystem C) (hD : IsPiSystem D) : IsPiSystem (image2 (· ×ˢ ·) C D) := by - rintro _ ⟨s₁, t₁, hs₁, ht₁, rfl⟩ _ ⟨s₂, t₂, hs₂, ht₂, rfl⟩ hst + rintro _ ⟨s₁, hs₁, t₁, ht₁, rfl⟩ _ ⟨s₂, hs₂, t₂, ht₂, rfl⟩ hst rw [prod_inter_prod] at hst ⊢; rw [prod_nonempty_iff] at hst exact mem_image2_of_mem (hC _ hs₁ _ hs₂ hst.1) (hD _ ht₁ _ ht₂ hst.2) #align is_pi_system.prod IsPiSystem.prod @@ -113,7 +113,7 @@ theorem generateFrom_prod_eq {α β} {C : Set (Set α)} {D : Set (Set β)} (hC : apply MeasurableSet.iUnion intro n apply measurableSet_generateFrom - exact ⟨s, t n, hs, h1t n, rfl⟩ + exact ⟨s, hs, t n, h1t n, rfl⟩ · rcases hC with ⟨t, h1t, h2t⟩ rw [← univ_prod, ← h2t, iUnion_prod_const] apply MeasurableSet.iUnion @@ -121,7 +121,7 @@ theorem generateFrom_prod_eq {α β} {C : Set (Set α)} {D : Set (Set β)} (hC : apply measurableSet_generateFrom exact mem_image2_of_mem (h1t n) hs · apply generateFrom_le - rintro _ ⟨s, t, hs, ht, rfl⟩ + rintro _ ⟨s, hs, t, ht, rfl⟩ dsimp only rw [prod_eq] apply (measurable_fst _).inter (measurable_snd _) @@ -159,7 +159,7 @@ theorem measurable_measure_prod_mk_left_finite [IsFiniteMeasure ν] {s : Set (α refine' induction_on_inter (C := fun s => Measurable fun x => ν (Prod.mk x ⁻¹' s)) generateFrom_prod.symm isPiSystem_prod _ _ _ _ hs · simp [measurable_zero, const_def] - · rintro _ ⟨s, t, hs, _, rfl⟩ + · rintro _ ⟨s, hs, t, _, rfl⟩ simp only [mk_preimage_prod_right_eq_if, measure_if] exact measurable_const.indicator hs · intro t ht h2t @@ -221,7 +221,7 @@ theorem MeasurableEmbedding.prod_mk {α β γ δ : Type*} {mα : MeasurableSpace (fun s => MeasurableSet ((fun x : γ × α => (g x.fst, f x.snd)) '' s)) _ _ generateFrom_prod.symm isPiSystem_prod _ _ _ _ _ hs · simp only [Set.image_empty, MeasurableSet.empty] - · rintro t ⟨t₁, t₂, ht₁, ht₂, rfl⟩ + · rintro t ⟨t₁, ht₁, t₂, ht₂, rfl⟩ rw [← Set.prod_image_image_eq] exact (hg.measurableSet_image.mpr ht₁).prod (hf.measurableSet_image.mpr ht₂) · intro t _ ht_m @@ -600,7 +600,7 @@ theorem prod_eq_generateFrom {μ : Measure α} {ν : Measure β} {C : Set (Set (h3C.prod h3D).ext (generateFrom_eq_prod hC hD h3C.isCountablySpanning h3D.isCountablySpanning).symm (h2C.prod h2D) _ - · rintro _ ⟨s, t, hs, ht, rfl⟩ + · rintro _ ⟨s, hs, t, ht, rfl⟩ haveI := h3D.sigmaFinite rw [h₁ s hs t ht, prod_prod] #align measure_theory.measure.prod_eq_generate_from MeasureTheory.Measure.prod_eq_generateFrom @@ -703,7 +703,7 @@ theorem prodAssoc_prod [SFinite τ] : isPiSystem_measurableSet isPiSystem_prod ((sFiniteSeq μ i.1.1)).toFiniteSpanningSetsIn ((sFiniteSeq ν i.1.2).toFiniteSpanningSetsIn.prod (sFiniteSeq τ i.2).toFiniteSpanningSetsIn) _).symm - rintro s hs _ ⟨t, u, ht, hu, rfl⟩; rw [mem_setOf_eq] at hs ht hu + rintro s hs _ ⟨t, ht, u, hu, rfl⟩; rw [mem_setOf_eq] at hs ht hu simp_rw [map_apply (MeasurableEquiv.measurable _) (hs.prod (ht.prod hu)), MeasurableEquiv.prodAssoc, MeasurableEquiv.coe_mk, Equiv.prod_assoc_preimage, prod_prod, mul_assoc] diff --git a/Mathlib/MeasureTheory/Function/Jacobian.lean b/Mathlib/MeasureTheory/Function/Jacobian.lean index 8cd27dd4d467d..014e914c37edf 100644 --- a/Mathlib/MeasureTheory/Function/Jacobian.lean +++ b/Mathlib/MeasureTheory/Function/Jacobian.lean @@ -326,7 +326,7 @@ theorem addHaar_image_le_mul_of_det_lt (A : E →L[ℝ] E) {m : ℝ≥0} intro x r xs r0 have K : f '' (s ∩ closedBall x r) ⊆ A '' closedBall 0 r + closedBall (f x) (ε * r) := by rintro y ⟨z, ⟨zs, zr⟩, rfl⟩ - apply Set.mem_add.2 ⟨A (z - x), f z - f x - A (z - x) + f x, _, _, _⟩ + apply Set.mem_add.2 ⟨A (z - x), _, f z - f x - A (z - x) + f x, _, _⟩ · apply mem_image_of_mem simpa only [dist_eq_norm, mem_closedBall, mem_closedBall_zero_iff, sub_zero] using zr · rw [mem_closedBall_iff_norm, add_sub_cancel] diff --git a/Mathlib/MeasureTheory/Measure/Haar/Basic.lean b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean index 90b69038490d5..ea0b2727ee528 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Basic.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean @@ -728,9 +728,8 @@ theorem div_mem_nhds_one_of_haar_pos (μ : Measure G) [IsHaarMeasure μ] [Locall suffices V ⊆ E / E from Filter.mem_of_superset hV1 this intro v hvV obtain ⟨x, hxK, hxvK⟩ : ∃ x : G, x ∈ {v} * K ∧ x ∈ K := Set.not_disjoint_iff.1 (hv v hvV) - refine' ⟨x, v⁻¹ * x, hKE hxvK, _, _⟩ - · apply hKE - simpa only [singleton_mul, image_mul_left, mem_preimage] using hxK + refine ⟨x, hKE hxvK, v⁻¹ * x, hKE ?_, ?_⟩ + · simpa only [singleton_mul, image_mul_left, mem_preimage] using hxK · simp only [div_eq_iff_eq_mul, ← mul_assoc, mul_right_inv, one_mul] #align measure_theory.measure.div_mem_nhds_one_of_haar_pos MeasureTheory.Measure.div_mem_nhds_one_of_haar_pos #align measure_theory.measure.sub_mem_nhds_zero_of_add_haar_pos MeasureTheory.Measure.sub_mem_nhds_zero_of_addHaar_pos diff --git a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean index 91b7fcd1d6cf1..f876a640205d2 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean @@ -102,7 +102,7 @@ lemma continuous_integral_apply_inv_mul · exact (hg.comp (continuous_snd.inv.mul continuous_fst)).continuousOn · intro p x hp hx contrapose! hx - refine ⟨p, p⁻¹ * x, hp, ?_, by simp⟩ + refine ⟨p, hp, p⁻¹ * x, ?_, by simp⟩ simpa only [Set.mem_inv, mul_inv_rev, inv_inv] using subset_tsupport _ hx exact A.continuousAt ht diff --git a/Mathlib/Order/Filter/NAry.lean b/Mathlib/Order/Filter/NAry.lean index 4fd8d3dbb9b5f..4c5d9b201dccd 100644 --- a/Mathlib/Order/Filter/NAry.lean +++ b/Mathlib/Order/Filter/NAry.lean @@ -37,17 +37,17 @@ variable {α α' β β' γ γ' δ δ' ε ε' : Type*} {m : α → β → γ} {f /-- The image of a binary function `m : α → β → γ` as a function `Filter α → Filter β → Filter γ`. Mathematically this should be thought of as the image of the corresponding function `α × β → γ`. -/ def map₂ (m : α → β → γ) (f : Filter α) (g : Filter β) : Filter γ := - ((f ×ˢ g).map (uncurry m)).copy { s | ∃ u v, u ∈ f ∧ v ∈ g ∧ image2 m u v ⊆ s } fun _ ↦ by - simp only [mem_map, mem_prod_iff, image2_subset_iff, prod_subset_iff, exists_and_left]; rfl + ((f ×ˢ g).map (uncurry m)).copy { s | ∃ u ∈ f, ∃ v ∈ g, image2 m u v ⊆ s } fun _ ↦ by + simp only [mem_map, mem_prod_iff, image2_subset_iff, prod_subset_iff]; rfl #align filter.map₂ Filter.map₂ @[simp 900] -theorem mem_map₂_iff : u ∈ map₂ m f g ↔ ∃ s t, s ∈ f ∧ t ∈ g ∧ image2 m s t ⊆ u := +theorem mem_map₂_iff : u ∈ map₂ m f g ↔ ∃ s ∈ f, ∃ t ∈ g, image2 m s t ⊆ u := Iff.rfl #align filter.mem_map₂_iff Filter.mem_map₂_iff theorem image2_mem_map₂ (hs : s ∈ f) (ht : t ∈ g) : image2 m s t ∈ map₂ m f g := - ⟨_, _, hs, ht, Subset.rfl⟩ + ⟨_, hs, _, ht, Subset.rfl⟩ #align filter.image2_mem_map₂ Filter.image2_mem_map₂ theorem map_prod_eq_map₂ (m : α → β → γ) (f : Filter α) (g : Filter β) : @@ -69,7 +69,7 @@ theorem map₂_mk_eq_prod (f : Filter α) (g : Filter β) : map₂ Prod.mk f 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⟩ theorem map₂_mono (hf : f₁ ≤ f₂) (hg : g₁ ≤ g₂) : map₂ m f₁ g₁ ≤ map₂ m f₂ g₂ := - fun _ ⟨s, t, hs, ht, hst⟩ => ⟨s, t, hf hs, hg ht, hst⟩ + fun _ ⟨s, hs, t, ht, hst⟩ => ⟨s, hf hs, t, hg ht, hst⟩ #align filter.map₂_mono Filter.map₂_mono theorem map₂_mono_left (h : g₁ ≤ g₂) : map₂ m f g₁ ≤ map₂ m f g₂ := @@ -83,7 +83,7 @@ theorem map₂_mono_right (h : f₁ ≤ f₂) : map₂ m f₁ g ≤ map₂ m f @[simp] theorem le_map₂_iff {h : Filter γ} : h ≤ map₂ m f g ↔ ∀ ⦃s⦄, s ∈ f → ∀ ⦃t⦄, t ∈ g → image2 m s t ∈ h := - ⟨fun H _ hs _ ht => H <| image2_mem_map₂ hs ht, fun H _ ⟨_, _, hs, ht, hu⟩ => + ⟨fun H _ hs _ ht => H <| image2_mem_map₂ hs ht, fun H _ ⟨_, hs, _, ht, hu⟩ => mem_of_superset (H hs ht) hu⟩ #align filter.le_map₂_iff Filter.le_map₂_iff @@ -261,8 +261,8 @@ theorem map_map₂_right_comm {m : α → β' → γ} {n : β → β'} {m' : α theorem map₂_distrib_le_left {m : α → δ → ε} {n : β → γ → δ} {m₁ : α → β → β'} {m₂ : α → γ → γ'} {n' : β' → γ' → ε} (h_distrib : ∀ a b c, m a (n b c) = n' (m₁ a b) (m₂ a c)) : map₂ m f (map₂ n g h) ≤ map₂ n' (map₂ m₁ f g) (map₂ m₂ f h) := by - rintro s ⟨t₁, t₂, ⟨u₁, v, hu₁, hv, ht₁⟩, ⟨u₂, w, hu₂, hw, ht₂⟩, hs⟩ - refine' ⟨u₁ ∩ u₂, _, inter_mem hu₁ hu₂, image2_mem_map₂ hv hw, _⟩ + rintro s ⟨t₁, ⟨u₁, hu₁, v, hv, ht₁⟩, t₂, ⟨u₂, hu₂, w, hw, ht₂⟩, hs⟩ + refine' ⟨u₁ ∩ u₂, inter_mem hu₁ hu₂, _, image2_mem_map₂ hv hw, _⟩ refine' (image2_distrib_subset_left h_distrib).trans ((image2_subset _ _).trans hs) · exact (image2_subset_right <| inter_subset_left _ _).trans ht₁ · exact (image2_subset_right <| inter_subset_right _ _).trans ht₂ @@ -272,8 +272,8 @@ theorem map₂_distrib_le_left {m : α → δ → ε} {n : β → γ → δ} {m theorem map₂_distrib_le_right {m : δ → γ → ε} {n : α → β → δ} {m₁ : α → γ → α'} {m₂ : β → γ → β'} {n' : α' → β' → ε} (h_distrib : ∀ a b c, m (n a b) c = n' (m₁ a c) (m₂ b c)) : map₂ m (map₂ n f g) h ≤ map₂ n' (map₂ m₁ f h) (map₂ m₂ g h) := by - rintro s ⟨t₁, t₂, ⟨u, w₁, hu, hw₁, ht₁⟩, ⟨v, w₂, hv, hw₂, ht₂⟩, hs⟩ - refine' ⟨_, w₁ ∩ w₂, image2_mem_map₂ hu hv, inter_mem hw₁ hw₂, _⟩ + rintro s ⟨t₁, ⟨u, hu, w₁, hw₁, ht₁⟩, t₂, ⟨v, hv, w₂, hw₂, ht₂⟩, hs⟩ + refine' ⟨_, image2_mem_map₂ hu hv, w₁ ∩ w₂, inter_mem hw₁ hw₂, _⟩ refine' (image2_distrib_subset_right h_distrib).trans ((image2_subset _ _).trans hs) · exact (image2_subset_left <| inter_subset_left _ _).trans ht₁ · exact (image2_subset_left <| inter_subset_right _ _).trans ht₂ diff --git a/Mathlib/Order/Filter/Pointwise.lean b/Mathlib/Order/Filter/Pointwise.lean index 928159c1d38e5..2674a16d28be7 100644 --- a/Mathlib/Order/Filter/Pointwise.lean +++ b/Mathlib/Order/Filter/Pointwise.lean @@ -292,7 +292,7 @@ variable [Mul α] [Mul β] {f f₁ f₂ g g₁ g₂ h : Filter α} {s t : Set α protected def instMul : Mul (Filter α) := ⟨/- This is defeq to `map₂ (· * ·) f g`, but the hypothesis unfolds to `t₁ * t₂ ⊆ s` rather than all the way to `Set.image2 (· * ·) t₁ t₂ ⊆ s`. -/ - fun f g => { map₂ (· * ·) f g with sets := { s | ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ * t₂ ⊆ s } }⟩ + fun f g => { map₂ (· * ·) f g with sets := { s | ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ * t₂ ⊆ s } }⟩ #align filter.has_mul Filter.instMul #align filter.has_add Filter.instAdd @@ -305,7 +305,7 @@ theorem map₂_mul : map₂ (· * ·) f g = f * g := #align filter.map₂_add Filter.map₂_add @[to_additive] -theorem mem_mul : s ∈ f * g ↔ ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ * t₂ ⊆ s := +theorem mem_mul : s ∈ f * g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ * t₂ ⊆ s := Iff.rfl #align filter.mem_mul Filter.mem_mul #align filter.mem_add Filter.mem_add @@ -437,7 +437,7 @@ variable [Div α] {f f₁ f₂ g g₁ g₂ h : Filter α} {s t : Set α} {a b : protected def instDiv : Div (Filter α) := ⟨/- This is defeq to `map₂ (· / ·) f g`, but the hypothesis unfolds to `t₁ / t₂ ⊆ s` rather than all the way to `Set.image2 (· / ·) t₁ t₂ ⊆ s`. -/ - fun f g => { map₂ (· / ·) f g with sets := { s | ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ / t₂ ⊆ s } }⟩ + fun f g => { map₂ (· / ·) f g with sets := { s | ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ / t₂ ⊆ s } }⟩ #align filter.has_div Filter.instDiv #align filter.has_sub Filter.instSub @@ -450,7 +450,7 @@ theorem map₂_div : map₂ (· / ·) f g = f / g := #align filter.map₂_sub Filter.map₂_sub @[to_additive] -theorem mem_div : s ∈ f / g ↔ ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ / t₂ ⊆ s := +theorem mem_div : s ∈ f / g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ / t₂ ⊆ s := Iff.rfl #align filter.mem_div Filter.mem_div #align filter.mem_sub Filter.mem_sub @@ -641,8 +641,8 @@ def mapMonoidHom [MonoidHomClass F α β] (φ : F) : Filter α →* Filter β wh -- The other direction does not hold in general @[to_additive] theorem comap_mul_comap_le [MulHomClass F α β] (m : F) {f g : Filter β} : - f.comap m * g.comap m ≤ (f * g).comap m := fun _ ⟨_, ⟨t₁, t₂, ht₁, ht₂, t₁t₂⟩, mt⟩ => - ⟨m ⁻¹' t₁, m ⁻¹' t₂, ⟨t₁, ht₁, Subset.rfl⟩, ⟨t₂, ht₂, Subset.rfl⟩, + f.comap m * g.comap m ≤ (f * g).comap m := fun _ ⟨_, ⟨t₁, ht₁, t₂, ht₂, t₁t₂⟩, mt⟩ => + ⟨m ⁻¹' t₁, ⟨t₁, ht₁, Subset.rfl⟩, m ⁻¹' t₂, ⟨t₂, ht₂, Subset.rfl⟩, (preimage_mul_preimage_subset _).trans <| (preimage_mono t₁t₂).trans mt⟩ #align filter.comap_mul_comap_le Filter.comap_mul_comap_le #align filter.comap_add_comap_le Filter.comap_add_comap_le @@ -761,7 +761,7 @@ variable [DivisionMonoid α] {f g : Filter α} @[to_additive] protected theorem mul_eq_one_iff : f * g = 1 ↔ ∃ a b, f = pure a ∧ g = pure b ∧ a * b = 1 := by refine' ⟨fun hfg => _, _⟩ - · obtain ⟨t₁, t₂, h₁, h₂, h⟩ : (1 : Set α) ∈ f * g := hfg.symm.subst one_mem_one + · obtain ⟨t₁, h₁, t₂, h₂, h⟩ : (1 : Set α) ∈ f * g := hfg.symm.subst one_mem_one have hfg : (f * g).NeBot := hfg.symm.subst one_neBot rw [(hfg.nonempty_of_mem <| mul_mem_mul h₁ h₂).subset_one_iff, Set.mul_eq_one_iff] at h obtain ⟨a, b, rfl, rfl, h⟩ := h @@ -849,13 +849,13 @@ variable [MulZeroClass α] {f g : Filter α} theorem NeBot.mul_zero_nonneg (hf : f.NeBot) : 0 ≤ f * 0 := le_mul_iff.2 fun _ h₁ _ h₂ => let ⟨_, ha⟩ := hf.nonempty_of_mem h₁ - ⟨_, _, ha, h₂, mul_zero _⟩ + ⟨_, ha, _, h₂, mul_zero _⟩ #align filter.ne_bot.mul_zero_nonneg Filter.NeBot.mul_zero_nonneg theorem NeBot.zero_mul_nonneg (hg : g.NeBot) : 0 ≤ 0 * g := le_mul_iff.2 fun _ h₁ _ h₂ => let ⟨_, hb⟩ := hg.nonempty_of_mem h₂ - ⟨_, _, h₁, hb, zero_mul _⟩ + ⟨_, h₁, _, hb, zero_mul _⟩ #align filter.ne_bot.zero_mul_nonneg Filter.NeBot.zero_mul_nonneg end MulZeroClass @@ -873,7 +873,7 @@ protected theorem one_le_div_iff : 1 ≤ f / g ↔ ¬Disjoint f g := by refine' ⟨fun h hfg => _, _⟩ · obtain ⟨s, hs, t, ht, hst⟩ := hfg.le_bot (mem_bot : ∅ ∈ ⊥) exact Set.one_mem_div_iff.1 (h <| div_mem_div hs ht) (disjoint_iff.2 hst.symm) - · rintro h s ⟨t₁, t₂, h₁, h₂, hs⟩ + · rintro h s ⟨t₁, h₁, t₂, h₂, hs⟩ exact hs (Set.one_mem_div_iff.2 fun ht => h <| disjoint_of_disjoint_of_mem ht h₁ h₂) #align filter.one_le_div_iff Filter.one_le_div_iff #align filter.nonneg_sub_iff Filter.nonneg_sub_iff @@ -886,7 +886,7 @@ theorem not_one_le_div_iff : ¬1 ≤ f / g ↔ Disjoint f g := @[to_additive] theorem NeBot.one_le_div (h : f.NeBot) : 1 ≤ f / f := by - rintro s ⟨t₁, t₂, h₁, h₂, hs⟩ + rintro s ⟨t₁, h₁, t₂, h₂, hs⟩ obtain ⟨a, ha₁, ha₂⟩ := Set.not_disjoint_iff.1 (h.not_disjoint h₁ h₂) rw [mem_one, ← div_self' a] exact hs (Set.div_mem_div ha₁ ha₂) @@ -940,13 +940,13 @@ variable [GroupWithZero α] {f g : Filter α} theorem NeBot.div_zero_nonneg (hf : f.NeBot) : 0 ≤ f / 0 := Filter.le_div_iff.2 fun _ h₁ _ h₂ => let ⟨_, ha⟩ := hf.nonempty_of_mem h₁ - ⟨_, _, ha, h₂, div_zero _⟩ + ⟨_, ha, _, h₂, div_zero _⟩ #align filter.ne_bot.div_zero_nonneg Filter.NeBot.div_zero_nonneg theorem NeBot.zero_div_nonneg (hg : g.NeBot) : 0 ≤ 0 / g := Filter.le_div_iff.2 fun _ h₁ _ h₂ => let ⟨_, hb⟩ := hg.nonempty_of_mem h₂ - ⟨_, _, h₁, hb, zero_div _⟩ + ⟨_, h₁, _, hb, zero_div _⟩ #align filter.ne_bot.zero_div_nonneg Filter.NeBot.zero_div_nonneg end GroupWithZero @@ -965,7 +965,7 @@ variable [SMul α β] {f f₁ f₂ : Filter α} {g g₁ g₂ h : Filter β} {s : protected def instSMul : SMul (Filter α) (Filter β) := ⟨/- This is defeq to `map₂ (· • ·) f g`, but the hypothesis unfolds to `t₁ • t₂ ⊆ s` rather than all the way to `Set.image2 (· • ·) t₁ t₂ ⊆ s`. -/ - fun f g => { map₂ (· • ·) f g with sets := { s | ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ • t₂ ⊆ s } }⟩ + fun f g => { map₂ (· • ·) f g with sets := { s | ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ • t₂ ⊆ s } }⟩ #align filter.has_smul Filter.instSMul #align filter.has_vadd Filter.instVAdd @@ -978,7 +978,7 @@ theorem map₂_smul : map₂ (· • ·) f g = f • g := #align filter.map₂_vadd Filter.map₂_vadd @[to_additive] -theorem mem_smul : t ∈ f • g ↔ ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ • t₂ ⊆ t := +theorem mem_smul : t ∈ f • g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ • t₂ ⊆ t := Iff.rfl #align filter.mem_smul Filter.mem_smul #align filter.mem_vadd Filter.mem_vadd @@ -1097,7 +1097,7 @@ variable [VSub α β] {f f₁ f₂ g g₁ g₂ : Filter β} {h : Filter α} {s t protected def instVSub : VSub (Filter α) (Filter β) := ⟨/- This is defeq to `map₂ (-ᵥ) f g`, but the hypothesis unfolds to `t₁ -ᵥ t₂ ⊆ s` rather than all the way to `Set.image2 (-ᵥ) t₁ t₂ ⊆ s`. -/ - fun f g => { map₂ (· -ᵥ ·) f g with sets := { s | ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ -ᵥ t₂ ⊆ s } }⟩ + fun f g => { map₂ (· -ᵥ ·) f g with sets := { s | ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ -ᵥ t₂ ⊆ s } }⟩ #align filter.has_vsub Filter.instVSub scoped[Pointwise] attribute [instance] Filter.instVSub @@ -1107,7 +1107,7 @@ theorem map₂_vsub : map₂ (· -ᵥ ·) f g = f -ᵥ g := rfl #align filter.map₂_vsub Filter.map₂_vsub -theorem mem_vsub {s : Set α} : s ∈ f -ᵥ g ↔ ∃ t₁ t₂, t₁ ∈ f ∧ t₂ ∈ g ∧ t₁ -ᵥ t₂ ⊆ s := +theorem mem_vsub {s : Set α} : s ∈ f -ᵥ g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ -ᵥ t₂ ⊆ s := Iff.rfl #align filter.mem_vsub Filter.mem_vsub @@ -1380,13 +1380,13 @@ because `0 * ⊥ ≠ 0`. theorem NeBot.smul_zero_nonneg (hf : f.NeBot) : 0 ≤ f • (0 : Filter β) := le_smul_iff.2 fun _ h₁ _ h₂ => let ⟨_, ha⟩ := hf.nonempty_of_mem h₁ - ⟨_, _, ha, h₂, smul_zero _⟩ + ⟨_, ha, _, h₂, smul_zero _⟩ #align filter.ne_bot.smul_zero_nonneg Filter.NeBot.smul_zero_nonneg theorem NeBot.zero_smul_nonneg (hg : g.NeBot) : 0 ≤ (0 : Filter α) • g := le_smul_iff.2 fun _ h₁ _ h₂ => let ⟨_, hb⟩ := hg.nonempty_of_mem h₂ - ⟨_, _, h₁, hb, zero_smul _ _⟩ + ⟨_, h₁, _, hb, zero_smul _ _⟩ #align filter.ne_bot.zero_smul_nonneg Filter.NeBot.zero_smul_nonneg theorem zero_smul_filter_nonpos : (0 : α) • g ≤ 0 := by diff --git a/Mathlib/Probability/Kernel/Disintegration.lean b/Mathlib/Probability/Kernel/Disintegration.lean index a328de26de972..58f9609b68d08 100644 --- a/Mathlib/Probability/Kernel/Disintegration.lean +++ b/Mathlib/Probability/Kernel/Disintegration.lean @@ -139,7 +139,7 @@ theorem lintegral_condKernelReal_mem {s : Set (α × ℝ)} (hs : MeasurableSet s apply MeasurableSpace.induction_on_inter generateFrom_prod.symm isPiSystem_prod _ _ _ _ hs · simp only [mem_empty_iff_false, setOf_false, measure_empty, lintegral_const, zero_mul] - · rintro _ ⟨t₁, t₂, ht₁, ht₂, rfl⟩ + · rintro _ ⟨t₁, ht₁, t₂, ht₂, rfl⟩ have h_prod_eq_snd : ∀ a ∈ t₁, {x : ℝ | (a, x) ∈ t₁ ×ˢ t₂} = t₂ := by intro a ha simp only [ha, prod_mk_mem_set_prod_eq, true_and_iff, setOf_mem_eq] diff --git a/Mathlib/RingTheory/Adjoin/FG.lean b/Mathlib/RingTheory/Adjoin/FG.lean index 02ad6b3cc20b3..96748cabc131b 100644 --- a/Mathlib/RingTheory/Adjoin/FG.lean +++ b/Mathlib/RingTheory/Adjoin/FG.lean @@ -77,7 +77,7 @@ theorem fg_trans (h1 : (adjoin R s).toSubmodule.FG) (h2 : (adjoin (adjoin R s) t change _ * _ ∈ _ rw [smul_mul_assoc] refine' smul_mem _ _ _ - exact subset_span ⟨t, z, hlp ht, hlq hz, rfl⟩ + exact subset_span ⟨t, hlp ht, z, hlq hz, rfl⟩ #align algebra.fg_trans Algebra.fg_trans end Algebra diff --git a/Mathlib/RingTheory/Adjoin/Tower.lean b/Mathlib/RingTheory/Adjoin/Tower.lean index a4ed9a297e08f..ad0ce756741ae 100644 --- a/Mathlib/RingTheory/Adjoin/Tower.lean +++ b/Mathlib/RingTheory/Adjoin/Tower.lean @@ -111,7 +111,7 @@ theorem exists_subalgebra_of_fg (hAC : (⊤ : Subalgebra A C).FG) (hBC : (⊤ : span (Algebra.adjoin A (↑s : Set B)) (↑(insert 1 y : Finset C) : Set C) ≤ span (Algebra.adjoin A (↑s : Set B)) (↑(insert 1 y : Finset C) : Set C) := by rw [span_mul_span, span_le, coe_insert] - rintro _ ⟨yi, yj, rfl | hyi, rfl | hyj, rfl⟩ <;> dsimp + rintro _ ⟨yi, rfl | hyi, yj, rfl | hyj, rfl⟩ <;> dsimp · rw [mul_one] exact subset_span (Set.mem_insert _ _) · rw [one_mul] diff --git a/Mathlib/RingTheory/HahnSeries.lean b/Mathlib/RingTheory/HahnSeries.lean index cb8ac26203e36..435fb14b91c90 100644 --- a/Mathlib/RingTheory/HahnSeries.lean +++ b/Mathlib/RingTheory/HahnSeries.lean @@ -993,7 +993,7 @@ theorem embDomain_mul [NonUnitalNonAssocSemiring R] (f : Γ ↪o Γ') exact ⟨i, j, h1, rfl⟩ · rw [embDomain_notin_range hg, eq_comm] contrapose! hg - obtain ⟨_, _, hi, hj, rfl⟩ := support_mul_subset_add_support ((mem_support _ _).2 hg) + obtain ⟨_, hi, _, hj, rfl⟩ := support_mul_subset_add_support ((mem_support _ _).2 hg) obtain ⟨i, _, rfl⟩ := support_embDomain_subset hi obtain ⟨j, _, rfl⟩ := support_embDomain_subset hj refine' ⟨i + j, hf i j⟩ @@ -1342,7 +1342,7 @@ theorem isPwo_iUnion_support_powers [LinearOrderedCancelAddCommMonoid Γ] [Ring · simp only [Nat.zero_eq, pow_zero, support_one, Set.mem_singleton_iff] at hn rw [hn, SetLike.mem_coe] exact AddSubmonoid.zero_mem _ - · obtain ⟨i, j, hi, hj, rfl⟩ := support_mul_subset_add_support hn + · obtain ⟨i, hi, j, hj, rfl⟩ := support_mul_subset_add_support hn exact SetLike.mem_coe.2 (AddSubmonoid.add_mem _ (AddSubmonoid.subset_closure hi) (ih hj)) #align hahn_series.is_pwo_Union_support_powers HahnSeries.isPwo_iUnion_support_powers @@ -1538,7 +1538,7 @@ instance : SMul (HahnSeries Γ R) (SummableFamily Γ R α) where fun a ha => _ · exact fun ij _ => Function.support fun a => (s a).coeff ij.2 · apply s.finite_co_support - · obtain ⟨i, j, hi, hj, rfl⟩ := support_mul_subset_add_support ha + · obtain ⟨i, hi, j, hj, rfl⟩ := support_mul_subset_add_support ha simp only [exists_prop, Set.mem_iUnion, mem_addAntidiagonal, mul_coeff, mem_support, isPwo_support, Prod.exists] exact ⟨i, j, mem_coe.2 (mem_addAntidiagonal.2 ⟨hi, Set.mem_iUnion.2 ⟨a, hj⟩, rfl⟩), hj⟩ } @@ -1729,7 +1729,7 @@ def powers (x : HahnSeries Γ R) (hx : 0 < addVal Γ R x) : SummableFamily Γ R _ · rintro (_ | n) hn · exact Set.mem_union_right _ (Set.mem_singleton 0) - · obtain ⟨i, j, hi, hj, rfl⟩ := support_mul_subset_add_support hn + · obtain ⟨i, hi, j, hj, rfl⟩ := support_mul_subset_add_support hn refine' Set.mem_union_left _ ⟨n, Set.mem_iUnion.2 ⟨⟨i, j⟩, Set.mem_iUnion.2 ⟨_, hj⟩⟩, rfl⟩ simp only [and_true_iff, Set.mem_iUnion, mem_addAntidiagonal, mem_coe, eq_self_iff_true, Ne.def, mem_support, Set.mem_setOf_eq] diff --git a/Mathlib/RingTheory/Ideal/Norm.lean b/Mathlib/RingTheory/Ideal/Norm.lean index 4100795d4f52f..500ebe4ccb616 100644 --- a/Mathlib/RingTheory/Ideal/Norm.lean +++ b/Mathlib/RingTheory/Ideal/Norm.lean @@ -580,7 +580,7 @@ theorem spanNorm_mul_spanNorm_le (I J : Ideal S) : spanNorm R I * spanNorm R J ≤ spanNorm R (I * J) := by rw [spanNorm, spanNorm, spanNorm, Ideal.span_mul_span', ← Set.image_mul] refine Ideal.span_mono (Set.monotone_image ?_) - rintro _ ⟨x, y, hxI, hyJ, rfl⟩ + rintro _ ⟨x, hxI, y, hyJ, rfl⟩ exact Ideal.mul_mem_mul hxI hyJ #align ideal.span_norm_mul_span_norm_le Ideal.spanNorm_mul_spanNorm_le diff --git a/Mathlib/Topology/Algebra/FilterBasis.lean b/Mathlib/Topology/Algebra/FilterBasis.lean index bcff36e5d098a..328542010c829 100644 --- a/Mathlib/Topology/Algebra/FilterBasis.lean +++ b/Mathlib/Topology/Algebra/FilterBasis.lean @@ -141,7 +141,7 @@ instance : Inhabited (GroupFilterBasis G) := ⟨by @[to_additive] theorem subset_mul_self (B : GroupFilterBasis G) {U : Set G} (h : U ∈ B) : U ⊆ U * U := - fun x x_in ↦ ⟨1, x, one h, x_in, one_mul x⟩ + fun x x_in ↦ ⟨1, one h, x, x_in, one_mul x⟩ #align group_filter_basis.prod_subset_self GroupFilterBasis.subset_mul_self #align add_group_filter_basis.sum_subset_self AddGroupFilterBasis.subset_add_self @@ -372,7 +372,7 @@ instance [DiscreteTopology R] : Inhabited (ModuleFilterBasis R M) := smul' := by rintro U (rfl : U ∈ {{(0 : M)}}) use univ, univ_mem, {0}, rfl - rintro a ⟨x, m, -, rfl, rfl⟩ + rintro a ⟨x, -, m, rfl, rfl⟩ simp only [smul_zero, mem_singleton_iff] smul_left' := by rintro x₀ U (h : U ∈ {{(0 : M)}}) diff --git a/Mathlib/Topology/Algebra/Group/Basic.lean b/Mathlib/Topology/Algebra/Group/Basic.lean index d088dae427535..0e5ea0011fc86 100644 --- a/Mathlib/Topology/Algebra/Group/Basic.lean +++ b/Mathlib/Topology/Algebra/Group/Basic.lean @@ -1030,7 +1030,7 @@ theorem TopologicalGroup.exists_antitone_basis_nhds_one : intro n rcases this n with ⟨j, k, -, h⟩ refine' atTop_basis.eventually_iff.mpr ⟨max j k, True.intro, fun m hm => _⟩ - rintro - ⟨a, b, ha, hb, rfl⟩ + rintro - ⟨a, ha, b, hb, rfl⟩ exact h a b (u_anti ((le_max_left _ _).trans hm) ha) (u_anti ((le_max_right _ _).trans hm) hb) obtain ⟨φ, -, hφ, φ_anti_basis⟩ := HasAntitoneBasis.subbasis_with_rel ⟨hu, u_anti⟩ event_mul exact ⟨u ∘ φ, φ_anti_basis, fun n => hφ n.lt_succ_self⟩ @@ -1257,7 +1257,7 @@ variable [TopologicalSpace α] [TopologicalSpace β] [Group α] [MulAction α β theorem IsClosed.smul_left_of_isCompact (ht : IsClosed t) (hs : IsCompact s) : IsClosed (s • t) := by have : ∀ x ∈ s • t, ∃ g ∈ s, g⁻¹ • x ∈ t := by - rintro x ⟨g, y, hgs, hyt, rfl⟩ + rintro x ⟨g, hgs, y, hyt, rfl⟩ refine ⟨g, hgs, ?_⟩ rwa [inv_smul_smul] choose! f hf using this @@ -1269,7 +1269,7 @@ theorem IsClosed.smul_left_of_isCompact (ht : IsClosed t) (hs : IsCompact s) : _ ≤ 𝓟 s := principal_mono.mpr (image_subset_iff.mpr (fun x hx ↦ (hf x hx).1)) rcases hs.ultrafilter_le_nhds (Ultrafilter.map f u) this with ⟨g, hg, hug⟩ suffices g⁻¹ • x ∈ t from - ⟨g, g⁻¹ • x, hg, this, smul_inv_smul _ _⟩ + ⟨g, hg, g⁻¹ • x, this, smul_inv_smul _ _⟩ exact ht.mem_of_tendsto ((Tendsto.inv hug).smul hux) (Eventually.mono hust (fun y hy ↦ (hf y hy).2)) @@ -1414,9 +1414,9 @@ theorem subset_interior_div : interior s / interior t ⊆ interior (s / t) := theorem IsOpen.mul_closure (hs : IsOpen s) (t : Set G) : s * closure t = s * t := by refine' (mul_subset_iff.2 fun a ha b hb => _).antisymm (mul_subset_mul_left subset_closure) rw [mem_closure_iff] at hb - have hbU : b ∈ s⁻¹ * {a * b} := ⟨a⁻¹, a * b, Set.inv_mem_inv.2 ha, rfl, inv_mul_cancel_left _ _⟩ - obtain ⟨_, ⟨c, d, hc, rfl : d = _, rfl⟩, hcs⟩ := hb _ hs.inv.mul_right hbU - exact ⟨c⁻¹, _, hc, hcs, inv_mul_cancel_left _ _⟩ + have hbU : b ∈ s⁻¹ * {a * b} := ⟨a⁻¹, Set.inv_mem_inv.2 ha, a * b, rfl, inv_mul_cancel_left _ _⟩ + obtain ⟨_, ⟨c, hc, d, rfl : d = _, rfl⟩, hcs⟩ := hb _ hs.inv.mul_right hbU + exact ⟨c⁻¹, hc, _, hcs, inv_mul_cancel_left _ _⟩ #align is_open.mul_closure IsOpen.mul_closure #align is_open.add_closure IsOpen.add_closure @@ -1491,12 +1491,12 @@ lemma IsClosed.mul_closure_one_eq {F : Set G} (hF : IsClosed F) : lemma compl_mul_closure_one_eq {t : Set G} (ht : t * (closure {1} : Set G) = t) : tᶜ * (closure {1} : Set G) = tᶜ := by refine Subset.antisymm ?_ (subset_mul_closure_one tᶜ) - rintro - ⟨x, g, hx, hg, rfl⟩ + rintro - ⟨x, hx, g, hg, rfl⟩ by_contra H have : x ∈ t * (closure {1} : Set G) := by rw [← Subgroup.coe_topologicalClosure_bot G] at hg ⊢ simp only [smul_eq_mul, mem_compl_iff, not_not] at H - exact ⟨x * g, g⁻¹, H, Subgroup.inv_mem _ hg, by simp⟩ + exact ⟨x * g, H, g⁻¹, Subgroup.inv_mem _ hg, by simp⟩ rw [ht] at this exact hx this @@ -1760,7 +1760,7 @@ theorem exists_disjoint_smul_of_isCompact [NoncompactSpace G] {K L : Set G} (hK refine' ⟨g, _⟩ refine disjoint_left.2 fun a ha h'a => hg ?_ rcases h'a with ⟨b, bL, rfl⟩ - refine' ⟨g * b, b⁻¹, ha, by simpa only [Set.mem_inv, inv_inv] using bL, _⟩ + refine' ⟨g * b, ha, b⁻¹, by simpa only [Set.mem_inv, inv_inv] using bL, _⟩ simp only [smul_eq_mul, mul_inv_cancel_right] #align exists_disjoint_smul_of_is_compact exists_disjoint_smul_of_isCompact #align exists_disjoint_vadd_of_is_compact exists_disjoint_vadd_of_isCompact diff --git a/Mathlib/Topology/Algebra/Monoid.lean b/Mathlib/Topology/Algebra/Monoid.lean index fddb9fa902076..be51f141e72fd 100644 --- a/Mathlib/Topology/Algebra/Monoid.lean +++ b/Mathlib/Topology/Algebra/Monoid.lean @@ -419,7 +419,7 @@ theorem Submonoid.top_closure_mul_self_subset (s : Submonoid M) : theorem Submonoid.top_closure_mul_self_eq (s : Submonoid M) : _root_.closure (s : Set M) * _root_.closure s = _root_.closure s := Subset.antisymm s.top_closure_mul_self_subset fun x hx => - ⟨x, 1, hx, _root_.subset_closure s.one_mem, mul_one _⟩ + ⟨x, hx, 1, _root_.subset_closure s.one_mem, mul_one _⟩ #align submonoid.top_closure_mul_self_eq Submonoid.top_closure_mul_self_eq #align add_submonoid.top_closure_add_self_eq AddSubmonoid.top_closure_add_self_eq @@ -430,7 +430,7 @@ itself a submonoid. -/ def Submonoid.topologicalClosure (s : Submonoid M) : Submonoid M where carrier := _root_.closure (s : Set M) one_mem' := _root_.subset_closure s.one_mem - mul_mem' ha hb := s.top_closure_mul_self_subset ⟨_, _, ha, hb, rfl⟩ + mul_mem' ha hb := s.top_closure_mul_self_subset ⟨_, ha, _, hb, rfl⟩ #align submonoid.topological_closure Submonoid.topologicalClosure #align add_submonoid.topological_closure AddSubmonoid.topologicalClosure @@ -508,7 +508,7 @@ theorem exists_open_nhds_one_mul_subset {U : Set M} (hU : U ∈ 𝓝 (1 : M)) : ∃ V : Set M, IsOpen V ∧ (1 : M) ∈ V ∧ V * V ⊆ U := by rcases exists_open_nhds_one_split hU with ⟨V, Vo, V1, hV⟩ use V, Vo, V1 - rintro _ ⟨x, y, hx, hy, rfl⟩ + rintro _ ⟨x, hx, y, hy, rfl⟩ exact hV _ hx _ hy #align exists_open_nhds_one_mul_subset exists_open_nhds_one_mul_subset #align exists_open_nhds_zero_add_subset exists_open_nhds_zero_add_subset diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/AdicTopology.lean b/Mathlib/Topology/Algebra/Nonarchimedean/AdicTopology.lean index af02d73ea693a..2d2ef70c73ba3 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/AdicTopology.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/AdicTopology.lean @@ -70,7 +70,7 @@ theorem adic_basis (I : Ideal R) : SubmodulesRingBasis fun n : ℕ => (I ^ n • simpa only [smul_top_eq_map, Algebra.id.map_eq_id, map_id] using this intro n use n - rintro a ⟨x, b, _hx, hb, rfl⟩ + rintro a ⟨x, _hx, b, hb, rfl⟩ exact (I ^ n).smul_mem x hb } #align ideal.adic_basis Ideal.adic_basis diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean index 216b486b39f63..f9fa2baceaa4f 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean @@ -84,7 +84,7 @@ def toRingFilterBasis [Nonempty ι] {B : ι → AddSubgroup A} (hB : RingSubgrou use B i constructor · use i - · rintro x ⟨y, z, y_in, z_in, rfl⟩ + · rintro x ⟨y, y_in, z, z_in, rfl⟩ exact (B i).add_mem y_in z_in neg' := by rintro _ ⟨i, rfl⟩ @@ -276,7 +276,7 @@ def toModuleFilterBasis : ModuleFilterBasis R M where use B i constructor · use i - · rintro x ⟨y, z, y_in, z_in, rfl⟩ + · rintro x ⟨y, y_in, z, z_in, rfl⟩ exact (B i).add_mem y_in z_in neg' := by rintro _ ⟨i, rfl⟩ @@ -299,7 +299,7 @@ def toModuleFilterBasis : ModuleFilterBasis R M where · use B i constructor · use i - · rintro _ ⟨a, m, -, hm, rfl⟩ + · rintro _ ⟨a, -, m, hm, rfl⟩ exact (B i).smul_mem _ hm smul_left' := by rintro x₀ _ ⟨i, rfl⟩ diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean index 0ec8fc0d61b1c..66762d4acc7ca 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean @@ -145,7 +145,7 @@ theorem mul_subset (U : OpenAddSubgroup R) : ∃ V : OpenAddSubgroup R, (V : Set let ⟨V, H⟩ := prod_self_subset <| (U.isOpen.preimage continuous_mul).mem_nhds <| by simpa only [Set.mem_preimage, Prod.snd_zero, mul_zero] using U.zero_mem use V - rintro v ⟨a, b, ha, hb, hv⟩ + rintro v ⟨a, ha, b, hb, hv⟩ have hy := H (Set.mk_mem_prod ha hb) simp only [Set.mem_preimage, SetLike.mem_coe, hv] at hy rw [SetLike.mem_coe] diff --git a/Mathlib/Topology/Algebra/UniformGroup.lean b/Mathlib/Topology/Algebra/UniformGroup.lean index 0d8ac0be372b4..154cb79396d4e 100644 --- a/Mathlib/Topology/Algebra/UniformGroup.lean +++ b/Mathlib/Topology/Algebra/UniformGroup.lean @@ -961,7 +961,7 @@ instance QuotientGroup.completeSpace' (G : Type u) [Group G] [TopologicalSpace G exact fun m => ⟨m, fun n hmn => Nat.decreasingInduction' - (fun k _ _ hk => u_mul k ⟨_, _, hx' k, hk, div_mul_div_cancel' _ _ _⟩) hmn + (fun k _ _ hk => u_mul k ⟨_, hx' k, _, hk, div_mul_div_cancel' _ _ _⟩) hmn (by simpa only [div_self'] using mem_of_mem_nhds (hu.mem _))⟩ /- Since `G` is complete, `x'` converges to some `x₀`, and so the image of this sequence under the quotient map converges to `↑x₀`. The image of `x'` is a convergent subsequence of `x`, and diff --git a/Mathlib/Topology/Algebra/Valuation.lean b/Mathlib/Topology/Algebra/Valuation.lean index 2c9d5c685d1a0..4fca4fa70849f 100644 --- a/Mathlib/Topology/Algebra/Valuation.lean +++ b/Mathlib/Topology/Algebra/Valuation.lean @@ -45,7 +45,7 @@ theorem subgroups_basis : RingSubgroupsBasis fun γ : Γ₀ˣ => (v.ltAddSubgrou rintro γ cases' exists_square_le γ with γ₀ h use γ₀ - rintro - ⟨r, s, r_in, s_in, rfl⟩ + rintro - ⟨r, r_in, s, s_in, rfl⟩ calc (v (r * s) : Γ₀) = v r * v s := Valuation.map_mul _ _ _ _ < γ₀ * γ₀ := (mul_lt_mul₀ r_in s_in) diff --git a/Mathlib/Topology/Bases.lean b/Mathlib/Topology/Bases.lean index 2643fbea748ed..7cd5f90c3210d 100644 --- a/Mathlib/Topology/Bases.lean +++ b/Mathlib/Topology/Bases.lean @@ -252,7 +252,7 @@ protected theorem IsTopologicalBasis.prod {β} [TopologicalSpace β] {B₁ : Set {B₂ : Set (Set β)} (h₁ : IsTopologicalBasis B₁) (h₂ : IsTopologicalBasis B₂) : IsTopologicalBasis (image2 (· ×ˢ ·) B₁ B₂) := by refine' isTopologicalBasis_of_isOpen_of_nhds _ _ - · rintro _ ⟨u₁, u₂, hu₁, hu₂, rfl⟩ + · rintro _ ⟨u₁, hu₁, u₂, hu₂, rfl⟩ exact (h₁.isOpen hu₁).prod (h₂.isOpen hu₂) · rintro ⟨a, b⟩ u hu uo rcases (h₁.nhds_hasBasis.prod_nhds h₂.nhds_hasBasis).mem_iff.1 (IsOpen.mem_nhds uo hu) with diff --git a/Mathlib/Topology/EMetricSpace/Lipschitz.lean b/Mathlib/Topology/EMetricSpace/Lipschitz.lean index 56cb78e81e633..ffedc002aa0ca 100644 --- a/Mathlib/Topology/EMetricSpace/Lipschitz.lean +++ b/Mathlib/Topology/EMetricSpace/Lipschitz.lean @@ -337,12 +337,11 @@ protected theorem prod {g : α → γ} {Kf Kg : ℝ≥0} (hf : LipschitzOnWith K exact max_le_max (hf hx hy) (hg hx hy) theorem ediam_image2_le (f : α → β → γ) {K₁ K₂ : ℝ≥0} (s : Set α) (t : Set β) - (hf₁ : ∀ b ∈ t, LipschitzOnWith K₁ (fun a => f a b) s) - (hf₂ : ∀ a ∈ s, LipschitzOnWith K₂ (f a) t) : + (hf₁ : ∀ b ∈ t, LipschitzOnWith K₁ (f · b) s) (hf₂ : ∀ a ∈ s, LipschitzOnWith K₂ (f a) t) : EMetric.diam (Set.image2 f s t) ≤ ↑K₁ * EMetric.diam s + ↑K₂ * EMetric.diam t := by - apply EMetric.diam_le - rintro _ ⟨a₁, b₁, ha₁, hb₁, rfl⟩ _ ⟨a₂, b₂, ha₂, hb₂, rfl⟩ - refine' (edist_triangle _ (f a₂ b₁) _).trans _ + simp only [EMetric.diam_le_iff, forall_image2_iff] + intro a₁ ha₁ b₁ hb₁ a₂ ha₂ b₂ hb₂ + refine (edist_triangle _ (f a₂ b₁) _).trans ?_ exact add_le_add ((hf₁ b₁ hb₁ ha₁ ha₂).trans <| ENNReal.mul_left_mono <| EMetric.edist_le_diam_of_mem ha₁ ha₂) From b8c97409df1dff19485c7da48e32f77aa198965f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagur=20T=C3=B3mas=20=C3=81sgeirsson?= Date: Fri, 29 Dec 2023 07:09:08 +0000 Subject: [PATCH 272/353] feat(Topology): clopen subsets of products of compact spaces are unions of clopen boxes (#8678) Co-authored-by: Yury G. Kudryashov --- Mathlib.lean | 1 + Mathlib/Topology/ClopenBox.lean | 75 +++++++++++++++++++++++++++++ Mathlib/Topology/CompactOpen.lean | 11 ++++- Mathlib/Topology/Constructions.lean | 6 +++ Mathlib/Topology/Sets/Closeds.lean | 11 +++++ docs/references.bib | 30 ++++++++++++ 6 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 Mathlib/Topology/ClopenBox.lean diff --git a/Mathlib.lean b/Mathlib.lean index 72f713857128d..47182459bee85 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3550,6 +3550,7 @@ import Mathlib.Topology.Category.TopCat.Opens import Mathlib.Topology.Category.TopCommRingCat import Mathlib.Topology.Category.UniformSpace import Mathlib.Topology.Clopen +import Mathlib.Topology.ClopenBox import Mathlib.Topology.CompactOpen import Mathlib.Topology.Compactification.OnePoint import Mathlib.Topology.Compactness.Compact diff --git a/Mathlib/Topology/ClopenBox.lean b/Mathlib/Topology/ClopenBox.lean new file mode 100644 index 0000000000000..cfabbc59341ab --- /dev/null +++ b/Mathlib/Topology/ClopenBox.lean @@ -0,0 +1,75 @@ +/- +Copyright (c) 2023 Dagur Asgeirsson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Dagur Asgeirsson +-/ +import Mathlib.Topology.CompactOpen +import Mathlib.Topology.Sets.Closeds + +/-! +# Clopen subsets in cartesian products + +In general, a clopen subset in a cartesian product of topological spaces +cannot be written as a union of "clopen boxes", +i.e. products of clopen subsets of the components (see [buzyakovaClopenBox] for counterexamples). + +However, when one of the factors is compact, a clopen subset can be written as such a union. +Our argument in `TopologicalSpace.Clopens.exists_prod_subset` +follows the one given in [buzyakovaClopenBox]. + +We deduce that in a product of compact spaces, a clopen subset is a finite union of clopen boxes, +and use that to prove that the property of having countably many clopens is preserved by taking +cartesian products of compact spaces (this is relevant to the theory of light profinite sets). + +## References + +- [buzyakovaClopenBox]: *On clopen sets in Cartesian products*, 2001. +- [engelking1989]: *General Topology*, 1989. + +-/ + +open Function Set Filter TopologicalSpace +open scoped Topology + +variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] [CompactSpace Y] + +theorem TopologicalSpace.Clopens.exists_prod_subset (W : Clopens (X × Y)) {a : X × Y} (h : a ∈ W) : + ∃ U : Clopens X, a.1 ∈ U ∧ ∃ V : Clopens Y, a.2 ∈ V ∧ U ×ˢ V ≤ W := by + have hp : Continuous (fun y : Y ↦ (a.1, y)) := Continuous.Prod.mk _ + let V : Set Y := {y | (a.1, y) ∈ W} + have hV : IsCompact V := (W.2.2.preimage hp).isCompact + let U : Set X := {x | MapsTo (Prod.mk x) V W} + have hUV : U ×ˢ V ⊆ W := fun ⟨_, _⟩ hw ↦ hw.1 hw.2 + exact ⟨⟨U, (ContinuousMap.isClopen_setOf_mapsTo hV W.2).preimage + (ContinuousMap.id (X × Y)).curry.2⟩, by simp [MapsTo], ⟨V, W.2.preimage hp⟩, h, hUV⟩ + +variable [CompactSpace X] + +/-- Every clopen set in a product of two compact spaces +is a union of finitely many clopen boxes. -/ +theorem TopologicalSpace.Clopens.exists_finset_eq_sup_prod (W : Clopens (X × Y)) : + ∃ (I : Finset (Clopens X × Clopens Y)), W = I.sup fun i ↦ i.1 ×ˢ i.2 := by + choose! U hxU V hxV hUV using fun x ↦ W.exists_prod_subset (a := x) + rcases W.2.2.isCompact.elim_nhds_subcover (fun x ↦ U x ×ˢ V x) (fun x hx ↦ + (U x ×ˢ V x).2.isOpen.mem_nhds ⟨hxU x hx, hxV x hx⟩) with ⟨I, hIW, hWI⟩ + classical + use I.image fun x ↦ (U x, V x) + rw [Finset.sup_image] + refine le_antisymm (fun x hx ↦ ?_) (Finset.sup_le fun x hx ↦ ?_) + · rcases Set.mem_iUnion₂.1 (hWI hx) with ⟨i, hi, hxi⟩ + exact SetLike.le_def.1 (Finset.le_sup hi) hxi + · exact hUV _ <| hIW _ hx + +lemma TopologicalSpace.Clopens.surjective_finset_sup_prod : + Surjective fun I : Finset (Clopens X × Clopens Y) ↦ I.sup fun i ↦ i.1 ×ˢ i.2 := fun W ↦ + let ⟨I, hI⟩ := W.exists_finset_eq_sup_prod; ⟨I, hI.symm⟩ + +instance TopologicalSpace.Clopens.countable_prod [Countable (Clopens X)] + [Countable (Clopens Y)] : Countable (Clopens (X × Y)) := + surjective_finset_sup_prod.countable + +instance TopologicalSpace.Clopens.finite_prod [Finite (Clopens X)] [Finite (Clopens Y)] : + Finite (Clopens (X × Y)) := by + cases nonempty_fintype (Clopens X) + cases nonempty_fintype (Clopens Y) + exact .of_surjective _ surjective_finset_sup_prod diff --git a/Mathlib/Topology/CompactOpen.lean b/Mathlib/Topology/CompactOpen.lean index b11b67ec160c3..d044be2f36e68 100644 --- a/Mathlib/Topology/CompactOpen.lean +++ b/Mathlib/Topology/CompactOpen.lean @@ -210,6 +210,14 @@ theorem continuous_coe : Continuous ((⇑) : C(α, β) → (α → β)) := #align continuous_map.continuous_coe' ContinuousMap.continuous_coe #align continuous_map.continuous_coe ContinuousMap.continuous_coe +lemma isClosed_setOf_mapsTo {t : Set β} (ht : IsClosed t) (s : Set α) : + IsClosed {f : C(α, β) | MapsTo f s t} := + ht.setOf_mapsTo fun _ _ ↦ continuous_eval_const _ + +lemma isClopen_setOf_mapsTo {K : Set α} (hK : IsCompact K) {U : Set β} (hU : IsClopen U) : + IsClopen {f : C(α, β) | MapsTo f K U} := + ⟨isOpen_setOf_mapsTo hK hU.isOpen, isClosed_setOf_mapsTo hU.isClosed K⟩ + instance [T0Space β] : T0Space C(α, β) := t0Space_of_injective_of_continuous FunLike.coe_injective continuous_coe @@ -361,8 +369,7 @@ def curry' (f : C(α × β, γ)) (a : α) : C(β, γ) := /-- If a map `α × β → γ` is continuous, then its curried form `α → C(β, γ)` is continuous. -/ theorem continuous_curry' (f : C(α × β, γ)) : Continuous (curry' f) := - have hf : curry' f = ContinuousMap.comp f ∘ coev _ _ := by ext; rfl - hf ▸ Continuous.comp (continuous_comp f) continuous_coev + Continuous.comp (continuous_comp f) continuous_coev #align continuous_map.continuous_curry' ContinuousMap.continuous_curry' /-- To show continuity of a map `α → C(β, γ)`, it suffices to show that its uncurried form diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index b24f17c03d94f..45b02b3ea94fa 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -415,6 +415,12 @@ theorem Continuous.Prod.mk_left (b : β) : Continuous fun a : α => (a, b) := continuous_id.prod_mk continuous_const #align continuous.prod.mk_left Continuous.Prod.mk_left +/-- If `f x y` is continuous in `x` for all `y ∈ s`, +then the set of `x` such that `f x` maps `s` to `t` is closed. -/ +lemma IsClosed.setOf_mapsTo {f : α → β → γ} {s : Set β} {t : Set γ} (ht : IsClosed t) + (hf : ∀ y ∈ s, Continuous (f · y)) : IsClosed {x | MapsTo (f x) s t} := by + simpa only [MapsTo, setOf_forall] using isClosed_biInter fun y hy ↦ ht.preimage (hf y hy) + theorem Continuous.comp₂ {g : α × β → γ} (hg : Continuous g) {e : δ → α} (he : Continuous e) {f : δ → β} (hf : Continuous f) : Continuous fun x => g (e x, f x) := hg.comp <| he.prod_mk hf diff --git a/Mathlib/Topology/Sets/Closeds.lean b/Mathlib/Topology/Sets/Closeds.lean index e514b753b5060..2311868fdb964 100644 --- a/Mathlib/Topology/Sets/Closeds.lean +++ b/Mathlib/Topology/Sets/Closeds.lean @@ -315,6 +315,8 @@ theorem coe_mk (s : Set α) (h) : (mk s h : Set α) = s := rfl #align topological_space.clopens.coe_mk TopologicalSpace.Clopens.coe_mk +@[simp] lemma mem_mk {s : Set α} {x h} : x ∈ mk s h ↔ x ∈ s := .rfl + instance : Sup (Clopens α) := ⟨fun s t => ⟨s ∪ t, s.isClopen.union t.isClopen⟩⟩ instance : Inf (Clopens α) := ⟨fun s t => ⟨s ∩ t, s.isClopen.inter t.isClopen⟩⟩ instance : Top (Clopens α) := ⟨⟨⊤, isClopen_univ⟩⟩ @@ -346,6 +348,15 @@ instance : BooleanAlgebra (Clopens α) := instance : Inhabited (Clopens α) := ⟨⊥⟩ +variable [TopologicalSpace β] + +instance : SProd (Clopens α) (Clopens β) (Clopens (α × β)) where + sprod s t := ⟨s ×ˢ t, s.2.prod t.2⟩ + +@[simp] +protected lemma mem_prod {s : Clopens α} {t : Clopens β} {x : α × β} : + x ∈ s ×ˢ t ↔ x.1 ∈ s ∧ x.2 ∈ t := .rfl + end Clopens end TopologicalSpace diff --git a/docs/references.bib b/docs/references.bib index 90b6a3d6c8171..cd20bf7e61a75 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -504,6 +504,20 @@ @Article{ bruhnDiestelKriesselPendavinghWollan2013 url = {https://www.sciencedirect.com/science/article/pii/S0001870813000261} } +@Article{ buzyakovaClopenBox, + author = {Buzyakova, Raushan Z.}, + title = {On clopen sets in {C}artesian products}, + journal = {Comment. Math. Univ. Carolin.}, + fjournal = {Commentationes Mathematicae Universitatis Carolinae}, + volume = {42}, + year = {2001}, + number = {2}, + pages = {357--362}, + issn = {0010-2628,1213-7243}, + mrclass = {54B10 (54B15 54D20 55M10)}, + mrnumber = {1832154} +} + @Book{ cabreragarciarodriguezpalacios2014, author = {Miguel {Cabrera Garc\'{\i}a} and \'Angel {Rodr\'{\i}guez Palacios}}, @@ -933,6 +947,22 @@ @Book{ engel1997 year = {1997} } +@Book{ engelking1989, + title = {General topology}, + author = {Engelking, Ryszard}, + series = {Sigma Series in Pure Mathematics}, + volume = {6}, + edition = {Second}, + note = {Translated from the Polish by the author}, + publisher = {Heldermann Verlag, Berlin}, + year = {1989}, + pages = {viii+529}, + isbn = {3-88538-006-4}, + mrclass = {54-01 (54-02)}, + mrnumber = {1039321}, + mrreviewer = {Gary\ Gruenhage} +} + @Article{ erdosrenyisos, author = {P. Erd\"os, A.R\'enyi, and V. S\'os}, title = {On a problem of graph theory}, From e04a464df1da4a130b5fa9aaff1dcf79d92d3888 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Fri, 29 Dec 2023 07:09:09 +0000 Subject: [PATCH 273/353] style: use `cases x with | ...` instead of `cases x; case => ...` (#9321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This converts usages of the pattern ```lean cases h case inl h' => ... case inr h' => ... ``` which derive from mathported code, to the "structured `cases`" syntax: ```lean cases h with | inl h' => ... | inr h' => ... ``` The case where the subgoals are handled with `·` instead of `case` is more contentious (and much more numerous) so I left those alone. This pattern also appears with `cases'`, `induction`, `induction'`, and `rcases`. Furthermore, there is a similar transformation for `by_cases`: ```lean by_cases h : cond case pos => ... case neg => ... ``` is replaced by: ```lean if h : cond then ... else ... ``` Co-authored-by: Mario Carneiro --- Archive/Arithcc.lean | 18 +- Archive/Imo/Imo1962Q1.lean | 8 +- Mathlib/Algebra/Associated.lean | 22 +- Mathlib/Algebra/CharP/ExpChar.lean | 6 +- .../Computation/Approximations.lean | 24 +- .../Computation/TerminatesIffRat.lean | 18 +- .../ContinuedFractions/ConvergentsEquiv.lean | 48 ++-- .../ContinuedFractions/TerminatedStable.lean | 12 +- Mathlib/Algebra/FreeAlgebra.lean | 10 +- Mathlib/Algebra/GroupPower/Lemmas.lean | 8 +- Mathlib/Algebra/Lie/Free.lean | 14 +- Mathlib/Algebra/Module/LinearMap.lean | 8 +- .../Analysis/Calculus/Deriv/Polynomial.lean | 7 +- .../Convex/SpecificFunctions/Pow.lean | 24 +- .../Analysis/SpecialFunctions/Log/Basic.lean | 6 +- .../Analysis/SpecialFunctions/Pow/NNReal.lean | 18 +- .../Limits/ConcreteCategory.lean | 10 +- Mathlib/CategoryTheory/Limits/Final.lean | 10 +- .../Computability/AkraBazzi/AkraBazzi.lean | 56 ++-- .../AkraBazzi/GrowsPolynomially.lean | 88 +++--- Mathlib/Computability/Halting.lean | 8 +- Mathlib/Computability/PartrecCode.lean | 175 ++++++----- Mathlib/Computability/Primrec.lean | 28 +- Mathlib/Computability/RegularExpressions.lean | 20 +- Mathlib/Computability/TMToPartrec.lean | 271 ++++++++---------- Mathlib/Computability/TuringMachine.lean | 143 ++++----- Mathlib/Control/Fold.lean | 6 +- Mathlib/Data/List/BigOperators/Basic.lean | 8 +- Mathlib/Data/List/EditDistance/Defs.lean | 31 +- Mathlib/Data/List/Func.lean | 24 +- Mathlib/Data/List/Perm.lean | 35 ++- Mathlib/Data/List/Sublists.lean | 10 +- Mathlib/Data/Multiset/Basic.lean | 20 +- Mathlib/Data/Multiset/Bind.lean | 6 +- Mathlib/Data/Multiset/Functor.lean | 10 +- Mathlib/Data/Multiset/Sections.lean | 6 +- Mathlib/Data/MvPolynomial/Basic.lean | 8 +- Mathlib/Data/Nat/Choose/Sum.lean | 5 +- Mathlib/Data/Nat/Factorization/Basic.lean | 56 ++-- Mathlib/Data/Nat/ForSqrt.lean | 31 +- Mathlib/Data/Nat/GCD/Basic.lean | 6 +- Mathlib/Data/Num/Lemmas.lean | 6 +- .../QPF/Multivariate/Constructions/Cofix.lean | 6 +- .../QPF/Multivariate/Constructions/Fix.lean | 17 +- Mathlib/Data/QPF/Univariate/Basic.lean | 16 +- Mathlib/Data/Set/Enumerate.lean | 31 +- Mathlib/Data/Stream/Init.lean | 5 +- Mathlib/Data/TypeVec.lean | 30 +- Mathlib/Data/Vector/Basic.lean | 6 +- Mathlib/Data/Vector/MapLemmas.lean | 14 +- Mathlib/Data/Vector/Snoc.lean | 12 +- Mathlib/Deprecated/Submonoid.lean | 8 +- Mathlib/FieldTheory/PerfectClosure.lean | 16 +- Mathlib/GroupTheory/Coprod/Basic.lean | 6 +- Mathlib/GroupTheory/FreeGroup/Basic.lean | 82 +++--- Mathlib/Init/Data/Nat/Bitwise.lean | 22 +- Mathlib/Init/Data/Nat/Lemmas.lean | 30 +- Mathlib/Init/Order/Defs.lean | 2 +- .../CliffordAlgebra/Conjugation.lean | 10 +- .../LinearAlgebra/CliffordAlgebra/Equivs.lean | 40 +-- .../CliffordAlgebra/EvenEquiv.lean | 10 +- Mathlib/Logic/Denumerable.lean | 6 +- Mathlib/Logic/Hydra.lean | 6 +- Mathlib/Logic/Relation.lean | 106 +++---- .../Constructions/BorelSpace/Basic.lean | 11 +- Mathlib/MeasureTheory/Integral/Marginal.lean | 12 +- .../Integral/MeanInequalities.lean | 6 +- Mathlib/ModelTheory/Satisfiability.lean | 6 +- Mathlib/ModelTheory/Ultraproducts.lean | 9 +- Mathlib/Order/Atoms.lean | 12 +- Mathlib/Order/Chain.lean | 24 +- Mathlib/Order/CompleteBooleanAlgebra.lean | 11 +- Mathlib/Order/Filter/Basic.lean | 22 +- Mathlib/RingTheory/Int/Basic.lean | 6 +- Mathlib/RingTheory/PrincipalIdealDomain.lean | 6 +- Mathlib/Topology/Connected/Basic.lean | 18 +- Mathlib/Topology/EMetricSpace/Basic.lean | 6 +- Mathlib/Topology/Irreducible.lean | 6 +- Mathlib/Topology/List.lean | 12 +- .../Topology/Order/LowerUpperTopology.lean | 10 +- 80 files changed, 957 insertions(+), 1029 deletions(-) diff --git a/Archive/Arithcc.lean b/Archive/Arithcc.lean index fc77d0c0749f0..557ee58d825ae 100644 --- a/Archive/Arithcc.lean +++ b/Archive/Arithcc.lean @@ -303,23 +303,21 @@ theorem write_eq_implies_stateEq {t : Register} {v : Word} {ζ₁ ζ₂ : State} Unlike Theorem 1 in the paper, both `map` and the assumption on `t` are explicit. -/ -theorem compiler_correctness : - ∀ (map : Identifier → Register) (e : Expr) (ξ : Identifier → Word) (η : State) (t : Register), - (∀ x, read (loc x map) η = ξ x) → - (∀ x, loc x map < t) → outcome (compile map e t) η ≃[t] { η with ac := value e ξ } := by - intro map e ξ η t hmap ht - revert η t - induction e <;> intro η t hmap ht +theorem compiler_correctness + (map : Identifier → Register) (e : Expr) (ξ : Identifier → Word) (η : State) (t : Register) + (hmap : ∀ x, read (loc x map) η = ξ x) (ht : ∀ x, loc x map < t) : + outcome (compile map e t) η ≃[t] { η with ac := value e ξ } := by + induction e generalizing η t with -- 5.I - case const => simp [StateEq, step]; rfl + | const => simp [StateEq, step]; rfl -- 5.II - case var => + | var => simp [hmap, StateEq, step] -- Porting note: was `finish [hmap, StateEq, step]` constructor · simp_all only [read, loc] · rfl -- 5.III - case sum => + | sum => rename_i e_s₁ e_s₂ e_ih_s₁ e_ih_s₂ simp generalize value e_s₁ ξ = ν₁ at e_ih_s₁ ⊢ diff --git a/Archive/Imo/Imo1962Q1.lean b/Archive/Imo/Imo1962Q1.lean index 6a05b328784b8..bd440259d1147 100644 --- a/Archive/Imo/Imo1962Q1.lean +++ b/Archive/Imo/Imo1962Q1.lean @@ -145,11 +145,11 @@ theorem satisfied_by_153846 : ProblemPredicate 153846 := by #align imo1962_q1.satisfied_by_153846 Imo1962Q1.satisfied_by_153846 theorem no_smaller_solutions (n : ℕ) (h1 : ProblemPredicate n) : n ≥ 153846 := by - cases' without_digits h1 with c h2 + have ⟨c, h2⟩ := without_digits h1 have h3 : (digits 10 c).length < 6 ∨ (digits 10 c).length ≥ 6 := by apply lt_or_ge - cases' h3 with h3 h3 - case inr => exact case_more_digits h3 h2 - case inl => + cases h3 with + | inr h3 => exact case_more_digits h3 h2 + | inl h3 => interval_cases h : (digits 10 c).length · exfalso; exact case_0_digit h h2 · exfalso; exact case_1_digit h h2 diff --git a/Mathlib/Algebra/Associated.lean b/Mathlib/Algebra/Associated.lean index 1952ca46bbb9d..278d05db08d66 100644 --- a/Mathlib/Algebra/Associated.lean +++ b/Mathlib/Algebra/Associated.lean @@ -1143,25 +1143,23 @@ theorem one_or_eq_of_le_of_prime : ∀ p m : Associates α, Prime p → m ≤ p rw [r] match h m d dvd_rfl' with | Or.inl h' => - by_cases h : m = 0 - case pos => + if h : m = 0 then simp [h, zero_mul] - case neg => + else rw [r] at h' have : m * d ≤ m * 1 := by simpa using h' have : d ≤ 1 := Associates.le_of_mul_le_mul_left m d 1 ‹m ≠ 0› this have : d = 1 := bot_unique this simp [this] | Or.inr h' => - by_cases h : d = 0 - case pos => - rw [r] at hp0 - have : m * d = 0 := by rw [h]; simp - contradiction - case neg => - rw [r] at h' - have : d * m ≤ d * 1 := by simpa [mul_comm] using h' - exact Or.inl <| bot_unique <| Associates.le_of_mul_le_mul_left d m 1 ‹d ≠ 0› this + if h : d = 0 then + rw [r] at hp0 + have : m * d = 0 := by rw [h]; simp + contradiction + else + rw [r] at h' + have : d * m ≤ d * 1 := by simpa [mul_comm] using h' + exact Or.inl <| bot_unique <| Associates.le_of_mul_le_mul_left d m 1 ‹d ≠ 0› this #align associates.one_or_eq_of_le_of_prime Associates.one_or_eq_of_le_of_prime instance : CanonicallyOrderedCommMonoid (Associates α) where diff --git a/Mathlib/Algebra/CharP/ExpChar.lean b/Mathlib/Algebra/CharP/ExpChar.lean index 94d248dd17670..9ea5a40c02362 100644 --- a/Mathlib/Algebra/CharP/ExpChar.lean +++ b/Mathlib/Algebra/CharP/ExpChar.lean @@ -102,9 +102,9 @@ theorem char_prime_of_ne_zero {p : ℕ} [hp : CharP R p] (p_ne_zero : p ≠ 0) : /-- The exponential characteristic is a prime number or one. -/ theorem expChar_is_prime_or_one (q : ℕ) [hq : ExpChar R q] : Nat.Prime q ∨ q = 1 := by - cases hq - case zero => exact .inr rfl - case prime hp _ => exact .inl hp + cases hq with + | zero => exact .inr rfl + | prime hp => exact .inl hp #align exp_char_is_prime_or_one expChar_is_prime_or_one /-- The exponential characteristic is positive. -/ diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean b/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean index f8a78987127d1..60e16e7d3946b 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean @@ -68,12 +68,12 @@ of great interest for the end user. /-- Shows that the fractional parts of the stream are in `[0,1)`. -/ theorem nth_stream_fr_nonneg_lt_one {ifp_n : IntFractPair K} (nth_stream_eq : IntFractPair.stream v n = some ifp_n) : 0 ≤ ifp_n.fr ∧ ifp_n.fr < 1 := by - cases n - case zero => + cases n with + | zero => have : IntFractPair.of v = ifp_n := by injection nth_stream_eq rw [← this, IntFractPair.of] exact ⟨fract_nonneg _, fract_lt_one _⟩ - case succ => + | succ => rcases succ_nth_stream_eq_some_iff.1 nth_stream_eq with ⟨_, _, _, ifp_of_eq_ifp_n⟩ rw [← ifp_of_eq_ifp_n, IntFractPair.of] exact ⟨fract_nonneg _, fract_lt_one _⟩ @@ -238,9 +238,9 @@ theorem succ_nth_fib_le_of_nth_denom (hyp : n = 0 ∨ ¬(of v).TerminatedAt (n - (fib (n + 1) : K) ≤ (of v).denominators n := by rw [denom_eq_conts_b, nth_cont_eq_succ_nth_cont_aux] have : n + 1 ≤ 1 ∨ ¬(of v).TerminatedAt (n - 1) := by - cases' n with n - case zero => exact Or.inl <| le_refl 1 - case succ => exact Or.inr (Or.resolve_left hyp n.succ_ne_zero) + cases n with + | zero => exact Or.inl <| le_refl 1 + | succ n => exact Or.inr (Or.resolve_left hyp n.succ_ne_zero) exact fib_le_of_continuantsAux_b this #align generalized_continued_fraction.succ_nth_fib_le_of_nth_denom GeneralizedContinuedFraction.succ_nth_fib_le_of_nth_denom @@ -249,9 +249,9 @@ theorem succ_nth_fib_le_of_nth_denom (hyp : n = 0 ∨ ¬(of v).TerminatedAt (n - theorem zero_le_of_continuantsAux_b : 0 ≤ ((of v).continuantsAux n).b := by let g := of v - induction' n with n IH - case zero => rfl - case succ => + induction n with + | zero => rfl + | succ n IH => cases' Decidable.em <| g.TerminatedAt (n - 1) with terminated not_terminated · -- terminating case cases' n with n @@ -320,9 +320,9 @@ Next we prove the so-called *determinant formula* for `GeneralizedContinuedFract theorem determinant_aux (hyp : n = 0 ∨ ¬(of v).TerminatedAt (n - 1)) : ((of v).continuantsAux n).a * ((of v).continuantsAux (n + 1)).b - ((of v).continuantsAux n).b * ((of v).continuantsAux (n + 1)).a = (-1) ^ n := by - induction' n with n IH - case zero => simp [continuantsAux] - case succ => + induction n with + | zero => simp [continuantsAux] + | succ n IH => -- set up some shorthand notation let g := of v let conts := continuantsAux g (n + 2) diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/TerminatesIffRat.lean b/Mathlib/Algebra/ContinuedFractions/Computation/TerminatesIffRat.lean index db29aa94d4722..3e664efb3e999 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/TerminatesIffRat.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/TerminatesIffRat.lean @@ -175,16 +175,16 @@ theorem coe_of_rat_eq : ((IntFractPair.of q).mapFr (↑) : IntFractPair K) = Int theorem coe_stream_nth_rat_eq : ((IntFractPair.stream q n).map (mapFr (↑)) : Option <| IntFractPair K) = IntFractPair.stream v n := by - induction' n with n IH - case zero => + induction n with + | zero => -- Porting note: was -- simp [IntFractPair.stream, coe_of_rat_eq v_eq_q] simp only [IntFractPair.stream, Option.map_some', coe_of_rat_eq v_eq_q] - case succ => + | succ n IH => rw [v_eq_q] at IH - cases' stream_q_nth_eq : IntFractPair.stream q n with ifp_n - case none => simp [IntFractPair.stream, IH.symm, v_eq_q, stream_q_nth_eq] - case some => + cases stream_q_nth_eq : IntFractPair.stream q n with + | none => simp [IntFractPair.stream, IH.symm, v_eq_q, stream_q_nth_eq] + | some ifp_n => cases' ifp_n with b fr cases' Decidable.em (fr = 0) with fr_zero fr_ne_zero · simp [IntFractPair.stream, IH.symm, v_eq_q, stream_q_nth_eq, fr_zero] @@ -296,12 +296,12 @@ theorem stream_succ_nth_fr_num_lt_nth_fr_num_rat {ifp_n ifp_succ_n : IntFractPai theorem stream_nth_fr_num_le_fr_num_sub_n_rat : ∀ {ifp_n : IntFractPair ℚ}, IntFractPair.stream q n = some ifp_n → ifp_n.fr.num ≤ (IntFractPair.of q).fr.num - n := by - induction' n with n IH - case zero => + induction n with + | zero => intro ifp_zero stream_zero_eq have : IntFractPair.of q = ifp_zero := by injection stream_zero_eq simp [le_refl, this.symm] - case succ => + | succ n IH => intro ifp_succ_n stream_succ_nth_eq suffices ifp_succ_n.fr.num + 1 ≤ (IntFractPair.of q).fr.num - n by rw [Int.ofNat_succ, sub_add_eq_sub_sub] diff --git a/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean b/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean index 715b3210257fe..23322b4bfb910 100644 --- a/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean +++ b/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean @@ -120,9 +120,9 @@ theorem squashSeq_nth_of_not_terminated {gp_n gp_succ_n : Pair K} (s_nth_eq : s. /-- The values before the squashed position stay the same. -/ theorem squashSeq_nth_of_lt {m : ℕ} (m_lt_n : m < n) : (squashSeq s n).get? m = s.get? m := by - cases s_succ_nth_eq : s.get? (n + 1) - case none => rw [squashSeq_eq_self_of_terminated s_succ_nth_eq] - case some => + cases s_succ_nth_eq : s.get? (n + 1) with + | none => rw [squashSeq_eq_self_of_terminated s_succ_nth_eq] + | some => obtain ⟨gp_n, s_nth_eq⟩ : ∃ gp_n, s.get? n = some gp_n exact s.ge_stable n.le_succ s_succ_nth_eq obtain ⟨gp_m, s_mth_eq⟩ : ∃ gp_m, s.get? m = some gp_m @@ -134,11 +134,11 @@ theorem squashSeq_nth_of_lt {m : ℕ} (m_lt_n : m < n) : (squashSeq s n).get? m sequence at position `n`. -/ theorem squashSeq_succ_n_tail_eq_squashSeq_tail_n : (squashSeq s (n + 1)).tail = squashSeq s.tail n := by - cases' s_succ_succ_nth_eq : s.get? (n + 2) with gp_succ_succ_n - case none => + cases s_succ_succ_nth_eq : s.get? (n + 2) with + | none => cases s_succ_nth_eq : s.get? (n + 1) <;> simp only [squashSeq, Stream'.Seq.get?_tail, s_succ_nth_eq, s_succ_succ_nth_eq] - case some => + | some gp_succ_succ_n => obtain ⟨gp_succ_n, s_succ_nth_eq⟩ : ∃ gp_succ_n, s.get? (n + 1) = some gp_succ_n; exact s.ge_stable (n + 1).le_succ s_succ_succ_nth_eq -- apply extensionality with `m` and continue by cases `m = n`. @@ -155,19 +155,19 @@ theorem squashSeq_succ_n_tail_eq_squashSeq_tail_n : corresponding squashed sequence at the squashed position. -/ theorem succ_succ_nth_convergent'_aux_eq_succ_nth_convergent'_aux_squashSeq : convergents'Aux s (n + 2) = convergents'Aux (squashSeq s n) (n + 1) := by - cases' s_succ_nth_eq : s.get? <| n + 1 with gp_succ_n - case none => + cases s_succ_nth_eq : s.get? <| n + 1 with + | none => rw [squashSeq_eq_self_of_terminated s_succ_nth_eq, convergents'Aux_stable_step_of_terminated s_succ_nth_eq] - case some => - induction' n with m IH generalizing s gp_succ_n - case zero => + | some gp_succ_n => + induction n generalizing s gp_succ_n with + | zero => obtain ⟨gp_head, s_head_eq⟩ : ∃ gp_head, s.head = some gp_head exact s.ge_stable zero_le_one s_succ_nth_eq have : (squashSeq s 0).head = some ⟨gp_head.a, gp_head.b + gp_succ_n.a / gp_succ_n.b⟩ := squashSeq_nth_of_not_terminated s_head_eq s_succ_nth_eq simp_all [convergents'Aux, Stream'.Seq.head, Stream'.Seq.get?_tail] - case succ => + | succ m IH => obtain ⟨gp_head, s_head_eq⟩ : ∃ gp_head, s.head = some gp_head exact s.ge_stable (m + 2).zero_le s_succ_nth_eq suffices @@ -204,11 +204,11 @@ squashed gcf. -/ /-- If the gcf already terminated at position `n`, nothing gets squashed. -/ theorem squashGCF_eq_self_of_terminated (terminated_at_n : TerminatedAt g n) : squashGCF g n = g := by - cases n - case zero => + cases n with + | zero => change g.s.get? 0 = none at terminated_at_n simp only [convergents', squashGCF, convergents'Aux, terminated_at_n] - case succ => + | succ => cases g simp only [squashGCF, mk.injEq, true_and] exact squashSeq_eq_self_of_terminated terminated_at_n @@ -224,11 +224,11 @@ theorem squashGCF_nth_of_lt {m : ℕ} (m_lt_n : m < n) : squashed position. -/ theorem succ_nth_convergent'_eq_squashGCF_nth_convergent' : g.convergents' (n + 1) = (squashGCF g n).convergents' n := by - cases n - case zero => + cases n with + | zero => cases g_s_head_eq : g.s.get? 0 <;> simp [g_s_head_eq, squashGCF, convergents', convergents'Aux, Stream'.Seq.head] - case succ => + | succ => simp only [succ_succ_nth_convergent'_aux_eq_succ_nth_convergent'_aux_squashSeq, convergents', squashGCF] #align generalized_continued_fraction.succ_nth_convergent'_eq_squash_gcf_nth_convergent' GeneralizedContinuedFraction.succ_nth_convergent'_eq_squashGCF_nth_convergent' @@ -270,8 +270,8 @@ theorem succ_nth_convergent_eq_squashGCF_nth_convergent [Field K] · obtain ⟨⟨a, b⟩, s_nth_eq⟩ : ∃ gp_n, g.s.get? n = some gp_n exact Option.ne_none_iff_exists'.mp not_terminated_at_n have b_ne_zero : b ≠ 0 := nth_part_denom_ne_zero (part_denom_eq_s_b s_nth_eq) - cases' n with n' - case zero => + cases n with + | zero => suffices (b * g.h + a) / b = g.h + a / b by simpa [squashGCF, s_nth_eq, convergent_eq_conts_a_div_conts_b, continuants_recurrenceAux s_nth_eq zeroth_continuant_aux_eq_one_zero @@ -280,7 +280,7 @@ theorem succ_nth_convergent_eq_squashGCF_nth_convergent [Field K] (b * g.h + a) / b = b * g.h / b + a / b := by ring -- requires `Field`, not `DivisionRing` _ = g.h + a / b := by rw [mul_div_cancel_left _ b_ne_zero] - case succ => + | succ n' => obtain ⟨⟨pa, pb⟩, s_n'th_eq⟩ : ∃ gp_n', g.s.get? n' = some gp_n' := g.s.ge_stable n'.le_succ s_nth_eq -- Notations @@ -342,9 +342,9 @@ positivity criterion required here. The analogous result for them theorem convergents_eq_convergents' [LinearOrderedField K] (s_pos : ∀ {gp : Pair K} {m : ℕ}, m < n → g.s.get? m = some gp → 0 < gp.a ∧ 0 < gp.b) : g.convergents n = g.convergents' n := by - induction' n with n IH generalizing g - case zero => simp - case succ => + induction n generalizing g with + | zero => simp + | succ n IH => let g' := squashGCF g n -- first replace the rhs with the squashed computation suffices g.convergents (n + 1) = g'.convergents' n by diff --git a/Mathlib/Algebra/ContinuedFractions/TerminatedStable.lean b/Mathlib/Algebra/ContinuedFractions/TerminatedStable.lean index bfc48c04ba1fb..0f37a957af95c 100644 --- a/Mathlib/Algebra/ContinuedFractions/TerminatedStable.lean +++ b/Mathlib/Algebra/ContinuedFractions/TerminatedStable.lean @@ -45,12 +45,12 @@ theorem continuantsAux_stable_of_terminated (n_lt_m : n < m) (terminated_at_n : theorem convergents'Aux_stable_step_of_terminated {s : Stream'.Seq <| Pair K} (terminated_at_n : s.TerminatedAt n) : convergents'Aux s (n + 1) = convergents'Aux s n := by change s.get? n = none at terminated_at_n - induction' n with n IH generalizing s - case zero => simp only [convergents'Aux, terminated_at_n, Stream'.Seq.head] - case succ => - cases' s_head_eq : s.head with gp_head - case none => simp only [convergents'Aux, s_head_eq] - case some => + induction n generalizing s with + | zero => simp only [convergents'Aux, terminated_at_n, Stream'.Seq.head] + | succ n IH => + cases s_head_eq : s.head with + | none => simp only [convergents'Aux, s_head_eq] + | some gp_head => have : s.tail.TerminatedAt n := by simp only [Stream'.Seq.TerminatedAt, s.get?_tail, terminated_at_n] have := IH this diff --git a/Mathlib/Algebra/FreeAlgebra.lean b/Mathlib/Algebra/FreeAlgebra.lean index f7d8be0a962fd..c0a84fc39b2e0 100644 --- a/Mathlib/Algebra/FreeAlgebra.lean +++ b/Mathlib/Algebra/FreeAlgebra.lean @@ -371,21 +371,21 @@ def lift : (X → A) ≃ (FreeAlgebra R X →ₐ[R] A) := right_inv := fun F ↦ by ext t rcases t with ⟨x⟩ - induction x - case of => + induction x with + | of => change ((F : FreeAlgebra R X → A) ∘ ι R) _ = _ simp only [Function.comp_apply, ι_def] - case ofScalar x => + | ofScalar x => change algebraMap _ _ x = F (algebraMap _ _ x) rw [AlgHom.commutes F _] - case add a b ha hb => + | add a b ha hb => -- Porting note: it is necessary to declare fa and fb explicitly otherwise Lean refuses -- to consider `Quot.mk (Rel R X) ·` as element of FreeAlgebra R X let fa : FreeAlgebra R X := Quot.mk (Rel R X) a let fb : FreeAlgebra R X := Quot.mk (Rel R X) b change liftAux R (F ∘ ι R) (fa + fb) = F (fa + fb) rw [AlgHom.map_add, AlgHom.map_add, ha, hb] - case mul a b ha hb => + | mul a b ha hb => let fa : FreeAlgebra R X := Quot.mk (Rel R X) a let fb : FreeAlgebra R X := Quot.mk (Rel R X) b change liftAux R (F ∘ ι R) (fa * fb) = F (fa * fb) diff --git a/Mathlib/Algebra/GroupPower/Lemmas.lean b/Mathlib/Algebra/GroupPower/Lemmas.lean index 8c326e4887858..7e2e718de4be1 100644 --- a/Mathlib/Algebra/GroupPower/Lemmas.lean +++ b/Mathlib/Algebra/GroupPower/Lemmas.lean @@ -213,10 +213,10 @@ theorem zpow_sub_one (a : G) (n : ℤ) : a ^ (n - 1) = a ^ n * a⁻¹ := @[to_additive add_zsmul] theorem zpow_add (a : G) (m n : ℤ) : a ^ (m + n) = a ^ m * a ^ n := by - induction' n using Int.induction_on with n ihn n ihn - case hz => simp - · simp only [← add_assoc, zpow_add_one, ihn, mul_assoc] - · rw [zpow_sub_one, ← mul_assoc, ← ihn, ← zpow_sub_one, add_sub_assoc] + induction n using Int.induction_on with + | hz => simp + | hp n ihn => simp only [← add_assoc, zpow_add_one, ihn, mul_assoc] + | hn n ihn => rw [zpow_sub_one, ← mul_assoc, ← ihn, ← zpow_sub_one, add_sub_assoc] #align zpow_add zpow_add #align add_zsmul add_zsmul diff --git a/Mathlib/Algebra/Lie/Free.lean b/Mathlib/Algebra/Lie/Free.lean index 66ab1f4a5235b..ed701c023455d 100644 --- a/Mathlib/Algebra/Lie/Free.lean +++ b/Mathlib/Algebra/Lie/Free.lean @@ -201,14 +201,14 @@ theorem liftAux_map_mul (f : X → L) (a b : lib R X) : theorem liftAux_spec (f : X → L) (a b : lib R X) (h : FreeLieAlgebra.Rel R X a b) : liftAux R f a = liftAux R f b := by - induction h - case lie_self a' => simp only [liftAux_map_mul, NonUnitalAlgHom.map_zero, lie_self] - case leibniz_lie a' b' c' => + induction h with + | lie_self a' => simp only [liftAux_map_mul, NonUnitalAlgHom.map_zero, lie_self] + | leibniz_lie a' b' c' => simp only [liftAux_map_mul, liftAux_map_add, sub_add_cancel, lie_lie] - case smul t a' b' _ h₂ => simp only [liftAux_map_smul, h₂] - case add_right a' b' c' _ h₂ => simp only [liftAux_map_add, h₂] - case mul_left a' b' c' _ h₂ => simp only [liftAux_map_mul, h₂] - case mul_right a' b' c' _ h₂ => simp only [liftAux_map_mul, h₂] + | smul b' _ h₂ => simp only [liftAux_map_smul, h₂] + | add_right c' _ h₂ => simp only [liftAux_map_add, h₂] + | mul_left c' _ h₂ => simp only [liftAux_map_mul, h₂] + | mul_right c' _ h₂ => simp only [liftAux_map_mul, h₂] #align free_lie_algebra.lift_aux_spec FreeLieAlgebra.liftAux_spec /-- The quotient map as a `NonUnitalAlgHom`. -/ diff --git a/Mathlib/Algebra/Module/LinearMap.lean b/Mathlib/Algebra/Module/LinearMap.lean index 07f886c18f078..e543896ee0add 100644 --- a/Mathlib/Algebra/Module/LinearMap.lean +++ b/Mathlib/Algebra/Module/LinearMap.lean @@ -645,10 +645,10 @@ protected theorem map_sub (x y : M) : f (x - y) = f x - f y := instance CompatibleSMul.intModule {S : Type*} [Semiring S] [Module S M] [Module S M₂] : CompatibleSMul M M₂ ℤ S := ⟨fun fₗ c x ↦ by - induction c using Int.induction_on - case hz => simp - case hp n ih => simp [add_smul, ih] - case hn n ih => simp [sub_smul, ih]⟩ + induction c using Int.induction_on with + | hz => simp + | hp n ih => simp [add_smul, ih] + | hn n ih => simp [sub_smul, ih]⟩ #align linear_map.compatible_smul.int_module LinearMap.CompatibleSMul.intModule instance CompatibleSMul.units {R S : Type*} [Monoid R] [MulAction R M] [MulAction R M₂] diff --git a/Mathlib/Analysis/Calculus/Deriv/Polynomial.lean b/Mathlib/Analysis/Calculus/Deriv/Polynomial.lean index 1efb4b91a9b20..8d32cb227257e 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Polynomial.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Polynomial.lean @@ -66,9 +66,9 @@ variable (p : 𝕜[X]) (q : R[X]) /-- The derivative (in the analysis sense) of a polynomial `p` is given by `p.derivative`. -/ protected theorem hasStrictDerivAt (x : 𝕜) : HasStrictDerivAt (fun x => p.eval x) (p.derivative.eval x) x := by - induction p using Polynomial.induction_on' - case h_add p q hp hq => simpa using hp.add hq - case h_monomial n a => simpa [mul_assoc] using (hasStrictDerivAt_pow n x).const_mul a + induction p using Polynomial.induction_on' with + | h_add p q hp hq => simpa using hp.add hq + | h_monomial n a => simpa [mul_assoc] using (hasStrictDerivAt_pow n x).const_mul a #align polynomial.has_strict_deriv_at Polynomial.hasStrictDerivAt protected theorem hasStrictDerivAt_aeval (x : 𝕜) : @@ -195,4 +195,3 @@ protected theorem fderivWithin_aeval (hxs : UniqueDiffWithinAt 𝕜 s x) : #align polynomial.fderiv_within_aeval Polynomial.fderivWithin_aeval end Polynomial - diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Pow.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Pow.lean index 0f573fc5f8eff..acb7850df8d66 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Pow.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Pow.lean @@ -47,13 +47,13 @@ lemma strictConcaveOn_rpow {p : ℝ} (hp₀ : 0 < p) (hp₁ : p < 1) : lemma concaveOn_rpow {p : ℝ} (hp₀ : 0 ≤ p) (hp₁ : p ≤ 1) : ConcaveOn ℝ≥0 univ fun x : ℝ≥0 ↦ x ^ p := by - by_cases hp : p = 0 - case pos => exact ⟨convex_univ, fun _ _ _ _ _ _ _ _ hab => by simp [hp, hab]⟩ - case neg => + if hp : p = 0 then + exact ⟨convex_univ, fun _ _ _ _ _ _ _ _ hab => by simp [hp, hab]⟩ + else push_neg at hp - by_cases hp' : p = 1 - case pos => exact ⟨convex_univ, by simp [hp']⟩ - case neg => + if hp' : p = 1 then + exact ⟨convex_univ, by simp [hp']⟩ + else push_neg at hp' exact (strictConcaveOn_rpow (by positivity) (lt_of_le_of_ne hp₁ hp')).concaveOn @@ -86,13 +86,13 @@ lemma strictConcaveOn_rpow {p : ℝ} (hp₀ : 0 < p) (hp₁ : p < 1) : lemma concaveOn_rpow {p : ℝ} (hp₀ : 0 ≤ p) (hp₁ : p ≤ 1) : ConcaveOn ℝ (Set.Ici 0) fun x : ℝ ↦ x ^ p := by - by_cases hp : p = 0 - case pos => exact ⟨convex_Ici 0, fun _ _ _ _ _ _ _ _ hab => by simp [hp, hab]⟩ - case neg => + if hp : p = 0 then + exact ⟨convex_Ici 0, fun _ _ _ _ _ _ _ _ hab => by simp [hp, hab]⟩ + else push_neg at hp - by_cases hp' : p = 1 - case pos => exact ⟨convex_Ici 0, by simp [hp']⟩ - case neg => + if hp' : p = 1 then + exact ⟨convex_Ici 0, by simp [hp']⟩ + else push_neg at hp' exact (strictConcaveOn_rpow (by positivity) (lt_of_le_of_ne hp₁ hp')).concaveOn diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean index 24ba679fa2b05..a33fb9175e3e9 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean @@ -220,9 +220,9 @@ theorem log_nonpos (hx : 0 ≤ x) (h'x : x ≤ 1) : log x ≤ 0 := #align real.log_nonpos Real.log_nonpos theorem log_nat_cast_nonneg (n : ℕ) : 0 ≤ log n := by - by_cases hn : n = 0 - case pos => simp [hn] - case neg => + if hn : n = 0 then + simp [hn] + else have : (1 : ℝ) ≤ n := mod_cast Nat.one_le_of_lt <| Nat.pos_of_ne_zero hn exact log_nonneg this diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean b/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean index 9a4f0606447eb..598828dcdd8ff 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean @@ -594,9 +594,9 @@ theorem coe_mul_rpow (x y : ℝ≥0) (z : ℝ) : ((x : ℝ≥0∞) * y) ^ z = (x theorem prod_coe_rpow {ι} (s : Finset ι) (f : ι → ℝ≥0) (r : ℝ) : ∏ i in s, (f i : ℝ≥0∞) ^ r = ((∏ i in s, f i : ℝ≥0) : ℝ≥0∞) ^ r := by - induction s using Finset.induction - case empty => simp - case insert i s hi ih => simp_rw [prod_insert hi, ih, ← coe_mul_rpow, coe_mul] + induction s using Finset.induction with + | empty => simp + | insert hi ih => simp_rw [prod_insert hi, ih, ← coe_mul_rpow, coe_mul] theorem mul_rpow_of_ne_zero {x y : ℝ≥0∞} (hx : x ≠ 0) (hy : y ≠ 0) (z : ℝ) : (x * y) ^ z = x ^ z * y ^ z := by simp [*, mul_rpow_eq_ite] @@ -608,18 +608,18 @@ theorem mul_rpow_of_nonneg (x y : ℝ≥0∞) {z : ℝ} (hz : 0 ≤ z) : (x * y) theorem prod_rpow_of_ne_top {ι} {s : Finset ι} {f : ι → ℝ≥0∞} (hf : ∀ i ∈ s, f i ≠ ∞) (r : ℝ) : ∏ i in s, f i ^ r = (∏ i in s, f i) ^ r := by - induction s using Finset.induction - case empty => simp - case insert i s hi ih => + induction s using Finset.induction with + | empty => simp + | @insert i s hi ih => have h2f : ∀ i ∈ s, f i ≠ ∞ := fun i hi ↦ hf i <| mem_insert_of_mem hi rw [prod_insert hi, prod_insert hi, ih h2f, ← mul_rpow_of_ne_top <| hf i <| mem_insert_self ..] apply prod_lt_top h2f |>.ne theorem prod_rpow_of_nonneg {ι} {s : Finset ι} {f : ι → ℝ≥0∞} {r : ℝ} (hr : 0 ≤ r) : ∏ i in s, f i ^ r = (∏ i in s, f i) ^ r := by - induction s using Finset.induction - case empty => simp - case insert i s hi ih => simp_rw [prod_insert hi, ih, ← mul_rpow_of_nonneg _ _ hr] + induction s using Finset.induction with + | empty => simp + | insert hi ih => simp_rw [prod_insert hi, ih, ← mul_rpow_of_nonneg _ _ hr] theorem inv_rpow (x : ℝ≥0∞) (y : ℝ) : x⁻¹ ^ y = (x ^ y)⁻¹ := by rcases eq_or_ne y 0 with (rfl | hy); · simp only [rpow_zero, inv_one] diff --git a/Mathlib/CategoryTheory/Limits/ConcreteCategory.lean b/Mathlib/CategoryTheory/Limits/ConcreteCategory.lean index 5d666c3a85a6f..8ca0ebd62812c 100644 --- a/Mathlib/CategoryTheory/Limits/ConcreteCategory.lean +++ b/Mathlib/CategoryTheory/Limits/ConcreteCategory.lean @@ -145,17 +145,17 @@ theorem Concrete.isColimit_exists_of_rep_eq {D : Cocone F} {i j : J} (hD : IsCol ∃ (k : _) (f : a.1 ⟶ k) (g : b.1 ⟶ k), F.map f a.2 = F.map g b.2 by exact this ⟨i, x⟩ ⟨j, y⟩ h intro a b h - induction h - case rel x y hh => + induction h with + | rel x y hh => obtain ⟨e, he⟩ := hh use y.1, e, 𝟙 _ simpa using he.symm - case refl x => + | refl x => exact ⟨x.1, 𝟙 _, 𝟙 _, rfl⟩ - case symm x y _ hh => + | symm x y _ hh => obtain ⟨k, f, g, hh⟩ := hh exact ⟨k, g, f, hh.symm⟩ - case trans x y z _ _ hh1 hh2 => + | trans x y z _ _ hh1 hh2 => obtain ⟨k1, f1, g1, h1⟩ := hh1 obtain ⟨k2, f2, g2, h2⟩ := hh2 let k0 : J := IsFiltered.max k1 k2 diff --git a/Mathlib/CategoryTheory/Limits/Final.lean b/Mathlib/CategoryTheory/Limits/Final.lean index 0a473c1a2426d..d6c4fdc578dfe 100644 --- a/Mathlib/CategoryTheory/Limits/Final.lean +++ b/Mathlib/CategoryTheory/Limits/Final.lean @@ -395,18 +395,18 @@ namespace Final theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X} (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) : Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by - induction t - case rel x y r => + induction t with + | rel x y r => obtain ⟨f, w⟩ := r fconstructor swap; fconstructor left; fconstructor exact StructuredArrow.homMk f - case refl => fconstructor - case symm x y _ ih => + | refl => fconstructor + | symm x y _ ih => apply zigzag_symmetric exact ih - case trans x y z _ _ ih₁ ih₂ => + | trans x y z _ _ ih₁ ih₂ => apply Relation.ReflTransGen.trans exact ih₁; exact ih₂ #align category_theory.functor.final.zigzag_of_eqv_gen_quot_rel CategoryTheory.Functor.Final.zigzag_of_eqvGen_quot_rel diff --git a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean index 8a595d5a9522b..1c4adb124c365 100644 --- a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean +++ b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean @@ -259,11 +259,11 @@ lemma eventually_log_b_mul_pos : ∀ᶠ (n:ℕ) in atTop, ∀ i, 0 < log (b i * exact h.eventually_gt_atTop 0 @[aesop safe apply] lemma T_pos (n : ℕ) : 0 < T n := by - induction n using Nat.strongInductionOn - case ind n h_ind => - rcases lt_or_le n R.n₀ with hn|hn - case inl => exact R.T_gt_zero' n hn -- n < R.n₀ - case inr => -- R.n₀ ≤ n + induction n using Nat.strongInductionOn with + | ind n h_ind => + cases lt_or_le n R.n₀ with + | inl hn => exact R.T_gt_zero' n hn -- n < R.n₀ + | inr hn => -- R.n₀ ≤ n rw [R.h_rec n hn] have := R.g_nonneg refine add_pos_of_pos_of_nonneg (Finset.sum_pos ?sum_elems univ_nonempty) (by aesop) @@ -614,8 +614,8 @@ lemma eventually_atTop_sumTransform_le : intro i have hrpos_i := hrpos i have g_nonneg : 0 ≤ g n := R.g_nonneg n (by positivity) - rcases le_or_lt 0 (p a b + 1) with hp|hp - case h.inl => -- 0 ≤ p a b + 1 + cases le_or_lt 0 (p a b + 1) with + | inl hp => -- 0 ≤ p a b + 1 calc sumTransform (p a b) g (r i n) n = n ^ (p a b) * (∑ u in Finset.Ico (r i n) n, g u / u ^ ((p a b) + 1)) := by rfl _ ≤ n ^ (p a b) * (∑ u in Finset.Ico (r i n) n, c₂ * g n / u ^ ((p a b) + 1)) := by @@ -647,7 +647,7 @@ lemma eventually_atTop_sumTransform_le : _ = c₂ * g n / c₁ ^ ((p a b) + 1) := by rw [div_self (by positivity), mul_one] _ = (c₂ / c₁ ^ ((p a b) + 1)) * g n := by ring _ ≤ max c₂ (c₂ / c₁ ^ ((p a b) + 1)) * g n := by gcongr; exact le_max_right _ _ - case h.inr => -- p a b + 1 < 0 + | inr hp => -- p a b + 1 < 0 calc sumTransform (p a b) g (r i n) n = n ^ (p a b) * (∑ u in Finset.Ico (r i n) n, g u / u ^ ((p a b) + 1)) := by rfl _ ≤ n ^ (p a b) * (∑ u in Finset.Ico (r i n) n, c₂ * g n / u ^ ((p a b) + 1)) := by @@ -693,8 +693,8 @@ lemma eventually_atTop_sumTransform_ge : intro i have hrpos_i := hrpos i have g_nonneg : 0 ≤ g n := R.g_nonneg n (by positivity) - rcases le_or_gt 0 (p a b + 1) with hp|hp - case h.inl => -- 0 ≤ (p a b) + 1 + cases le_or_gt 0 (p a b + 1) with + | inl hp => -- 0 ≤ (p a b) + 1 calc sumTransform (p a b) g (r i n) n = n ^ (p a b) * (∑ u in Finset.Ico (r i n) n, g u / u ^ ((p a b) + 1)) := by rfl _ ≥ n ^ (p a b) * (∑ u in Finset.Ico (r i n) n, c₂ * g n / u^((p a b) + 1)) := by @@ -728,7 +728,7 @@ lemma eventually_atTop_sumTransform_ge : _ = c₂ * (1 - c₃) * g n := by rw [div_self (by positivity), mul_one] _ ≥ min (c₂ * (1 - c₃)) ((1 - c₃) * c₂ / c₁ ^ ((p a b) + 1)) * g n := by gcongr; exact min_le_left _ _ - case h.inr => -- (p a b) + 1 < 0 + | inr hp => -- (p a b) + 1 < 0 calc sumTransform (p a b) g (r i n) n = n ^ (p a b) * (∑ u in Finset.Ico (r i n) n, g u / u^((p a b) + 1)) := by rfl _ ≥ n ^ (p a b) * (∑ u in Finset.Ico (r i n) n, c₂ * g n / u ^ ((p a b) + 1)) := by @@ -910,8 +910,8 @@ lemma isTheta_deriv_rpow_p_mul_one_add_smoothingFn {p : ℝ} (hp : p ≠ 0) : lemma growsPolynomially_deriv_rpow_p_mul_one_sub_smoothingFn (p : ℝ) : GrowsPolynomially fun x => ‖deriv (fun z => z ^ p * (1 - ε z)) x‖ := by - rcases eq_or_ne p 0 with hp|hp - case inl => -- p = 0 + cases eq_or_ne p 0 with + | inl hp => -- p = 0 have h₁ : (fun x => ‖deriv (fun z => z ^ p * (1 - ε z)) x‖) =ᶠ[atTop] fun z => z⁻¹ / (log z ^ 2) := by filter_upwards [eventually_deriv_one_sub_smoothingFn, eventually_gt_atTop 1] with x hx hx_pos @@ -924,7 +924,7 @@ lemma growsPolynomially_deriv_rpow_p_mul_one_sub_smoothingFn (p : ℝ) : (GrowsPolynomially.pow 2 growsPolynomially_log ?_) filter_upwards [eventually_ge_atTop 1] with _ hx exact log_nonneg hx - case inr => -- p ≠ 0 + | inr hp => -- p ≠ 0 refine GrowsPolynomially.of_isTheta (growsPolynomially_rpow (p-1)) (isTheta_deriv_rpow_p_mul_one_sub_smoothingFn hp) ?_ filter_upwards [eventually_gt_atTop 0] with _ _ @@ -932,8 +932,8 @@ lemma growsPolynomially_deriv_rpow_p_mul_one_sub_smoothingFn (p : ℝ) : lemma growsPolynomially_deriv_rpow_p_mul_one_add_smoothingFn (p : ℝ) : GrowsPolynomially fun x => ‖deriv (fun z => z ^ p * (1 + ε z)) x‖ := by - rcases eq_or_ne p 0 with hp|hp - case inl => -- p = 0 + cases eq_or_ne p 0 with + | inl hp => -- p = 0 have h₁ : (fun x => ‖deriv (fun z => z ^ p * (1 + ε z)) x‖) =ᶠ[atTop] fun z => z⁻¹ / (log z ^ 2) := by filter_upwards [eventually_deriv_one_add_smoothingFn, eventually_gt_atTop 1] with x hx hx_pos @@ -947,8 +947,8 @@ lemma growsPolynomially_deriv_rpow_p_mul_one_add_smoothingFn (p : ℝ) : (GrowsPolynomially.pow 2 growsPolynomially_log ?_) filter_upwards [eventually_ge_atTop 1] with x hx exact log_nonneg hx - case inr => -- p ≠ 0 - refine GrowsPolynomially.of_isTheta ((growsPolynomially_rpow (p-1))) + | inr hp => -- p ≠ 0 + refine GrowsPolynomially.of_isTheta (growsPolynomially_rpow (p-1)) (isTheta_deriv_rpow_p_mul_one_add_smoothingFn hp) ?_ filter_upwards [eventually_gt_atTop 0] with _ _ positivity @@ -1212,8 +1212,8 @@ lemma T_isBigO_smoothingFn_mul_asympBound : have h_one_sub_smoothingFn_pos' : 0 < 1 - ε n := h_smoothing_pos n hn rw [Real.norm_of_nonneg (R.T_nonneg n), Real.norm_of_nonneg (by positivity)] -- We now prove all other cases by induction - induction n using Nat.strongInductionOn - case ind n h_ind => + induction n using Nat.strongInductionOn with + | ind n h_ind => have b_mul_n₀_le_ri i : ⌊b' * ↑n₀⌋₊ ≤ r i n := by exact_mod_cast calc ⌊b' * (n₀ : ℝ)⌋₊ ≤ b' * n₀ := Nat.floor_le <| by positivity _ ≤ b' * n := by gcongr @@ -1225,9 +1225,9 @@ lemma T_isBigO_smoothingFn_mul_asympBound : -- Apply the induction hypothesis, or use the base case depending on how large n is gcongr (∑ i, a i * ?_) + g n with i _ · exact le_of_lt <| R.a_pos _ - · by_cases ri_lt_n₀ : r i n < n₀ - case pos => exact h_base _ <| by aesop - case neg => + · if ri_lt_n₀ : r i n < n₀ then + exact h_base _ <| by aesop + else push_neg at ri_lt_n₀ exact h_ind (r i n) (R.r_lt_n _ _ (n₀_ge_Rn₀.trans hn)) ri_lt_n₀ (h_asympBound_r_pos _ hn _) (h_smoothing_r_pos n hn i) @@ -1358,8 +1358,8 @@ lemma smoothingFn_mul_asympBound_isBigO_T : have h_one_sub_smoothingFn_pos' : 0 < 1 + ε n := h_smoothing_pos n hn rw [Real.norm_of_nonneg (R.T_nonneg n), Real.norm_of_nonneg (by positivity)] -- We now prove all other cases by induction - induction n using Nat.strongInductionOn - case ind n h_ind => + induction n using Nat.strongInductionOn with + | ind n h_ind => have b_mul_n₀_le_ri i : ⌊b' * ↑n₀⌋₊ ≤ r i n := by exact_mod_cast calc ⌊b' * ↑n₀⌋₊ ≤ b' * n₀ := Nat.floor_le <| by positivity _ ≤ b' * n := by gcongr @@ -1371,9 +1371,9 @@ lemma smoothingFn_mul_asympBound_isBigO_T : -- Apply the induction hypothesis, or use the base case depending on how large `n` is gcongr (∑ i, a i * ?_) + g n with i _ · exact le_of_lt <| R.a_pos _ - · rcases lt_or_le (r i n) n₀ with ri_lt_n₀ | n₀_le_ri - case inl => exact h_base _ <| Finset.mem_Ico.mpr ⟨b_mul_n₀_le_ri i, ri_lt_n₀⟩ - case inr => + · cases lt_or_le (r i n) n₀ with + | inl ri_lt_n₀ => exact h_base _ <| Finset.mem_Ico.mpr ⟨b_mul_n₀_le_ri i, ri_lt_n₀⟩ + | inr n₀_le_ri => exact h_ind (r i n) (R.r_lt_n _ _ (n₀_ge_Rn₀.trans hn)) n₀_le_ri (h_asympBound_r_pos _ hn _) (h_smoothing_r_pos n hn i) _ = (∑ i, a i * (C * ((1 + ε (r i n)) * ((r i n) ^ (p a b) diff --git a/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean b/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean index 889bd9b1aa119..cccf395c85a0b 100644 --- a/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean +++ b/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean @@ -95,15 +95,15 @@ lemma eventually_zero_of_frequently_zero (hf : GrowsPolynomially f) (hf' : ∃ have hmain : ∀ (m : ℕ) (z : ℝ), x ≤ z → z ∈ Set.Icc ((2:ℝ)^(-(m:ℤ) -1) * x₀) ((2:ℝ)^(-(m:ℤ)) * x₀) → f z = 0 := by intro m - induction m - case zero => + induction m with + | zero => simp only [Nat.zero_eq, CharP.cast_eq_zero, neg_zero, zero_sub, zpow_zero, one_mul] at * specialize hx x₀ (le_of_max_le_left hx₀_ge) simp only [hx₀, mul_zero, Set.Icc_self, Set.mem_singleton_iff] at hx refine fun z _ hz => hx _ ?_ simp only [zpow_neg, zpow_one] at hz simp only [one_div, hz] - case succ k ih => + | succ k ih => intro z hxz hz simp only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] at * have hx' : x ≤ (2:ℝ)^(-(k:ℤ) - 1) * x₀ := by @@ -154,8 +154,8 @@ lemma eventually_zero_of_frequently_zero (hf : GrowsPolynomially f) (hf' : ∃ lemma eventually_atTop_nonneg_or_nonpos (hf : GrowsPolynomially f) : (∀ᶠ x in atTop, 0 ≤ f x) ∨ (∀ᶠ x in atTop, f x ≤ 0) := by obtain ⟨c₁, _, c₂, _, h⟩ := hf (1/2) (by norm_num) - rcases lt_trichotomy c₁ c₂ with hlt|heq|hgt - case inl => -- c₁ < c₂ + match lt_trichotomy c₁ c₂ with + | .inl hlt => -- c₁ < c₂ left filter_upwards [h, eventually_ge_atTop 0] with x hx hx_nonneg have h' : 3 / 4 * x ∈ Set.Icc (1 / 2 * x) x := by @@ -166,7 +166,7 @@ lemma eventually_atTop_nonneg_or_nonpos (hf : GrowsPolynomially f) : rw [Set.nonempty_Icc] at hu have hu' : 0 ≤ (c₂ - c₁) * f x := by linarith exact nonneg_of_mul_nonneg_right hu' (by linarith) - case inr.inr => -- c₂ < c₁ + | .inr (.inr hgt) => -- c₂ < c₁ right filter_upwards [h, eventually_ge_atTop 0] with x hx hx_nonneg have h' : 3 / 4 * x ∈ Set.Icc (1 / 2 * x) x := by @@ -177,7 +177,7 @@ lemma eventually_atTop_nonneg_or_nonpos (hf : GrowsPolynomially f) : rw [Set.nonempty_Icc] at hu have hu' : (c₁ - c₂) * f x ≤ 0 := by linarith exact nonpos_of_mul_nonpos_right hu' (by linarith) - case inr.inl => -- c₁ = c₂ + | .inr (.inl heq) => -- c₁ = c₂ have hmain : ∃ c, ∀ᶠ x in atTop, f x = c := by simp only [heq, Set.Icc_self, Set.mem_singleton_iff, one_mul] at h rw [eventually_atTop] at h @@ -225,28 +225,28 @@ lemma eventually_atTop_nonneg_or_nonpos (hf : GrowsPolynomially f) : exact_mod_cast hz.2 rw [← z_to_half_z, half_z_to_base] obtain ⟨c, hc⟩ := hmain - rcases le_or_lt 0 c with hpos|hneg - case inl => + cases le_or_lt 0 c with + | inl hpos => exact Or.inl <| by filter_upwards [hc] with _ hc; simpa only [hc] - case inr => + | inr hneg => right filter_upwards [hc] with x hc exact le_of_lt <| by simpa only [hc] lemma eventually_atTop_zero_or_pos_or_neg (hf : GrowsPolynomially f) : (∀ᶠ x in atTop, f x = 0) ∨ (∀ᶠ x in atTop, 0 < f x) ∨ (∀ᶠ x in atTop, f x < 0) := by - by_cases h : ∃ᶠ x in atTop, f x = 0 - case pos => exact Or.inl <| eventually_zero_of_frequently_zero hf h - case neg => + if h : ∃ᶠ x in atTop, f x = 0 then + exact Or.inl <| eventually_zero_of_frequently_zero hf h + else rw [not_frequently] at h push_neg at h - rcases eventually_atTop_nonneg_or_nonpos hf with h'|h' - case inl => + cases eventually_atTop_nonneg_or_nonpos hf with + | inl h' => refine Or.inr (Or.inl ?_) simp only [lt_iff_le_and_ne] rw [eventually_and] exact ⟨h', by filter_upwards [h] with x hx; exact hx.symm⟩ - case inr => + | inr h' => refine Or.inr (Or.inr ?_) simp only [lt_iff_le_and_ne] rw [eventually_and] @@ -265,14 +265,14 @@ protected lemma neg_iff {f : ℝ → ℝ} : GrowsPolynomially f ↔ GrowsPolynom ⟨fun hf => hf.neg, fun hf => by rw [← neg_neg f]; exact hf.neg⟩ protected lemma abs (hf : GrowsPolynomially f) : GrowsPolynomially (fun x => |f x|) := by - rcases eventually_atTop_nonneg_or_nonpos hf with hf'|hf' - case inl => + cases eventually_atTop_nonneg_or_nonpos hf with + | inl hf' => have hmain : f =ᶠ[atTop] fun x => |f x| := by filter_upwards [hf'] with x hx rw [abs_of_nonneg hx] rw [← iff_eventuallyEq hmain] exact hf - case inr => + | inr hf' => have hmain : -f =ᶠ[atTop] fun x => |f x| := by filter_upwards [hf'] with x hx simp only [Pi.neg_apply, abs_of_nonpos hx] @@ -304,29 +304,29 @@ lemma growsPolynomially_id : GrowsPolynomially (fun x => x) := by protected lemma GrowsPolynomially.mul {f g : ℝ → ℝ} (hf : GrowsPolynomially f) (hg : GrowsPolynomially g) : GrowsPolynomially fun x => f x * g x := by suffices : GrowsPolynomially fun x => |f x| * |g x| - · rcases eventually_atTop_nonneg_or_nonpos hf with hf'|hf' - case inl => - rcases eventually_atTop_nonneg_or_nonpos hg with hg'|hg' - case inl => + · cases eventually_atTop_nonneg_or_nonpos hf with + | inl hf' => + cases eventually_atTop_nonneg_or_nonpos hg with + | inl hg' => have hmain : (fun x => f x * g x) =ᶠ[atTop] fun x => |f x| * |g x| := by filter_upwards [hf', hg'] with x hx₁ hx₂ rw [abs_of_nonneg hx₁, abs_of_nonneg hx₂] rwa [iff_eventuallyEq hmain] - case inr => + | inr hg' => have hmain : (fun x => f x * g x) =ᶠ[atTop] fun x => -|f x| * |g x| := by filter_upwards [hf', hg'] with x hx₁ hx₂ simp [abs_of_nonneg hx₁, abs_of_nonpos hx₂] simp only [iff_eventuallyEq hmain, neg_mul] exact this.neg - case inr => - rcases eventually_atTop_nonneg_or_nonpos hg with hg'|hg' - case inl => + | inr hf' => + cases eventually_atTop_nonneg_or_nonpos hg with + | inl hg' => have hmain : (fun x => f x * g x) =ᶠ[atTop] fun x => -|f x| * |g x| := by filter_upwards [hf', hg'] with x hx₁ hx₂ rw [abs_of_nonpos hx₁, abs_of_nonneg hx₂, neg_neg] simp only [iff_eventuallyEq hmain, neg_mul] exact this.neg - case inr => + | inr hg' => have hmain : (fun x => f x * g x) =ᶠ[atTop] fun x => |f x| * |g x| := by filter_upwards [hf', hg'] with x hx₁ hx₂ simp [abs_of_nonpos hx₁, abs_of_nonpos hx₂] @@ -404,8 +404,8 @@ lemma GrowsPolynomially.add_isLittleO {f g : ℝ → ℝ} (hf : GrowsPolynomiall intro b hb have hb_ub := hb.2 rw [isLittleO_iff] at hfg - rcases hf.eventually_atTop_nonneg_or_nonpos with hf'|hf' - case inl => -- f is eventually nonneg + cases hf.eventually_atTop_nonneg_or_nonpos with + | inl hf' => -- f is eventually nonneg have hf := hf b hb obtain ⟨c₁, hc₁_mem : 0 < c₁, c₂, hc₂_mem : 0 < c₂, hf⟩ := hf specialize hfg (c := 1/2) (by norm_num) @@ -448,7 +448,7 @@ lemma GrowsPolynomially.add_isLittleO {f g : ℝ → ℝ} (hf : GrowsPolynomiall _ ≤ 3/2 * (c₂ * f x) := by gcongr; exact (hf₁ u ⟨hu_lb, hu_ub⟩).2 _ = 3*c₂ * (1/2 * f x) := by ring _ ≤ 3*c₂ * (f x + g x) := by gcongr - case inr => -- f is eventually nonpos + | inr hf' => -- f is eventually nonpos have hf := hf b hb obtain ⟨c₁, hc₁_mem : 0 < c₁, c₂, hc₂_mem : 0 < c₂, hf⟩ := hf specialize hfg (c := 1/2) (by norm_num) @@ -507,23 +507,23 @@ lemma GrowsPolynomially.add_isLittleO {f g : ℝ → ℝ} (hf : GrowsPolynomiall protected lemma GrowsPolynomially.inv {f : ℝ → ℝ} (hf : GrowsPolynomially f) : GrowsPolynomially fun x => (f x)⁻¹ := by - rcases hf.eventually_atTop_zero_or_pos_or_neg with hf'|hf_pos_or_neg - case inl => + cases hf.eventually_atTop_zero_or_pos_or_neg with + | inl hf' => refine fun b hb => ⟨1, by simp, 1, by simp, ?_⟩ have hb_pos := hb.1 filter_upwards [hf', (tendsto_id.const_mul_atTop hb_pos).eventually_forall_ge_atTop hf'] with x hx hx' intro u hu simp only [hx, inv_zero, mul_zero, Set.Icc_self, Set.mem_singleton_iff, hx' u hu.1] - case inr => + | inr hf_pos_or_neg => suffices : GrowsPolynomially fun x => |(f x)⁻¹| - · rcases hf_pos_or_neg with hf'|hf' - case inl => + · cases hf_pos_or_neg with + | inl hf' => have hmain : (fun x => (f x)⁻¹) =ᶠ[atTop] fun x => |(f x)⁻¹| := by filter_upwards [hf'] with x hx₁ rw [abs_of_nonneg (inv_nonneg_of_nonneg (le_of_lt hx₁))] rwa [iff_eventuallyEq hmain] - case inr => + | inr hf' => have hmain : (fun x => (f x)⁻¹) =ᶠ[atTop] fun x => -|(f x)⁻¹| := by filter_upwards [hf'] with x hx₁ simp [abs_of_nonpos (inv_nonpos.mpr (le_of_lt hx₁))] @@ -566,8 +566,8 @@ protected lemma GrowsPolynomially.rpow (p : ℝ) (hf : GrowsPolynomially f) obtain ⟨c₁, (hc₁_mem : 0 < c₁), c₂, hc₂_mem, hfnew⟩ := hf b hb have hc₁p : 0 < c₁ ^ p := Real.rpow_pos_of_pos hc₁_mem _ have hc₂p : 0 < c₂ ^ p := Real.rpow_pos_of_pos hc₂_mem _ - obtain _ | hp := le_or_lt 0 p - case inl => -- 0 ≤ p + cases le_or_lt 0 p with + | inl => -- 0 ≤ p refine ⟨c₁^p, hc₁p, ?_⟩ refine ⟨c₂^p, hc₂p, ?_⟩ filter_upwards [eventually_gt_atTop 0, hfnew, hf_nonneg, @@ -582,9 +582,9 @@ protected lemma GrowsPolynomially.rpow (p : ℝ) (hf : GrowsPolynomially f) case ub => calc (f u)^p ≤ (c₂ * f x)^p := by gcongr; exact (hf₁ u hu).2 _ = _ := by rw [← mul_rpow (le_of_lt hc₂_mem) hf_nonneg] - case inr => -- p < 0 - rcases hf.eventually_atTop_zero_or_pos_or_neg with hzero|hpos|hneg - case inl => -- eventually zero + | inr hp => -- p < 0 + match hf.eventually_atTop_zero_or_pos_or_neg with + | .inl hzero => -- eventually zero refine ⟨1, by norm_num, 1, by norm_num, ?_⟩ filter_upwards [hzero, hfnew] with x hx hx' intro u hu @@ -592,7 +592,7 @@ protected lemma GrowsPolynomially.rpow (p : ℝ) (hf : GrowsPolynomially f) Set.Icc_self, Set.mem_singleton_iff] simp only [hx, mul_zero, Set.Icc_self, Set.mem_singleton_iff] at hx' rw [hx' u hu, zero_rpow (ne_of_lt hp)] - case inr.inl => -- eventually positive + | .inr (.inl hpos) => -- eventually positive refine ⟨c₂^p, hc₂p, ?_⟩ refine ⟨c₁^p, hc₁p, ?_⟩ filter_upwards [eventually_gt_atTop 0, hfnew, hpos, @@ -607,7 +607,7 @@ protected lemma GrowsPolynomially.rpow (p : ℝ) (hf : GrowsPolynomially f) (f u)^p ≤ (c₁ * f x)^p := by exact rpow_le_rpow_of_exponent_nonpos (by positivity) (hf₁ u hu).1 (le_of_lt hp) _ = _ := by rw [← mul_rpow (le_of_lt hc₁_mem) (le_of_lt hf_pos)] - case inr.inr => -- eventually negative (which is impossible) + | .inr (.inr hneg) => -- eventually negative (which is impossible) have : ∀ᶠ (_:ℝ) in atTop, False := by filter_upwards [hf_nonneg, hneg] with x hx hx'; linarith rw [Filter.eventually_false_iff_eq_bot] at this exact False.elim <| (atTop_neBot).ne this diff --git a/Mathlib/Computability/Halting.lean b/Mathlib/Computability/Halting.lean index 755dccdae6d70..d7a10223b7fa1 100644 --- a/Mathlib/Computability/Halting.lean +++ b/Mathlib/Computability/Halting.lean @@ -297,10 +297,10 @@ open Nat (Partrec') open Nat.Partrec' theorem to_part {n f} (pf : @Partrec' n f) : _root_.Partrec f := by - induction pf - case prim n f hf => exact hf.to_prim.to_comp - case comp m n f g _ _ hf hg => exact (Partrec.vector_mOfFn fun i => hg i).bind (hf.comp snd) - case rfind n f _ hf => + induction pf with + | prim hf => exact hf.to_prim.to_comp + | comp _ _ _ hf hg => exact (Partrec.vector_mOfFn hg).bind (hf.comp snd) + | rfind _ hf => have := hf.comp (vector_cons.comp snd fst) have := ((Primrec.eq.comp _root_.Primrec.id (_root_.Primrec.const 0)).to_comp.comp diff --git a/Mathlib/Computability/PartrecCode.lean b/Mathlib/Computability/PartrecCode.lean index f7c6351f3a951..9207729655b42 100644 --- a/Mathlib/Computability/PartrecCode.lean +++ b/Mathlib/Computability/PartrecCode.lean @@ -696,36 +696,36 @@ theorem smn : #align nat.partrec.code.smn Nat.Partrec.Code.smn /-- A function is partial recursive if and only if there is a code implementing it. -/ -theorem exists_code {f : ℕ →. ℕ} : Nat.Partrec f ↔ ∃ c : Code, eval c = f := - ⟨fun h => by - induction h - case zero => exact ⟨zero, rfl⟩ - case succ => exact ⟨succ, rfl⟩ - case left => exact ⟨left, rfl⟩ - case right => exact ⟨right, rfl⟩ - case pair f g pf pg hf hg => +theorem exists_code {f : ℕ →. ℕ} : Nat.Partrec f ↔ ∃ c : Code, eval c = f := by + refine ⟨fun h => ?_, ?_⟩ + · induction h with + | zero => exact ⟨zero, rfl⟩ + | succ => exact ⟨succ, rfl⟩ + | left => exact ⟨left, rfl⟩ + | right => exact ⟨right, rfl⟩ + | pair pf pg hf hg => rcases hf with ⟨cf, rfl⟩; rcases hg with ⟨cg, rfl⟩ exact ⟨pair cf cg, rfl⟩ - case comp f g pf pg hf hg => + | comp pf pg hf hg => rcases hf with ⟨cf, rfl⟩; rcases hg with ⟨cg, rfl⟩ exact ⟨comp cf cg, rfl⟩ - case prec f g pf pg hf hg => + | prec pf pg hf hg => rcases hf with ⟨cf, rfl⟩; rcases hg with ⟨cg, rfl⟩ exact ⟨prec cf cg, rfl⟩ - case rfind f pf hf => + | rfind pf hf => rcases hf with ⟨cf, rfl⟩ refine' ⟨comp (rfind' cf) (pair Code.id zero), _⟩ - simp [eval, Seq.seq, pure, PFun.pure, Part.map_id'], - fun h => by - rcases h with ⟨c, rfl⟩; induction c - case zero => exact Nat.Partrec.zero - case succ => exact Nat.Partrec.succ - case left => exact Nat.Partrec.left - case right => exact Nat.Partrec.right - case pair cf cg pf pg => exact pf.pair pg - case comp cf cg pf pg => exact pf.comp pg - case prec cf cg pf pg => exact pf.prec pg - case rfind' cf pf => exact pf.rfind'⟩ + simp [eval, Seq.seq, pure, PFun.pure, Part.map_id'] + · rintro ⟨c, rfl⟩ + induction c with + | zero => exact Nat.Partrec.zero + | succ => exact Nat.Partrec.succ + | left => exact Nat.Partrec.left + | right => exact Nat.Partrec.right + | pair cf cg pf pg => exact pf.pair pg + | comp cf cg pf pg => exact pf.comp pg + | prec cf cg pf pg => exact pf.prec pg + | rfind' cf pf => exact pf.rfind' #align nat.partrec.code.exists_code Nat.Partrec.Code.exists_code -- Porting note: `>>`s in `evaln` are now `>>=` because `>>`s are not elaborated well in Lean4. @@ -858,73 +858,72 @@ theorem evaln_sound : ∀ {k c n x}, x ∈ evaln k c n → x ∈ eval c n exact ⟨z, by simpa [Nat.succ_eq_add_one, add_comm, add_left_comm] using hz, z0⟩ #align nat.partrec.code.evaln_sound Nat.Partrec.Code.evaln_sound -theorem evaln_complete {c n x} : x ∈ eval c n ↔ ∃ k, x ∈ evaln k c n := - ⟨fun h => by - rsuffices ⟨k, h⟩ : ∃ k, x ∈ evaln (k + 1) c n - · exact ⟨k + 1, h⟩ - induction c generalizing n x <;> simp [eval, evaln, pure, PFun.pure, Seq.seq, Bind.bind] at h ⊢ - iterate 4 exact ⟨⟨_, le_rfl⟩, h.symm⟩ - case pair cf cg hf hg => - rcases h with ⟨x, hx, y, hy, rfl⟩ - rcases hf hx with ⟨k₁, hk₁⟩; rcases hg hy with ⟨k₂, hk₂⟩ - refine' ⟨max k₁ k₂, _⟩ +theorem evaln_complete {c n x} : x ∈ eval c n ↔ ∃ k, x ∈ evaln k c n := by + refine ⟨fun h => ?_, fun ⟨k, h⟩ => evaln_sound h⟩ + rsuffices ⟨k, h⟩ : ∃ k, x ∈ evaln (k + 1) c n + · exact ⟨k + 1, h⟩ + induction c generalizing n x with simp [eval, evaln, pure, PFun.pure, Seq.seq, Bind.bind] at h ⊢ + | pair cf cg hf hg => + rcases h with ⟨x, hx, y, hy, rfl⟩ + rcases hf hx with ⟨k₁, hk₁⟩; rcases hg hy with ⟨k₂, hk₂⟩ + refine' ⟨max k₁ k₂, _⟩ + refine' + ⟨le_max_of_le_left <| Nat.le_of_lt_succ <| evaln_bound hk₁, _, + evaln_mono (Nat.succ_le_succ <| le_max_left _ _) hk₁, _, + evaln_mono (Nat.succ_le_succ <| le_max_right _ _) hk₂, rfl⟩ + | comp cf cg hf hg => + rcases h with ⟨y, hy, hx⟩ + rcases hg hy with ⟨k₁, hk₁⟩; rcases hf hx with ⟨k₂, hk₂⟩ + refine' ⟨max k₁ k₂, _⟩ + exact + ⟨le_max_of_le_left <| Nat.le_of_lt_succ <| evaln_bound hk₁, _, + evaln_mono (Nat.succ_le_succ <| le_max_left _ _) hk₁, + evaln_mono (Nat.succ_le_succ <| le_max_right _ _) hk₂⟩ + | prec cf cg hf hg => + revert h + generalize n.unpair.1 = n₁; generalize n.unpair.2 = n₂ + induction' n₂ with m IH generalizing x n <;> simp + · intro h + rcases hf h with ⟨k, hk⟩ + exact ⟨_, le_max_left _ _, evaln_mono (Nat.succ_le_succ <| le_max_right _ _) hk⟩ + · intro y hy hx + rcases IH hy with ⟨k₁, nk₁, hk₁⟩ + rcases hg hx with ⟨k₂, hk₂⟩ refine' - ⟨le_max_of_le_left <| Nat.le_of_lt_succ <| evaln_bound hk₁, _, - evaln_mono (Nat.succ_le_succ <| le_max_left _ _) hk₁, _, - evaln_mono (Nat.succ_le_succ <| le_max_right _ _) hk₂, rfl⟩ - case comp cf cg hf hg => - rcases h with ⟨y, hy, hx⟩ - rcases hg hy with ⟨k₁, hk₁⟩; rcases hf hx with ⟨k₂, hk₂⟩ - refine' ⟨max k₁ k₂, _⟩ - exact - ⟨le_max_of_le_left <| Nat.le_of_lt_succ <| evaln_bound hk₁, _, - evaln_mono (Nat.succ_le_succ <| le_max_left _ _) hk₁, - evaln_mono (Nat.succ_le_succ <| le_max_right _ _) hk₂⟩ - case prec cf cg hf hg => - revert h - generalize n.unpair.1 = n₁; generalize n.unpair.2 = n₂ - induction' n₂ with m IH generalizing x n <;> simp - · intro h - rcases hf h with ⟨k, hk⟩ - exact ⟨_, le_max_left _ _, evaln_mono (Nat.succ_le_succ <| le_max_right _ _) hk⟩ - · intro y hy hx - rcases IH hy with ⟨k₁, nk₁, hk₁⟩ - rcases hg hx with ⟨k₂, hk₂⟩ - refine' - ⟨(max k₁ k₂).succ, - Nat.le_succ_of_le <| le_max_of_le_left <| - le_trans (le_max_left _ (Nat.pair n₁ m)) nk₁, y, - evaln_mono (Nat.succ_le_succ <| le_max_left _ _) _, - evaln_mono (Nat.succ_le_succ <| Nat.le_succ_of_le <| le_max_right _ _) hk₂⟩ - simp only [evaln._eq_8, bind, unpaired, unpair_pair, Option.mem_def, Option.bind_eq_some, - Option.guard_eq_some', exists_and_left, exists_const] - exact ⟨le_trans (le_max_right _ _) nk₁, hk₁⟩ - case rfind' cf hf => - rcases h with ⟨y, ⟨hy₁, hy₂⟩, rfl⟩ - suffices ∃ k, y + n.unpair.2 ∈ evaln (k + 1) (rfind' cf) (Nat.pair n.unpair.1 n.unpair.2) by - simpa [evaln, Bind.bind] - revert hy₁ hy₂ - generalize n.unpair.2 = m - intro hy₁ hy₂ - induction' y with y IH generalizing m <;> simp [evaln, Bind.bind] - · simp at hy₁ - rcases hf hy₁ with ⟨k, hk⟩ - exact ⟨_, Nat.le_of_lt_succ <| evaln_bound hk, _, hk, by simp; rfl⟩ - · rcases hy₂ (Nat.succ_pos _) with ⟨a, ha, a0⟩ - rcases hf ha with ⟨k₁, hk₁⟩ - rcases IH m.succ (by simpa [Nat.succ_eq_add_one, add_comm, add_left_comm] using hy₁) - fun {i} hi => by - simpa [Nat.succ_eq_add_one, add_comm, add_left_comm] using - hy₂ (Nat.succ_lt_succ hi) with - ⟨k₂, hk₂⟩ - use (max k₁ k₂).succ - rw [zero_add] at hk₁ - use Nat.le_succ_of_le <| le_max_of_le_left <| Nat.le_of_lt_succ <| evaln_bound hk₁ - use a - use evaln_mono (Nat.succ_le_succ <| Nat.le_succ_of_le <| le_max_left _ _) hk₁ - simpa [Nat.succ_eq_add_one, a0, -max_eq_left, -max_eq_right, add_comm, add_left_comm] using - evaln_mono (Nat.succ_le_succ <| le_max_right _ _) hk₂, - fun ⟨k, h⟩ => evaln_sound h⟩ + ⟨(max k₁ k₂).succ, + Nat.le_succ_of_le <| le_max_of_le_left <| + le_trans (le_max_left _ (Nat.pair n₁ m)) nk₁, y, + evaln_mono (Nat.succ_le_succ <| le_max_left _ _) _, + evaln_mono (Nat.succ_le_succ <| Nat.le_succ_of_le <| le_max_right _ _) hk₂⟩ + simp only [evaln._eq_8, bind, unpaired, unpair_pair, Option.mem_def, Option.bind_eq_some, + Option.guard_eq_some', exists_and_left, exists_const] + exact ⟨le_trans (le_max_right _ _) nk₁, hk₁⟩ + | rfind' cf hf => + rcases h with ⟨y, ⟨hy₁, hy₂⟩, rfl⟩ + suffices ∃ k, y + n.unpair.2 ∈ evaln (k + 1) (rfind' cf) (Nat.pair n.unpair.1 n.unpair.2) by + simpa [evaln, Bind.bind] + revert hy₁ hy₂ + generalize n.unpair.2 = m + intro hy₁ hy₂ + induction' y with y IH generalizing m <;> simp [evaln, Bind.bind] + · simp at hy₁ + rcases hf hy₁ with ⟨k, hk⟩ + exact ⟨_, Nat.le_of_lt_succ <| evaln_bound hk, _, hk, by simp; rfl⟩ + · rcases hy₂ (Nat.succ_pos _) with ⟨a, ha, a0⟩ + rcases hf ha with ⟨k₁, hk₁⟩ + rcases IH m.succ (by simpa [Nat.succ_eq_add_one, add_comm, add_left_comm] using hy₁) + fun {i} hi => by + simpa [Nat.succ_eq_add_one, add_comm, add_left_comm] using + hy₂ (Nat.succ_lt_succ hi) with + ⟨k₂, hk₂⟩ + use (max k₁ k₂).succ + rw [zero_add] at hk₁ + use Nat.le_succ_of_le <| le_max_of_le_left <| Nat.le_of_lt_succ <| evaln_bound hk₁ + use a + use evaln_mono (Nat.succ_le_succ <| Nat.le_succ_of_le <| le_max_left _ _) hk₁ + simpa [Nat.succ_eq_add_one, a0, -max_eq_left, -max_eq_right, add_comm, add_left_comm] using + evaln_mono (Nat.succ_le_succ <| le_max_right _ _) hk₂ + | _ => exact ⟨⟨_, le_rfl⟩, h.symm⟩ #align nat.partrec.code.evaln_complete Nat.Partrec.Code.evaln_complete section diff --git a/Mathlib/Computability/Primrec.lean b/Mathlib/Computability/Primrec.lean index eec9bbc1a0dcd..2cffe2ec1024d 100644 --- a/Mathlib/Computability/Primrec.lean +++ b/Mathlib/Computability/Primrec.lean @@ -1377,12 +1377,12 @@ namespace Nat.Primrec' open Vector Primrec theorem to_prim {n f} (pf : @Nat.Primrec' n f) : Primrec f := by - induction pf - case zero => exact .const 0 - case succ => exact _root_.Primrec.succ.comp .vector_head - case get n i => exact Primrec.vector_get.comp .id (.const i) - case comp m n f g _ _ hf hg => exact hf.comp (.vector_ofFn fun i => hg i) - case prec n f g _ _ hf hg => + induction pf with + | zero => exact .const 0 + | succ => exact _root_.Primrec.succ.comp .vector_head + | get i => exact Primrec.vector_get.comp .id (.const i) + | comp _ _ _ hf hg => exact hf.comp (.vector_ofFn fun i => hg i) + | @prec n f g _ _ hf hg => exact .nat_rec' .vector_head (hf.comp Primrec.vector_tail) (hg.comp <| @@ -1525,14 +1525,14 @@ theorem of_prim {n f} : Primrec f → @Primrec' n f := Primrec'.encode).of_eq fun i => by simp [encodek] fun f hf => by - induction hf - case zero => exact const 0 - case succ => exact succ - case left => exact unpair₁ head - case right => exact unpair₂ head - case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg - case comp f g _ _ hf hg => exact hf.comp₁ _ hg - case prec f g _ _ hf hg => + induction hf with + | zero => exact const 0 + | succ => exact succ + | left => exact unpair₁ head + | right => exact unpair₂ head + | pair _ _ hf hg => exact natPair.comp₂ _ hf hg + | comp _ _ hf hg => exact hf.comp₁ _ hg + | prec _ _ hf hg => simpa using prec' (unpair₂ head) (hf.comp₁ _ (unpair₁ head)) (hg.comp₁ _ <| diff --git a/Mathlib/Computability/RegularExpressions.lean b/Mathlib/Computability/RegularExpressions.lean index 0571a9bac91ed..7185404a5d691 100644 --- a/Mathlib/Computability/RegularExpressions.lean +++ b/Mathlib/Computability/RegularExpressions.lean @@ -315,11 +315,11 @@ theorem star_rmatch_iff (P : RegularExpression α) : constructor · simp [hs, hsum] · intro t' ht' - cases ht' - case head ht' => + cases ht' with + | head ht' => simp only [ne_eq, not_false_iff, true_and, rmatch] exact ht - case tail ht' => exact helem t' ht' + | tail _ ht' => exact helem t' ht' · rintro ⟨S, hsum, helem⟩ cases' x with a x · rfl @@ -349,23 +349,23 @@ theorem star_rmatch_iff (P : RegularExpression α) : @[simp] theorem rmatch_iff_matches' (P : RegularExpression α) (x : List α) : P.rmatch x ↔ x ∈ P.matches' := by - induction P generalizing x - case zero => + induction P generalizing x with + | zero => rw [zero_def, zero_rmatch] tauto - case epsilon => + | epsilon => rw [one_def, one_rmatch_iff] rfl - case char => + | char => rw [char_rmatch_iff] rfl - case plus _ _ ih₁ ih₂ => + | plus _ _ ih₁ ih₂ => rw [plus_def, add_rmatch_iff, ih₁, ih₂] rfl - case comp P Q ih₁ ih₂ => + | comp P Q ih₁ ih₂ => simp only [comp_def, mul_rmatch_iff, matches'_mul, Language.mem_mul, *] tauto - case star _ ih => + | star _ ih => simp only [star_rmatch_iff, matches'_star, ih, Language.mem_kstar_iff_exists_nonempty, and_comm] #align regular_expression.rmatch_iff_matches RegularExpression.rmatch_iff_matches' diff --git a/Mathlib/Computability/TMToPartrec.lean b/Mathlib/Computability/TMToPartrec.lean index 4818e9c1406e8..342de6f9053b7 100644 --- a/Mathlib/Computability/TMToPartrec.lean +++ b/Mathlib/Computability/TMToPartrec.lean @@ -284,56 +284,57 @@ theorem exists_code.comp {m n} {f : Vector ℕ n →. ℕ} {g : Fin n → Vector theorem exists_code {n} {f : Vector ℕ n →. ℕ} (hf : Nat.Partrec' f) : ∃ c : Code, ∀ v : Vector ℕ n, c.eval v.1 = pure <$> f v := by - induction' hf with n f hf - induction hf - case prim.zero => exact ⟨zero', fun ⟨[], _⟩ => rfl⟩ - case prim.succ => exact ⟨succ, fun ⟨[v], _⟩ => rfl⟩ - case prim.get n i => - refine' Fin.succRec (fun n => _) (fun n i IH => _) i - · exact ⟨head, fun ⟨List.cons a as, _⟩ => by simp [Bind.bind]; rfl⟩ - · obtain ⟨c, h⟩ := IH - exact ⟨c.comp tail, fun v => by simpa [← Vector.get_tail, Bind.bind] using h v.tail⟩ - case prim.comp m n f g hf hg IHf IHg => - simpa [Part.bind_eq_bind] using exists_code.comp IHf IHg - case prim.prec n f g _ _ IHf IHg => - obtain ⟨cf, hf⟩ := IHf - obtain ⟨cg, hg⟩ := IHg - simp only [Part.map_eq_map, Part.map_some, PFun.coe_val] at hf hg - refine' ⟨prec cf cg, fun v => _⟩ - rw [← v.cons_head_tail] - specialize hf v.tail - replace hg := fun a b => hg (a ::ᵥ b ::ᵥ v.tail) - simp only [Vector.cons_val, Vector.tail_val] at hf hg - simp only [Part.map_eq_map, Part.map_some, Vector.cons_val, Vector.tail_cons, Vector.head_cons, - PFun.coe_val, Vector.tail_val] - simp only [← Part.pure_eq_some] at hf hg ⊢ - induction' v.head with n _ <;> - simp [prec, hf, Part.bind_assoc, ← Part.bind_some_eq_map, Part.bind_some, - show ∀ x, pure x = [x] from fun _ => rfl, Bind.bind, Functor.map] - suffices ∀ a b, a + b = n → - (n.succ :: 0 :: - g (n ::ᵥ Nat.rec (f v.tail) (fun y IH => g (y ::ᵥ IH ::ᵥ v.tail)) n ::ᵥ v.tail) :: - v.val.tail : List ℕ) ∈ - PFun.fix - (fun v : List ℕ => Part.bind (cg.eval (v.headI :: v.tail.tail)) - (fun x => Part.some (if v.tail.headI = 0 - then Sum.inl - (v.headI.succ :: v.tail.headI.pred :: x.headI :: v.tail.tail.tail : List ℕ) - else Sum.inr - (v.headI.succ :: v.tail.headI.pred :: x.headI :: v.tail.tail.tail)))) - (a :: b :: Nat.rec (f v.tail) (fun y IH => g (y ::ᵥ IH ::ᵥ v.tail)) a :: v.val.tail) by - erw [Part.eq_some_iff.2 (this 0 n (zero_add n))] - simp only [List.headI, Part.bind_some, List.tail_cons] - intro a b e - induction' b with b IH generalizing a - · refine' PFun.mem_fix_iff.2 (Or.inl <| Part.eq_some_iff.1 _) - simp only [hg, ← e, Part.bind_some, List.tail_cons, pure] - rfl - · refine' PFun.mem_fix_iff.2 (Or.inr ⟨_, _, IH (a + 1) (by rwa [add_right_comm])⟩) - simp only [hg, eval, Part.bind_some, Nat.rec_add_one, List.tail_nil, List.tail_cons, pure] - exact Part.mem_some_iff.2 rfl - case comp m n f g _ _ IHf IHg => exact exists_code.comp IHf IHg - case rfind n f _ IHf => + induction hf with + | prim hf => + induction hf with + | zero => exact ⟨zero', fun ⟨[], _⟩ => rfl⟩ + | succ => exact ⟨succ, fun ⟨[v], _⟩ => rfl⟩ + | get i => + refine' Fin.succRec (fun n => _) (fun n i IH => _) i + · exact ⟨head, fun ⟨List.cons a as, _⟩ => by simp [Bind.bind]; rfl⟩ + · obtain ⟨c, h⟩ := IH + exact ⟨c.comp tail, fun v => by simpa [← Vector.get_tail, Bind.bind] using h v.tail⟩ + | comp g hf hg IHf IHg => + simpa [Part.bind_eq_bind] using exists_code.comp IHf IHg + | @prec n f g _ _ IHf IHg => + obtain ⟨cf, hf⟩ := IHf + obtain ⟨cg, hg⟩ := IHg + simp only [Part.map_eq_map, Part.map_some, PFun.coe_val] at hf hg + refine' ⟨prec cf cg, fun v => _⟩ + rw [← v.cons_head_tail] + specialize hf v.tail + replace hg := fun a b => hg (a ::ᵥ b ::ᵥ v.tail) + simp only [Vector.cons_val, Vector.tail_val] at hf hg + simp only [Part.map_eq_map, Part.map_some, Vector.cons_val, Vector.tail_cons, + Vector.head_cons, PFun.coe_val, Vector.tail_val] + simp only [← Part.pure_eq_some] at hf hg ⊢ + induction' v.head with n _ <;> + simp [prec, hf, Part.bind_assoc, ← Part.bind_some_eq_map, Part.bind_some, + show ∀ x, pure x = [x] from fun _ => rfl, Bind.bind, Functor.map] + suffices ∀ a b, a + b = n → + (n.succ :: 0 :: + g (n ::ᵥ Nat.rec (f v.tail) (fun y IH => g (y ::ᵥ IH ::ᵥ v.tail)) n ::ᵥ v.tail) :: + v.val.tail : List ℕ) ∈ + PFun.fix + (fun v : List ℕ => Part.bind (cg.eval (v.headI :: v.tail.tail)) + (fun x => Part.some (if v.tail.headI = 0 + then Sum.inl + (v.headI.succ :: v.tail.headI.pred :: x.headI :: v.tail.tail.tail : List ℕ) + else Sum.inr + (v.headI.succ :: v.tail.headI.pred :: x.headI :: v.tail.tail.tail)))) + (a :: b :: Nat.rec (f v.tail) (fun y IH => g (y ::ᵥ IH ::ᵥ v.tail)) a :: v.val.tail) by + erw [Part.eq_some_iff.2 (this 0 n (zero_add n))] + simp only [List.headI, Part.bind_some, List.tail_cons] + intro a b e + induction' b with b IH generalizing a + · refine' PFun.mem_fix_iff.2 (Or.inl <| Part.eq_some_iff.1 _) + simp only [hg, ← e, Part.bind_some, List.tail_cons, pure] + rfl + · refine' PFun.mem_fix_iff.2 (Or.inr ⟨_, _, IH (a + 1) (by rwa [add_right_comm])⟩) + simp only [hg, eval, Part.bind_some, Nat.rec_add_one, List.tail_nil, List.tail_cons, pure] + exact Part.mem_some_iff.2 rfl + | comp g _ _ IHf IHg => exact exists_code.comp IHf IHg + | @rfind n f _ IHf => obtain ⟨cf, hf⟩ := IHf; refine' ⟨rfind cf, fun v => _⟩ replace hf := fun a => hf (a ::ᵥ v) simp only [Part.map_eq_map, Part.map_some, Vector.cons_val, PFun.coe_val, @@ -566,30 +567,30 @@ equality, not a simulation; the original and embedded machines move in lock-step embedded machine reaches the halt state. -/ theorem stepNormal_then (c) (k k' : Cont) (v) : stepNormal c (k.then k') v = (stepNormal c k v).then k' := by - induction c generalizing k v <;> simp only [Cont.then, stepNormal, *] <;> - try { simp only [Cfg.then]; done } - case cons c c' ih _ => rw [← ih, Cont.then] - case comp c c' _ ih' => rw [← ih', Cont.then] - · cases v.headI <;> simp only [Nat.rec] - case fix c ih => rw [← ih, Cont.then] + induction c generalizing k v with simp only [Cont.then, stepNormal, *] + | cons c c' ih _ => rw [← ih, Cont.then] + | comp c c' _ ih' => rw [← ih', Cont.then] + | case => cases v.headI <;> simp only [Nat.rec] + | fix c ih => rw [← ih, Cont.then] + | _ => simp only [Cfg.then] #align turing.to_partrec.step_normal_then Turing.ToPartrec.stepNormal_then /-- The `stepRet` function respects the `then k'` homomorphism. Note that this is an exact equality, not a simulation; the original and embedded machines move in lock-step until the embedded machine reaches the halt state. -/ theorem stepRet_then {k k' : Cont} {v} : stepRet (k.then k') v = (stepRet k v).then k' := by - induction k generalizing v <;> simp only [Cont.then, stepRet, *] <;> - try { simp only [Cfg.then]; done } - case cons₁ => + induction k generalizing v with simp only [Cont.then, stepRet, *] + | cons₁ => rw [← stepNormal_then] rfl - case comp => + | comp => rw [← stepNormal_then] - case fix _ k_ih => + | fix _ _ k_ih => split_ifs · rw [← k_ih] · rw [← stepNormal_then] rfl + | _ => simp only [Cfg.then] #align turing.to_partrec.step_ret_then Turing.ToPartrec.stepRet_then /-- This is a temporary definition, because we will prove in `code_is_ok` that it always holds. @@ -611,15 +612,15 @@ theorem Code.Ok.zero {c} (h : Code.Ok c) {v} : #align turing.to_partrec.code.ok.zero Turing.ToPartrec.Code.Ok.zero theorem stepNormal.is_ret (c k v) : ∃ k' v', stepNormal c k v = Cfg.ret k' v' := by - induction c generalizing k v - iterate 3 exact ⟨_, _, rfl⟩ - case cons _f fs IHf _IHfs => apply IHf - case comp f _g _IHf IHg => apply IHg - case case f g IHf IHg => + induction c generalizing k v with + | cons _f fs IHf _IHfs => apply IHf + | comp f _g _IHf IHg => apply IHg + | case f g IHf IHg => rw [stepNormal] simp only [] cases v.headI <;> simp only [] <;> [apply IHf; apply IHg] - case fix f IHf => apply IHf + | fix f IHf => apply IHf + | _ => exact ⟨_, _, rfl⟩ #align turing.to_partrec.step_normal.is_ret Turing.ToPartrec.stepNormal.is_ret theorem cont_eval_fix {f k v} (fok : Code.Ok f) : @@ -696,23 +697,23 @@ theorem cont_eval_fix {f k v} (fok : Code.Ok f) : #align turing.to_partrec.cont_eval_fix Turing.ToPartrec.cont_eval_fix theorem code_is_ok (c) : Code.Ok c := by - induction c <;> intro k v <;> rw [stepNormal] - iterate 3 simp only [Code.eval, pure_bind] - case cons f fs IHf IHfs => + induction c with (intro k v; rw [stepNormal]) + | cons f fs IHf IHfs => rw [Code.eval, IHf] simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v rw [reaches_eval]; swap; exact ReflTransGen.single rfl rw [stepRet, IHfs]; congr; funext v' refine' Eq.trans _ (Eq.symm _) <;> try exact reaches_eval (ReflTransGen.single rfl) - case comp f g IHf IHg => + | comp f g IHf IHg => rw [Code.eval, IHg] simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v rw [reaches_eval]; swap; exact ReflTransGen.single rfl rw [stepRet, IHf] - case case f g IHf IHg => + | case f g IHf IHg => simp only [Code.eval] cases v.headI <;> simp only [Code.eval] <;> [apply IHf; apply IHg] - case fix f IHf => rw [cont_eval_fix IHf] + | fix f IHf => rw [cont_eval_fix IHf] + | _ => simp only [Code.eval, pure_bind] #align turing.to_partrec.code_is_ok Turing.ToPartrec.code_is_ok theorem stepNormal_eval (c v) : eval step (stepNormal c Cont.halt v) = Cfg.halt <$> c.eval v := @@ -720,22 +721,22 @@ theorem stepNormal_eval (c v) : eval step (stepNormal c Cont.halt v) = Cfg.halt #align turing.to_partrec.step_normal_eval Turing.ToPartrec.stepNormal_eval theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by - induction k generalizing v - case halt => + induction k generalizing v with + | halt => simp only [mem_eval, Cont.eval, map_pure] exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩) - case cons₁ fs as k IH => + | cons₁ fs as k IH => rw [Cont.eval, stepRet, code_is_ok] simp only [← bind_pure_comp, bind_assoc]; congr; funext v' rw [reaches_eval]; swap; exact ReflTransGen.single rfl rw [stepRet, IH, bind_pure_comp] - case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH - case comp f k IH => + | cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH + | comp f k IH => rw [Cont.eval, stepRet, code_is_ok] simp only [← bind_pure_comp, bind_assoc]; congr; funext v' rw [reaches_eval]; swap; exact ReflTransGen.single rfl rw [IH, bind_pure_comp] - case fix f k IH => + | fix f k IH => rw [Cont.eval, stepRet]; simp only [bind_pure_comp] split_ifs; · exact IH simp only [← bind_pure_comp, bind_assoc, cont_eval_fix (code_is_ok _)] @@ -947,31 +948,9 @@ instance Λ'.instInhabited : Inhabited Λ' := #align turing.partrec_to_TM2.Λ'.inhabited Turing.PartrecToTM2.Λ'.instInhabited instance Λ'.instDecidableEq : DecidableEq Λ' := fun a b => by - induction a generalizing b <;> cases b <;> try apply Decidable.isFalse; rintro ⟨⟨⟩⟩; done - case move.move _ _ _ _ I _ _ _ _ => - letI := I - exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) - case clear.clear _ _ _ I _ _ _ => - letI := I - exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) - case copy.copy _ I _ => - letI := I - exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) - case push.push _ _ _ I _ _ _ => - letI := I - exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) - case read.read _ I _ => - letI := I - exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) - case succ.succ _ I _ => - letI := I - exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) - case pred.pred _ _ I₁ I₂ _ _ => - letI := I₁ - letI := I₂ - exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) - case ret.ret _ _ => - exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) + induction a generalizing b <;> cases b <;> first + | apply Decidable.isFalse; rintro ⟨⟨⟩⟩; done + | exact decidable_of_iff' _ (by simp [Function.funext_iff]; rfl) #align turing.partrec_to_TM2.Λ'.decidable_eq Turing.PartrecToTM2.Λ'.instDecidableEq /-- The type of TM2 statements used by this machine. -/ @@ -1614,16 +1593,15 @@ theorem trNormal_respects (c k v s) : TrCfg (stepNormal c k v) b₂ ∧ Reaches₁ (TM2.step tr) ⟨some (trNormal c (trCont k)), s, K'.elim (trList v) [] [] (trContStack k)⟩ b₂ := by - induction c generalizing k v s - case zero' => refine' ⟨_, ⟨s, rfl⟩, TransGen.single _⟩; simp - case succ => refine' ⟨_, ⟨none, rfl⟩, head_main_ok.trans succ_ok⟩ - case tail => + induction c generalizing k v s with + | zero' => refine' ⟨_, ⟨s, rfl⟩, TransGen.single _⟩; simp + | succ => refine' ⟨_, ⟨none, rfl⟩, head_main_ok.trans succ_ok⟩ + | tail => let o : Option Γ' := List.casesOn v none fun _ _ => some Γ'.cons refine' ⟨_, ⟨o, rfl⟩, _⟩; convert clear_ok _ using 2; simp; rfl; swap refine' splitAtPred_eq _ _ (trNat v.headI) _ _ (trNat_natEnd _) _ cases v <;> simp - case - cons f fs IHf _ => + | cons f fs IHf _ => obtain ⟨c, h₁, h₂⟩ := IHf (Cont.cons₁ fs v k) v none refine' ⟨c, h₁, TransGen.head rfl <| (move_ok (by decide) (splitAtPred_false _)).trans _⟩ simp only [TM2.step, Option.mem_def, elim_stack, elim_update_stack, elim_update_main, ne_eq, @@ -1631,8 +1609,8 @@ theorem trNormal_respects (c k v s) : refine' (copy_ok _ none [] (trList v).reverse _ _).trans _ convert h₂ using 2 simp [List.reverseAux_eq, trContStack] - case comp f _ _ IHg => exact IHg (Cont.comp f k) v s - case case f g IHf IHg => + | comp f _ _ IHg => exact IHg (Cont.comp f k) v s + | case f g IHf IHg => rw [stepNormal] simp only obtain ⟨s', h⟩ := pred_ok _ _ s v _ _ @@ -1641,17 +1619,16 @@ theorem trNormal_respects (c k v s) : exact ⟨_, h₁, h.trans h₂⟩ · obtain ⟨c, h₁, h₂⟩ := IHg k _ s' exact ⟨_, h₁, h.trans h₂⟩ - case fix f IH => apply IH + | fix f IH => apply IH #align turing.partrec_to_TM2.tr_normal_respects Turing.PartrecToTM2.trNormal_respects theorem tr_ret_respects (k v s) : ∃ b₂, TrCfg (stepRet k v) b₂ ∧ Reaches₁ (TM2.step tr) ⟨some (Λ'.ret (trCont k)), s, K'.elim (trList v) [] [] (trContStack k)⟩ b₂ := by - induction k generalizing v s - case halt => exact ⟨_, rfl, TransGen.single rfl⟩ - case - cons₁ fs as k _ => + induction k generalizing v s with + | halt => exact ⟨_, rfl, TransGen.single rfl⟩ + | cons₁ fs as k _ => obtain ⟨s', h₁, h₂⟩ := trNormal_respects fs (Cont.cons₂ v k) as none refine' ⟨s', h₁, TransGen.head rfl _⟩; simp refine' (move₂_ok (by decide) _ (splitAtPred_false _)).trans _; · rfl @@ -1667,13 +1644,13 @@ theorem tr_ret_respects (k v s) : ∃ b₂, List.append_nil, elim_update_main, id_eq, elim_update_aux, ne_eq, Function.update_noteq, elim_aux, elim_stack] exact h₂ - case cons₂ ns k IH => + | cons₂ ns k IH => obtain ⟨c, h₁, h₂⟩ := IH (ns.headI :: v) none exact ⟨c, h₁, TransGen.head rfl <| head_stack_ok.trans h₂⟩ - case comp f k _ => + | comp f k _ => obtain ⟨s', h₁, h₂⟩ := trNormal_respects f k v s exact ⟨_, h₁, TransGen.head rfl h₂⟩ - case fix f k IH => + | fix f k IH => rw [stepRet] have : if v.headI = 0 then natEnd (trList v).head?.iget = true ∧ (trList v).tail = trList v.tail @@ -1953,12 +1930,12 @@ theorem head_supports {S k q} (H : (q : Λ').Supports S) : (head k q).Supports S theorem ret_supports {S k} (H₁ : contSupp k ⊆ S) : TM2.SupportsStmt S (tr (Λ'.ret k)) := by have W := fun {q} => trStmts₁_self q - cases k - case halt => trivial - case cons₁ => rw [contSupp_cons₁, Finset.union_subset_iff] at H₁; exact fun _ => H₁.1 W - case cons₂ => rw [contSupp_cons₂, Finset.union_subset_iff] at H₁; exact fun _ => H₁.1 W - case comp => rw [contSupp_comp] at H₁; exact fun _ => H₁ (codeSupp_self _ _ W) - case fix => + cases k with + | halt => trivial + | cons₁ => rw [contSupp_cons₁, Finset.union_subset_iff] at H₁; exact fun _ => H₁.1 W + | cons₂ => rw [contSupp_cons₂, Finset.union_subset_iff] at H₁; exact fun _ => H₁.1 W + | comp => rw [contSupp_comp] at H₁; exact fun _ => H₁ (codeSupp_self _ _ W) + | fix => rw [contSupp_fix] at H₁ have L := @Finset.mem_union_left; have R := @Finset.mem_union_right intro s; dsimp only; cases natEnd s.iget @@ -1998,27 +1975,24 @@ theorem trStmts₁_supports' {S q K} (H₁ : (q : Λ').Supports S) (H₂ : trStm #align turing.partrec_to_TM2.tr_stmts₁_supports' Turing.PartrecToTM2.trStmts₁_supports' theorem trNormal_supports {S c k} (Hk : codeSupp c k ⊆ S) : (trNormal c k).Supports S := by - induction c generalizing k <;> simp [Λ'.Supports, head] - case zero' => exact Finset.union_subset_right Hk - case succ => intro; split_ifs <;> exact Finset.union_subset_right Hk - case tail => exact Finset.union_subset_right Hk - case cons f fs IHf _ => + induction c generalizing k with simp [Λ'.Supports, head] + | zero' => exact Finset.union_subset_right Hk + | succ => intro; split_ifs <;> exact Finset.union_subset_right Hk + | tail => exact Finset.union_subset_right Hk + | cons f fs IHf _ => apply IHf rw [codeSupp_cons] at Hk exact Finset.union_subset_right Hk - case comp f g _ IHg => apply IHg; rw [codeSupp_comp] at Hk; exact Finset.union_subset_right Hk - case - case f g IHf IHg => + | comp f g _ IHg => apply IHg; rw [codeSupp_comp] at Hk; exact Finset.union_subset_right Hk + | case f g IHf IHg => simp only [codeSupp_case, Finset.union_subset_iff] at Hk exact ⟨IHf Hk.2.1, IHg Hk.2.2⟩ - case fix f IHf => apply IHf; rw [codeSupp_fix] at Hk; exact Finset.union_subset_right Hk + | fix f IHf => apply IHf; rw [codeSupp_fix] at Hk; exact Finset.union_subset_right Hk #align turing.partrec_to_TM2.tr_normal_supports Turing.PartrecToTM2.trNormal_supports theorem codeSupp'_supports {S c k} (H : codeSupp c k ⊆ S) : Supports (codeSupp' c k) S := by - induction c generalizing k - iterate 3 - exact trStmts₁_supports (trNormal_supports H) (Finset.Subset.trans (codeSupp_self _ _) H) - case cons f fs IHf IHfs => + induction c generalizing k with + | cons f fs IHf IHfs => have H' := H; simp only [codeSupp_cons, Finset.union_subset_iff] at H' refine' trStmts₁_supports' (trNormal_supports H) (Finset.union_subset_left H) fun h => _ refine' supports_union.2 ⟨IHf H'.2, _⟩ @@ -2031,7 +2005,7 @@ theorem codeSupp'_supports {S c k} (H : codeSupp c k ⊆ S) : Supports (codeSupp exact trStmts₁_supports (head_supports <| Finset.union_subset_right H) (Finset.union_subset_right h) - case comp f g IHf IHg => + | comp f g IHf IHg => have H' := H; rw [codeSupp_comp] at H'; have H' := Finset.union_subset_right H' refine' trStmts₁_supports' (trNormal_supports H) (Finset.union_subset_left H) fun h => _ refine' supports_union.2 ⟨IHg H', _⟩ @@ -2039,11 +2013,11 @@ theorem codeSupp'_supports {S c k} (H : codeSupp c k ⊆ S) : Supports (codeSupp · simp only [codeSupp', codeSupp, Finset.union_subset_iff, contSupp] at h H ⊢ exact ⟨h.2.2, H.2⟩ exact IHf (Finset.union_subset_right H') - case case f g IHf IHg => + | case f g IHf IHg => have H' := H; simp only [codeSupp_case, Finset.union_subset_iff] at H' refine' trStmts₁_supports' (trNormal_supports H) (Finset.union_subset_left H) fun _ => _ exact supports_union.2 ⟨IHf H'.2.1, IHg H'.2.2⟩ - case fix f IHf => + | fix f IHf => have H' := H; simp only [codeSupp_fix, Finset.union_subset_iff] at H' refine' trStmts₁_supports' (trNormal_supports H) (Finset.union_subset_left H) fun h => _ refine' supports_union.2 ⟨IHf H'.2, _⟩ @@ -2052,24 +2026,25 @@ theorem codeSupp'_supports {S c k} (H : codeSupp c k ⊆ S) : Supports (codeSupp Finset.insert_subset_iff] at h H ⊢ exact ⟨h.1, ⟨H.1.1, h⟩, H.2⟩ exact supports_singleton.2 (ret_supports <| Finset.union_subset_right H) + | _ => exact trStmts₁_supports (trNormal_supports H) (Finset.Subset.trans (codeSupp_self _ _) H) #align turing.partrec_to_TM2.code_supp'_supports Turing.PartrecToTM2.codeSupp'_supports theorem contSupp_supports {S k} (H : contSupp k ⊆ S) : Supports (contSupp k) S := by - induction k - · simp [contSupp_halt, Supports] - case cons₁ f k IH => + induction k with + | halt => simp [contSupp_halt, Supports] + | cons₁ f k IH => have H₁ := H; rw [contSupp_cons₁] at H₁; have H₂ := Finset.union_subset_right H₁ refine' trStmts₁_supports' (trNormal_supports H₂) H₁ fun h => _ refine' supports_union.2 ⟨codeSupp'_supports H₂, _⟩ simp only [codeSupp, contSupp_cons₂, Finset.union_subset_iff] at H₂ exact trStmts₁_supports' (head_supports H₂.2.2) (Finset.union_subset_right h) IH - case cons₂ k IH => + | cons₂ k IH => have H' := H; rw [contSupp_cons₂] at H' exact trStmts₁_supports' (head_supports <| Finset.union_subset_right H') H' IH - case comp f k IH => + | comp f k IH => have H' := H; rw [contSupp_comp] at H'; have H₂ := Finset.union_subset_right H' exact supports_union.2 ⟨codeSupp'_supports H', IH H₂⟩ - case fix f k IH => + | fix f k IH => rw [contSupp] at H exact supports_union.2 ⟨codeSupp'_supports H, IH (Finset.union_subset_right H)⟩ #align turing.partrec_to_TM2.cont_supp_supports Turing.PartrecToTM2.contSupp_supports diff --git a/Mathlib/Computability/TuringMachine.lean b/Mathlib/Computability/TuringMachine.lean index bb407555229ca..fd523cfeab727 100644 --- a/Mathlib/Computability/TuringMachine.lean +++ b/Mathlib/Computability/TuringMachine.lean @@ -1321,32 +1321,32 @@ theorem stmts₁_self {q : Stmt₁} : q ∈ stmts₁ q := by theorem stmts₁_trans {q₁ q₂ : Stmt₁} : q₁ ∈ stmts₁ q₂ → stmts₁ q₁ ⊆ stmts₁ q₂ := by intro h₁₂ q₀ h₀₁ - induction' q₂ with _ q IH _ q IH _ q IH <;> simp only [stmts₁] at h₁₂ ⊢ <;> - simp only [Finset.mem_insert, Finset.mem_union, Finset.mem_singleton] at h₁₂ - iterate 3 - rcases h₁₂ with (rfl | h₁₂) - · unfold stmts₁ at h₀₁ - exact h₀₁ - · exact Finset.mem_insert_of_mem (IH h₁₂) - case branch p q₁ q₂ IH₁ IH₂ => + induction q₂ with ( + simp only [stmts₁] at h₁₂ ⊢ + simp only [Finset.mem_insert, Finset.mem_union, Finset.mem_singleton] at h₁₂) + | branch p q₁ q₂ IH₁ IH₂ => rcases h₁₂ with (rfl | h₁₂ | h₁₂) · unfold stmts₁ at h₀₁ exact h₀₁ · exact Finset.mem_insert_of_mem (Finset.mem_union_left _ <| IH₁ h₁₂) · exact Finset.mem_insert_of_mem (Finset.mem_union_right _ <| IH₂ h₁₂) - case goto l => subst h₁₂; exact h₀₁ - case halt => subst h₁₂; exact h₀₁ + | goto l => subst h₁₂; exact h₀₁ + | halt => subst h₁₂; exact h₀₁ + | _ _ q IH => + rcases h₁₂ with rfl | h₁₂ + · exact h₀₁ + · exact Finset.mem_insert_of_mem (IH h₁₂) #align turing.TM1.stmts₁_trans Turing.TM1.stmts₁_trans theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt₁} (h : q₁ ∈ stmts₁ q₂) (hs : SupportsStmt S q₂) : SupportsStmt S q₁ := by - induction' q₂ with _ q IH _ q IH _ q IH <;> + induction q₂ with simp only [stmts₁, SupportsStmt, Finset.mem_insert, Finset.mem_union, Finset.mem_singleton] at h hs - iterate 3 rcases h with (rfl | h) <;> [exact hs; exact IH h hs] - case branch p q₁ q₂ IH₁ IH₂ => rcases h with (rfl | h | h); exacts [hs, IH₁ h hs.1, IH₂ h hs.2] - case goto l => subst h; exact hs - case halt => subst h; trivial + | branch p q₁ q₂ IH₁ IH₂ => rcases h with (rfl | h | h); exacts [hs, IH₁ h hs.1, IH₂ h hs.2] + | goto l => subst h; exact hs + | halt => subst h; trivial + | _ _ q IH => rcases h with (rfl | h) <;> [exact hs; exact IH h hs] #align turing.TM1.stmts₁_supports_stmt_mono Turing.TM1.stmts₁_supportsStmt_mono /-- The set of all statements in a Turing machine, plus one extra value `none` representing the @@ -1383,14 +1383,14 @@ theorem step_supports (M : Λ → Stmt₁) {S : Finset Λ} (ss : Supports M S) : | ⟨some l₁, v, T⟩, c', h₁, h₂ => by replace h₂ := ss.2 _ (Finset.some_mem_insertNone.1 h₂) simp only [step, Option.mem_def, Option.some.injEq] at h₁; subst c' - revert h₂; induction' M l₁ with _ q IH _ q IH _ q IH generalizing v T <;> intro hs - iterate 3 exact IH _ _ hs - case branch p q₁' q₂' IH₁ IH₂ => + revert h₂; induction M l₁ generalizing v T with intro hs + | branch p q₁' q₂' IH₁ IH₂ => unfold stepAux; cases p T.1 v · exact IH₂ _ _ hs.2 · exact IH₁ _ _ hs.1 - case goto => exact Finset.some_mem_insertNone.2 (hs _ _) - case halt => apply Multiset.mem_cons_self + | goto => exact Finset.some_mem_insertNone.2 (hs _ _) + | halt => apply Multiset.mem_cons_self + | _ _ q IH => exact IH _ _ hs #align turing.TM1.step_supports Turing.TM1.step_supports variable [Inhabited σ] @@ -1501,15 +1501,15 @@ theorem tr_respects : fun_respects.2 fun ⟨l₁, v, T⟩ ↦ by cases' l₁ with l₁; · exact rfl simp only [trCfg, TM1.step, FRespects, Option.map] - induction' M l₁ with _ _ IH _ _ IH _ _ IH generalizing v T - case move _ _ IH => exact TransGen.head rfl (IH _ _) - case write _ _ IH => exact TransGen.head rfl (IH _ _) - case load _ _ IH => exact (reaches₁_eq (by rfl)).2 (IH _ _) - case branch p _ _ IH₁ IH₂ => + induction M l₁ generalizing v T with + | move _ _ IH => exact TransGen.head rfl (IH _ _) + | write _ _ IH => exact TransGen.head rfl (IH _ _) + | load _ _ IH => exact (reaches₁_eq (by rfl)).2 (IH _ _) + | branch p _ _ IH₁ IH₂ => unfold TM1.stepAux; cases e : p T.1 v · exact (reaches₁_eq (by simp only [TM0.step, tr, trAux, e]; rfl)).2 (IH₂ _ _) · exact (reaches₁_eq (by simp only [TM0.step, tr, trAux, e]; rfl)).2 (IH₁ _ _) - iterate 2 + | _ => exact TransGen.single (congr_arg some (congr (congr_arg TM0.Cfg.mk rfl) (Tape.write_self T))) #align turing.TM1to0.tr_respects Turing.TM1to0.tr_respects @@ -1550,20 +1550,20 @@ theorem tr_supports {S : Finset Λ} (ss : TM1.Supports M S) : cases q'; · exact Multiset.mem_cons_self _ _ simp only [tr, Option.mem_def] at h₁ have := TM1.stmts_supportsStmt ss h₂ - revert this; induction q generalizing v <;> intro hs - case move d q => + revert this; induction q generalizing v with intro hs + | move d q => cases h₁; refine' TM1.stmts_trans _ h₂ unfold TM1.stmts₁ exact Finset.mem_insert_of_mem TM1.stmts₁_self - case write b q => + | write b q => cases h₁; refine' TM1.stmts_trans _ h₂ unfold TM1.stmts₁ exact Finset.mem_insert_of_mem TM1.stmts₁_self - case load b q IH => + | load b q IH => refine' IH _ (TM1.stmts_trans _ h₂) h₁ hs unfold TM1.stmts₁ exact Finset.mem_insert_of_mem TM1.stmts₁_self - case branch p q₁ q₂ IH₁ IH₂ => + | branch p q₁ q₂ IH₁ IH₂ => cases h : p a v <;> rw [trAux, h] at h₁ · refine' IH₂ _ (TM1.stmts_trans _ h₂) h₁ hs.2 unfold TM1.stmts₁ @@ -1571,10 +1571,10 @@ theorem tr_supports {S : Finset Λ} (ss : TM1.Supports M S) : · refine' IH₁ _ (TM1.stmts_trans _ h₂) h₁ hs.1 unfold TM1.stmts₁ exact Finset.mem_insert_of_mem (Finset.mem_union_left _ TM1.stmts₁_self) - case goto l => + | goto l => cases h₁ exact Finset.some_mem_insertNone.2 (Finset.mem_biUnion.2 ⟨_, hs _ _, TM1.stmts₁_self⟩) - case halt => cases h₁ + | halt => cases h₁ #align turing.TM1to0.tr_supports Turing.TM1to0.tr_supports end @@ -1859,30 +1859,30 @@ theorem tr_respects {enc₀} : exact this _ R clear R l₁ intro q R - induction' q generalizing v L R - case move d q IH => + induction q generalizing v L R with + | move d q IH => cases d <;> simp only [trNormal, iterate, stepAux_move, stepAux, ListBlank.head_cons, Tape.move_left_mk', ListBlank.cons_head_tail, ListBlank.tail_cons, trTape'_move_left enc0, trTape'_move_right enc0] <;> apply IH - case write f q IH => + | write f q IH => simp only [trNormal, stepAux_read dec enc0 encdec, stepAux] refine' ReflTransGen.head rfl _ obtain ⟨a, R, rfl⟩ := R.exists_cons rw [tr, Tape.mk'_head, stepAux_write, ListBlank.head_cons, stepAux_move, trTape'_move_left enc0, ListBlank.head_cons, ListBlank.tail_cons, Tape.write_mk'] apply IH - case load a q IH => + | load a q IH => simp only [trNormal, stepAux_read dec enc0 encdec] apply IH - case branch p q₁ q₂ IH₁ IH₂ => + | branch p q₁ q₂ IH₁ IH₂ => simp only [trNormal, stepAux_read dec enc0 encdec, stepAux] cases p R.head v <;> [apply IH₂; apply IH₁] - case goto l => + | goto l => simp only [trNormal, stepAux_read dec enc0 encdec, stepAux, trCfg, trTape_mk'] apply ReflTransGen.refl - case halt => + | halt => simp only [trNormal, stepAux, trCfg, stepAux_move, trTape'_move_left enc0, trTape'_move_right enc0, trTape_mk'] apply ReflTransGen.refl @@ -1919,12 +1919,12 @@ theorem tr_supports {S : Finset Λ} (ss : Supports M S) : Supports (tr enc dec M rcases Finset.mem_insert.1 h with (rfl | h) exacts [this.1, this.2 _ h] intro q hs hw - induction q - case move d q IH => + induction q with + | move d q IH => unfold writes at hw ⊢ replace IH := IH hs hw; refine' ⟨_, IH.2⟩ cases d <;> simp only [trNormal, iterate, supportsStmt_move, IH] - case write f q IH => + | write f q IH => unfold writes at hw ⊢ simp only [Finset.mem_image, Finset.mem_union, Finset.mem_univ, exists_prop, true_and_iff] at hw ⊢ @@ -1933,21 +1933,21 @@ theorem tr_supports {S : Finset Λ} (ss : Supports M S) : Supports (tr enc dec M rcases hq with (⟨a, q₂, rfl⟩ | hq) · simp only [tr, supportsStmt_write, supportsStmt_move, IH.1] · exact IH.2 _ hq - case load a q IH => + | load a q IH => unfold writes at hw ⊢ replace IH := IH hs hw refine' ⟨supportsStmt_read _ fun _ ↦ IH.1, IH.2⟩ - case branch p q₁ q₂ IH₁ IH₂ => + | branch p q₁ q₂ IH₁ IH₂ => unfold writes at hw ⊢ simp only [Finset.mem_union] at hw ⊢ replace IH₁ := IH₁ hs.1 fun q hq ↦ hw q (Or.inl hq) replace IH₂ := IH₂ hs.2 fun q hq ↦ hw q (Or.inr hq) exact ⟨supportsStmt_read _ fun _ ↦ ⟨IH₁.1, IH₂.1⟩, fun q ↦ Or.rec (IH₁.2 _) (IH₂.2 _)⟩ - case goto l => + | goto l => simp only [writes, Finset.not_mem_empty]; refine' ⟨_, fun _ ↦ False.elim⟩ refine' supportsStmt_read _ fun a _ s ↦ _ exact Finset.mem_biUnion.2 ⟨_, hs _ _, Finset.mem_insert_self _ _⟩ - case halt => + | halt => simp only [writes, Finset.not_mem_empty]; refine' ⟨_, fun _ ↦ False.elim⟩ simp only [SupportsStmt, supportsStmt_move, trNormal]⟩ #align turing.TM1to1.tr_supports Turing.TM1to1.tr_supports @@ -2191,32 +2191,33 @@ theorem stmts₁_self {q : Stmt₂} : q ∈ stmts₁ q := by theorem stmts₁_trans {q₁ q₂ : Stmt₂} : q₁ ∈ stmts₁ q₂ → stmts₁ q₁ ⊆ stmts₁ q₂ := by intro h₁₂ q₀ h₀₁ - induction' q₂ with _ _ q IH _ _ q IH _ _ q IH _ q IH <;> simp only [stmts₁] at h₁₂ ⊢ <;> - simp only [Finset.mem_insert, Finset.mem_singleton, Finset.mem_union] at h₁₂ - iterate 4 - rcases h₁₂ with (rfl | h₁₂) - · unfold stmts₁ at h₀₁ - exact h₀₁ - · exact Finset.mem_insert_of_mem (IH h₁₂) - case branch f q₁ q₂ IH₁ IH₂ => + induction q₂ with ( + simp only [stmts₁] at h₁₂ ⊢ + simp only [Finset.mem_insert, Finset.mem_singleton, Finset.mem_union] at h₁₂) + | branch f q₁ q₂ IH₁ IH₂ => rcases h₁₂ with (rfl | h₁₂ | h₁₂) · unfold stmts₁ at h₀₁ exact h₀₁ · exact Finset.mem_insert_of_mem (Finset.mem_union_left _ (IH₁ h₁₂)) · exact Finset.mem_insert_of_mem (Finset.mem_union_right _ (IH₂ h₁₂)) - case goto l => subst h₁₂; exact h₀₁ - case halt => subst h₁₂; exact h₀₁ + | goto l => subst h₁₂; exact h₀₁ + | halt => subst h₁₂; exact h₀₁ + | load _ q IH | _ _ _ q IH => + rcases h₁₂ with (rfl | h₁₂) + · unfold stmts₁ at h₀₁ + exact h₀₁ + · exact Finset.mem_insert_of_mem (IH h₁₂) #align turing.TM2.stmts₁_trans Turing.TM2.stmts₁_trans theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt₂} (h : q₁ ∈ stmts₁ q₂) (hs : SupportsStmt S q₂) : SupportsStmt S q₁ := by - induction' q₂ with _ _ q IH _ _ q IH _ _ q IH _ q IH <;> + induction q₂ with simp only [stmts₁, SupportsStmt, Finset.mem_insert, Finset.mem_union, Finset.mem_singleton] at h hs - iterate 4 rcases h with (rfl | h) <;> [exact hs; exact IH h hs] - case branch f q₁ q₂ IH₁ IH₂ => rcases h with (rfl | h | h); exacts [hs, IH₁ h hs.1, IH₂ h hs.2] - case goto l => subst h; exact hs - case halt => subst h; trivial + | branch f q₁ q₂ IH₁ IH₂ => rcases h with (rfl | h | h); exacts [hs, IH₁ h hs.1, IH₂ h hs.2] + | goto l => subst h; exact hs + | halt => subst h; trivial + | load _ _ IH | _ _ _ _ IH => rcases h with (rfl | h) <;> [exact hs; exact IH h hs] #align turing.TM2.stmts₁_supports_stmt_mono Turing.TM2.stmts₁_supportsStmt_mono /-- The set of statements accessible from initial set `S` of labels. -/ @@ -2251,14 +2252,14 @@ theorem step_supports (M : Λ → Stmt₂) {S : Finset Λ} (ss : Supports M S) : | ⟨some l₁, v, T⟩, c', h₁, h₂ => by replace h₂ := ss.2 _ (Finset.some_mem_insertNone.1 h₂) simp only [step, Option.mem_def, Option.some.injEq] at h₁; subst c' - revert h₂; induction' M l₁ with _ _ q IH _ _ q IH _ _ q IH _ q IH generalizing v T <;> intro hs - iterate 4 exact IH _ _ hs - case branch p q₁' q₂' IH₁ IH₂ => + revert h₂; induction M l₁ generalizing v T with intro hs + | branch p q₁' q₂' IH₁ IH₂ => unfold stepAux; cases p v · exact IH₂ _ _ hs.2 · exact IH₁ _ _ hs.1 - case goto => exact Finset.some_mem_insertNone.2 (hs _) - case halt => apply Multiset.mem_cons_self + | goto => exact Finset.some_mem_insertNone.2 (hs _) + | halt => apply Multiset.mem_cons_self + | load _ _ IH | _ _ _ _ IH => exact IH _ _ hs #align turing.TM2.step_supports Turing.TM2.step_supports variable [Inhabited σ] @@ -2556,8 +2557,8 @@ theorem tr_respects_aux₂ {k : K} {q : Stmt₂₁} {v : σ} {S : ∀ k, List ( TM1.stepAux (trStAct q o) v ((Tape.move Dir.right)^[(S k).length] (Tape.mk' ∅ (addBottom L))) = TM1.stepAux q v' ((Tape.move Dir.right)^[(S' k).length] (Tape.mk' ∅ (addBottom L'))) := by - dsimp only; simp; cases o <;> simp only [stWrite, stVar, trStAct, TM1.stepAux] - case push f => + dsimp only; simp; cases o with simp only [stWrite, stVar, trStAct, TM1.stepAux] + | push f => have := Tape.write_move_right_n fun a : Γ' ↦ (a.1, update a.2 k (some (f v))) refine' ⟨_, fun k' ↦ _, by @@ -2586,7 +2587,7 @@ theorem tr_respects_aux₂ {k : K} {q : Stmt₂₁} {v : σ} {S : ∀ k, List ( List.length_append, List.length_map] · split_ifs <;> rw [Function.update_noteq h', ← proj_map_nth, hL] rw [Function.update_noteq h'] - case peek f => + | peek f => rw [Function.update_eq_self] use L, hL; rw [Tape.move_left_right]; congr cases e : S k; · rfl @@ -2594,7 +2595,7 @@ theorem tr_respects_aux₂ {k : K} {q : Stmt₂₁} {v : σ} {S : ∀ k, List ( Tape.move_right_n_head, Tape.mk'_nth_nat, addBottom_nth_snd, stk_nth_val _ (hL k), e, List.reverse_cons, ← List.length_reverse, List.get?_concat_length] rfl - case pop f => + | pop f => cases' e : S k with hd tl · simp only [Tape.mk'_head, ListBlank.head_cons, Tape.move_left_mk', List.length, Tape.write_mk', List.head?, iterate_zero_apply, List.tail_nil] diff --git a/Mathlib/Control/Fold.lean b/Mathlib/Control/Fold.lean index e30d6b1ab5f57..6ea46443cbd3a 100644 --- a/Mathlib/Control/Fold.lean +++ b/Mathlib/Control/Fold.lean @@ -382,9 +382,9 @@ theorem foldr_map (g : β → γ) (f : γ → α → α) (a : α) (l : t β) : @[simp] theorem toList_eq_self {xs : List α} : toList xs = xs := by simp only [toList_spec, foldMap, traverse] - induction xs - case nil => rfl - case cons _ _ ih => conv_rhs => rw [← ih]; rfl + induction xs with + | nil => rfl + | cons _ _ ih => conv_rhs => rw [← ih]; rfl #align traversable.to_list_eq_self Traversable.toList_eq_self theorem length_toList {xs : t α} : length xs = List.length (toList xs) := by diff --git a/Mathlib/Data/List/BigOperators/Basic.lean b/Mathlib/Data/List/BigOperators/Basic.lean index 92b1aa09509f2..454854f55a781 100644 --- a/Mathlib/Data/List/BigOperators/Basic.lean +++ b/Mathlib/Data/List/BigOperators/Basic.lean @@ -291,12 +291,12 @@ of `∀ a ∈ l₂, 1 ≤ a` but this lemma is not yet in `mathlib`. -/ theorem Sublist.prod_le_prod' [Preorder M] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] [CovariantClass M M (· * ·) (· ≤ ·)] {l₁ l₂ : List M} (h : l₁ <+ l₂) (h₁ : ∀ a ∈ l₂, (1 : M) ≤ a) : l₁.prod ≤ l₂.prod := by - induction h - case slnil => rfl - case cons l₁ l₂ a _ ih' => + induction h with + | slnil => rfl + | cons a _ ih' => simp only [prod_cons, forall_mem_cons] at h₁ ⊢ exact (ih' h₁.2).trans (le_mul_of_one_le_left' h₁.1) - case cons₂ l₁ l₂ a _ ih' => + | cons₂ a _ ih' => simp only [prod_cons, forall_mem_cons] at h₁ ⊢ exact mul_le_mul_left' (ih' h₁.2) _ #align list.sublist.prod_le_prod' List.Sublist.prod_le_prod' diff --git a/Mathlib/Data/List/EditDistance/Defs.lean b/Mathlib/Data/List/EditDistance/Defs.lean index bf4bd6a00415f..358eb311864ef 100644 --- a/Mathlib/Data/List/EditDistance/Defs.lean +++ b/Mathlib/Data/List/EditDistance/Defs.lean @@ -124,10 +124,9 @@ theorem impl_cons_fst_zero (h) (w' : 0 < List.length ds) : theorem impl_length (d : {r : List δ // 0 < r.length}) (w : d.1.length = xs.length + 1) : (impl C xs y d).1.length = xs.length + 1 := by - induction xs generalizing d - · case nil => - rfl - · case cons x xs ih => + induction xs generalizing d with + | nil => rfl + | cons x xs ih => dsimp [impl] match d, w with | ⟨d₁ :: d₂ :: ds, _⟩, w => @@ -164,14 +163,14 @@ variable {C} theorem suffixLevenshtein_length (xs : List α) (ys : List β) : (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by - induction ys - · case nil => + induction ys with + | nil => dsimp [suffixLevenshtein] - induction xs - · case nil => rfl - · case cons _ xs ih => + induction xs with + | nil => rfl + | cons _ xs ih => simp_all - · case cons y ys ih => + | cons y ys ih => dsimp [suffixLevenshtein] rw [impl_length] exact ih @@ -229,10 +228,10 @@ theorem suffixLevenshtein_cons₁ suffixLevenshtein C (x :: xs) ys = ⟨levenshtein C (x :: xs) ys :: (suffixLevenshtein C xs ys).1, by simp⟩ := by - induction ys - · case nil => + induction ys with + | nil => dsimp [levenshtein, suffixLevenshtein] - · case cons y ys ih => + | cons y ys ih => apply suffixLevenshtein_cons₁_aux · rfl · rw [suffixLevenshtein_cons₂ (x :: xs), ih, impl_cons] @@ -265,10 +264,10 @@ theorem suffixLevenshtein_cons_cons_fst_get_zero theorem suffixLevenshtein_eq_tails_map (xs ys) : (suffixLevenshtein C xs ys).1 = xs.tails.map fun xs' => levenshtein C xs' ys := by - induction xs - · case nil => + induction xs with + | nil => simp only [List.map, suffixLevenshtein_nil'] - · case cons x xs ih => + | cons x xs ih => simp only [List.map, suffixLevenshtein_cons₁, ih] @[simp] diff --git a/Mathlib/Data/List/Func.lean b/Mathlib/Data/List/Func.lean index 5b078a11ff3e1..362cd548a1daa 100644 --- a/Mathlib/Data/List/Func.lean +++ b/Mathlib/Data/List/Func.lean @@ -170,20 +170,16 @@ theorem get_set_eq_of_ne {a : α} : contradiction cases as <;> simp only [set, get, get_nil] | as, k + 1, m, h1 => by - -- porting note : I somewhat rearranged the case split - cases as <;> cases m - case nil => - simp only [set, get] - case nil m => - have h3 : get m (nil {k ↦ a}) = default := by - rw [get_set_eq_of_ne k m, get_nil] - intro hc - apply h1 - simp [hc] - apply h3 - case zero => - simp only [set, get] - case _ _ m => + -- porting note: I somewhat rearranged the case split + match as, m with + | as, 0 => cases as <;> simp only [set, get] + | [], m+1 => + show get m (nil {k ↦ a}) = default + rw [get_set_eq_of_ne k m, get_nil] + intro hc + apply h1 + simp [hc] + | _::_, m+1 => apply get_set_eq_of_ne k m intro hc apply h1 diff --git a/Mathlib/Data/List/Perm.lean b/Mathlib/Data/List/Perm.lean index 7342462419e54..cb7aa7c2c7126 100644 --- a/Mathlib/Data/List/Perm.lean +++ b/Mathlib/Data/List/Perm.lean @@ -145,18 +145,17 @@ theorem perm_comp_perm : (Perm ∘r Perm : List α → List α → Prop) = Perm theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) : (Forall₂ r ∘r Perm) l v := by - induction hlu generalizing v - case nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩ - case cons a l u _hlu ih => + induction hlu generalizing v with + | nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩ + | cons u _hlu ih => cases' huv with _ b _ v hab huv' rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩ exact ⟨b :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩ - case swap a₁ a₂ h₂₃ => + | swap a₁ a₂ h₂₃ => cases' huv with _ b₁ _ l₂ h₁ hr₂₃ cases' hr₂₃ with _ b₂ _ l₂ h₂ h₁₂ exact ⟨b₂ :: b₁ :: l₂, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩ - case - trans la₁ la₂ la₃ _ _ ih₁ ih₂ => + | trans _ _ ih₁ ih₂ => rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩ rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩ exact ⟨lb₁, hab₁, Perm.trans h₁₂ h₂₃⟩ @@ -267,11 +266,11 @@ theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : Righ theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) : ∀ b, foldr f b l₁ = foldr f b l₂ := by intro b - induction p using Perm.recOnSwap' generalizing b - case nil => rfl - case cons r => simp; rw [r b] - case swap' r => simp; rw [lcomm, r b] - case trans r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b) + induction p using Perm.recOnSwap' generalizing b with + | nil => rfl + | cons _ _ r => simp; rw [r b] + | swap' _ _ _ r => simp; rw [lcomm, r b] + | trans _ _ r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b) #align list.perm.foldr_eq List.Perm.foldr_eq #align list.perm.rec_heq List.Perm.rec_heq @@ -358,16 +357,16 @@ alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) (h₁ : a ∉ l₁) (h₂ : a ∈ l₂) (s : l₁ <+~ l₂) : a :: l₁ <+~ l₂ := by rcases s with ⟨l, p, s⟩ - induction s generalizing l₁ - case slnil => cases h₂ - case cons r₁ r₂ b s' ih => + induction s generalizing l₁ with + | slnil => cases h₂ + | @cons r₁ r₂ b s' ih => simp? at h₂ says simp only [mem_cons] at h₂ cases' h₂ with e m · subst b exact ⟨a :: r₁, p.cons a, s'.cons₂ _⟩ · rcases ih d₁ h₁ m p with ⟨t, p', s'⟩ exact ⟨t, p', s'.cons _⟩ - case cons₂ r₁ r₂ b _ ih => + | @cons₂ r₁ r₂ b _ ih => have bm : b ∈ l₁ := p.subset <| mem_cons_self _ _ have am : a ∈ r₂ := by simp only [find?, mem_cons] at h₂ @@ -503,9 +502,9 @@ theorem Perm.dedup {l₁ l₂ : List α} (p : l₁ ~ l₂) : dedup l₁ ~ dedup theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) : l ∩ (t₁ ++ t₂) ~ l ∩ t₁ ++ l ∩ t₂ := by - induction l - case nil => simp - case cons x xs l_ih => + induction l with + | nil => simp + | cons x xs l_ih => by_cases h₁ : x ∈ t₁ · have h₂ : x ∉ t₂ := h h₁ simp [*] diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index 4d9ab07fff437..5021bd92f5060 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -157,11 +157,11 @@ theorem sublistsAux_eq_bind : theorem sublists_append (l₁ l₂ : List α) : sublists (l₁ ++ l₂) = (sublists l₂) >>= (fun x => (sublists l₁).map (· ++ x)) := by simp only [sublists, foldr_append] - induction l₁ - · case nil => simp - · case cons a l₁ ih => - rw [foldr_cons, ih] - simp [List.bind, join_join, Function.comp] + induction l₁ with + | nil => simp + | cons a l₁ ih => + rw [foldr_cons, ih] + simp [List.bind, join_join, Function.comp] #align list.sublists_append List.sublists_append --Portin note: New theorem diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index 08a0cb1fb359f..fdb2cb1b51825 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -2778,18 +2778,17 @@ theorem rel_eq {s t : Multiset α} : Rel (· = ·) s t ↔ s = t := by theorem Rel.mono {r p : α → β → Prop} {s t} (hst : Rel r s t) (h : ∀ a ∈ s, ∀ b ∈ t, r a b → p a b) : Rel p s t := by - induction hst - case zero => exact Rel.zero - case - cons a b s t hab _hst ih => + induction hst with + | zero => exact Rel.zero + | @cons a b s t hab _hst ih => apply Rel.cons (h a (mem_cons_self _ _) b (mem_cons_self _ _) hab) exact ih fun a' ha' b' hb' h' => h a' (mem_cons_of_mem ha') b' (mem_cons_of_mem hb') h' #align multiset.rel.mono Multiset.Rel.mono theorem Rel.add {s t u v} (hst : Rel r s t) (huv : Rel r u v) : Rel r (s + u) (t + v) := by - induction hst - case zero => simpa using huv - case cons a b s t hab hst ih => simpa using ih.cons hab + induction hst with + | zero => simpa using huv + | cons hab hst ih => simpa using ih.cons hab #align multiset.rel.add Multiset.Rel.add theorem rel_flip_eq {s t : Multiset α} : Rel (fun a b => b = a) s t ↔ s = t := @@ -2809,10 +2808,9 @@ theorem rel_cons_left {a as bs} : constructor · generalize hm : a ::ₘ as = m intro h - induction h generalizing as - case zero => simp at hm - case - cons a' b as' bs ha'b h ih => + induction h generalizing as with + | zero => simp at hm + | @cons a' b as' bs ha'b h ih => rcases cons_eq_cons.1 hm with (⟨eq₁, eq₂⟩ | ⟨_h, cs, eq₁, eq₂⟩) · subst eq₁ subst eq₂ diff --git a/Mathlib/Data/Multiset/Bind.lean b/Mathlib/Data/Multiset/Bind.lean index c4fc8b85216ba..275725fde8fad 100644 --- a/Mathlib/Data/Multiset/Bind.lean +++ b/Mathlib/Data/Multiset/Bind.lean @@ -76,9 +76,9 @@ theorem card_join (S) : card (@join α S) = sum (map card S) := #align multiset.card_join Multiset.card_join theorem rel_join {r : α → β → Prop} {s t} (h : Rel (Rel r) s t) : Rel r s.join t.join := by - induction h - case zero => simp - case cons a b s t hab hst ih => simpa using hab.add ih + induction h with + | zero => simp + | cons hab hst ih => simpa using hab.add ih #align multiset.rel_join Multiset.rel_join /-! ### Bind -/ diff --git a/Mathlib/Data/Multiset/Functor.lean b/Mathlib/Data/Multiset/Functor.lean index 7b98d000e794c..9866ed29c04a4 100644 --- a/Mathlib/Data/Multiset/Functor.lean +++ b/Mathlib/Data/Multiset/Functor.lean @@ -41,14 +41,14 @@ variable {α' β' : Type u} (f : α' → F β') def traverse : Multiset α' → F (Multiset β') := by refine' Quotient.lift (Functor.map Coe.coe ∘ Traversable.traverse f) _ introv p; unfold Function.comp - induction p - case nil => rfl - case cons x l₁ l₂ _ h => + induction p with + | nil => rfl + | @cons x l₁ l₂ _ h => have : Multiset.cons <$> f x <*> Coe.coe <$> Traversable.traverse f l₁ = Multiset.cons <$> f x <*> Coe.coe <$> Traversable.traverse f l₂ := by rw [h] simpa [functor_norm] using this - case swap x y l => + | swap x y l => have : (fun a b (l : List β') ↦ (↑(a :: b :: l) : Multiset β')) <$> f y <*> f x = (fun a b l ↦ ↑(a :: b :: l)) <$> f x <*> f y := by @@ -57,7 +57,7 @@ def traverse : Multiset α' → F (Multiset β') := by funext a b l simpa [flip] using Perm.swap a b l simp [(· ∘ ·), this, functor_norm, Coe.coe] - case trans => simp [*] + | trans => simp [*] #align multiset.traverse Multiset.traverse instance : Monad Multiset := diff --git a/Mathlib/Data/Multiset/Sections.lean b/Mathlib/Data/Multiset/Sections.lean index 66eb763db0f4b..ac7819f0a695e 100644 --- a/Mathlib/Data/Multiset/Sections.lean +++ b/Mathlib/Data/Multiset/Sections.lean @@ -58,9 +58,9 @@ theorem sections_add (s t : Multiset (Multiset α)) : theorem mem_sections {s : Multiset (Multiset α)} : ∀ {a}, a ∈ Sections s ↔ s.Rel (fun s a => a ∈ s) a := by - induction s using Multiset.induction_on - case empty => simp - case cons a a' ih => simp [ih, rel_cons_left, eq_comm] + induction s using Multiset.induction_on with + | empty => simp + | cons ih => simp [ih, rel_cons_left, eq_comm] #align multiset.mem_sections Multiset.mem_sections theorem card_sections {s : Multiset (Multiset α)} : card (Sections s) = prod (s.map card) := diff --git a/Mathlib/Data/MvPolynomial/Basic.lean b/Mathlib/Data/MvPolynomial/Basic.lean index 6120acc00166c..5bafaae1547a1 100644 --- a/Mathlib/Data/MvPolynomial/Basic.lean +++ b/Mathlib/Data/MvPolynomial/Basic.lean @@ -508,10 +508,10 @@ theorem algHom_C (f : MvPolynomial σ R →ₐ[R] MvPolynomial σ R) (r : R) : f theorem adjoin_range_X : Algebra.adjoin R (range (X : σ → MvPolynomial σ R)) = ⊤ := by set S := Algebra.adjoin R (range (X : σ → MvPolynomial σ R)) refine' top_unique fun p hp => _; clear hp - induction p using MvPolynomial.induction_on - case h_C => exact S.algebraMap_mem _ - case h_add p q hp hq => exact S.add_mem hp hq - case h_X p i hp => exact S.mul_mem hp (Algebra.subset_adjoin <| mem_range_self _) + induction p using MvPolynomial.induction_on with + | h_C => exact S.algebraMap_mem _ + | h_add p q hp hq => exact S.add_mem hp hq + | h_X p i hp => exact S.mul_mem hp (Algebra.subset_adjoin <| mem_range_self _) #align mv_polynomial.adjoin_range_X MvPolynomial.adjoin_range_X @[ext] diff --git a/Mathlib/Data/Nat/Choose/Sum.lean b/Mathlib/Data/Nat/Choose/Sum.lean index 7b884dc00bfe1..4fc5443a4c328 100644 --- a/Mathlib/Data/Nat/Choose/Sum.lean +++ b/Mathlib/Data/Nat/Choose/Sum.lean @@ -136,8 +136,9 @@ end Nat theorem Int.alternating_sum_range_choose {n : ℕ} : (∑ m in range (n + 1), ((-1) ^ m * ↑(choose n m) : ℤ)) = if n = 0 then 1 else 0 := by - cases n; · simp - case succ n => + cases n with + | zero => simp + | succ n => have h := add_pow (-1 : ℤ) 1 n.succ simp only [one_pow, mul_one, add_left_neg] at h rw [← h, zero_pow (Nat.succ_pos n), if_neg (Nat.succ_ne_zero n)] diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index 04a3e396ce47a..bee9a51e38009 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -70,8 +70,7 @@ of `p` in the factorization of `n`: we declare the former to be the simp-normal theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by rcases n.eq_zero_or_pos with (rfl | hn0) · simp [factorization, count] - by_cases pp : p.Prime - case neg => + if pp : p.Prime then ?_ else rw [count_eq_zero_of_not_mem (mt prime_of_mem_factors pp)] simp [factorization, pp] simp only [factorization, coe_mk, pp, if_true] @@ -337,8 +336,7 @@ theorem ord_compl_of_not_prime (n p : ℕ) (hp : ¬p.Prime) : ord_compl[p] n = n #align nat.ord_compl_of_not_prime Nat.ord_compl_of_not_prime theorem ord_proj_dvd (n p : ℕ) : ord_proj[p] n ∣ n := by - by_cases hp : p.Prime - case neg => simp [hp] + if hp : p.Prime then ?_ else simp [hp] rw [← factors_count_eq] apply dvd_of_factors_subperm (pow_ne_zero _ hp.ne_zero) rw [hp.factors_pow, List.subperm_ext_iff] @@ -351,9 +349,7 @@ theorem ord_compl_dvd (n p : ℕ) : ord_compl[p] n ∣ n := #align nat.ord_compl_dvd Nat.ord_compl_dvd theorem ord_proj_pos (n p : ℕ) : 0 < ord_proj[p] n := by - by_cases pp : p.Prime - · simp [pow_pos pp.pos] - · simp [pp] + if pp : p.Prime then simp [pow_pos pp.pos] else simp [pp] #align nat.ord_proj_pos Nat.ord_proj_pos theorem ord_proj_le {n : ℕ} (p : ℕ) (hn : n ≠ 0) : ord_proj[p] n ≤ n := @@ -361,9 +357,10 @@ theorem ord_proj_le {n : ℕ} (p : ℕ) (hn : n ≠ 0) : ord_proj[p] n ≤ n := #align nat.ord_proj_le Nat.ord_proj_le theorem ord_compl_pos {n : ℕ} (p : ℕ) (hn : n ≠ 0) : 0 < ord_compl[p] n := by - cases' em' p.Prime with pp pp - · simpa [Nat.factorization_eq_zero_of_non_prime n pp] using hn.bot_lt - exact Nat.div_pos (ord_proj_le p hn) (ord_proj_pos n p) + if pp : p.Prime then + exact Nat.div_pos (ord_proj_le p hn) (ord_proj_pos n p) + else + simpa [Nat.factorization_eq_zero_of_non_prime n pp] using hn.bot_lt #align nat.ord_compl_pos Nat.ord_compl_pos theorem ord_compl_le (n p : ℕ) : ord_compl[p] n ≤ n := @@ -380,10 +377,8 @@ theorem ord_proj_mul {a b : ℕ} (p : ℕ) (ha : a ≠ 0) (hb : b ≠ 0) : #align nat.ord_proj_mul Nat.ord_proj_mul theorem ord_compl_mul (a b p : ℕ) : ord_compl[p] (a * b) = ord_compl[p] a * ord_compl[p] b := by - rcases eq_or_ne a 0 with (rfl | ha) - · simp - rcases eq_or_ne b 0 with (rfl | hb) - · simp + if ha : a = 0 then simp [ha] else + if hb : b = 0 then simp [hb] else simp only [ord_proj_mul p ha hb] rw [mul_div_mul_comm_of_dvd_dvd (ord_proj_dvd a p) (ord_proj_dvd b p)] #align nat.ord_compl_mul Nat.ord_compl_mul @@ -401,11 +396,11 @@ theorem factorization_lt {n : ℕ} (p : ℕ) (hn : n ≠ 0) : n.factorization p /-- An upper bound on `n.factorization p` -/ theorem factorization_le_of_le_pow {n p b : ℕ} (hb : n ≤ p ^ b) : n.factorization p ≤ b := by - rcases eq_or_ne n 0 with (rfl | hn) - · simp - by_cases pp : p.Prime - · exact (pow_le_pow_iff_right pp.one_lt).1 ((ord_proj_le p hn).trans hb) - · simp [factorization_eq_zero_of_non_prime n pp] + if hn : n = 0 then simp [hn] else + if pp : p.Prime then + exact (pow_le_pow_iff_right pp.one_lt).1 ((ord_proj_le p hn).trans hb) + else + simp [factorization_eq_zero_of_non_prime n pp] #align nat.factorization_le_of_le_pow Nat.factorization_le_of_le_pow theorem factorization_le_iff_dvd {d n : ℕ} (hd : d ≠ 0) (hn : n ≠ 0) : @@ -501,9 +496,8 @@ theorem coprime_ord_compl {n p : ℕ} (hp : Prime p) (hn : n ≠ 0) : Coprime p theorem factorization_ord_compl (n p : ℕ) : (ord_compl[p] n).factorization = n.factorization.erase p := by - rcases eq_or_ne n 0 with (rfl | hn); · simp - by_cases pp : p.Prime - case neg => + if hn : n = 0 then simp [hn] else + if pp : p.Prime then ?_ else -- porting note: needed to solve side goal explicitly rw [Finsupp.erase_of_not_mem_support] <;> simp [pp] ext q @@ -517,14 +511,14 @@ theorem factorization_ord_compl (n p : ℕ) : -- `ord_compl[p] n` is the largest divisor of `n` not divisible by `p`. theorem dvd_ord_compl_of_dvd_not_dvd {p d n : ℕ} (hdn : d ∣ n) (hpd : ¬p ∣ d) : d ∣ ord_compl[p] n := by - rcases eq_or_ne n 0 with (rfl | hn0); · simp - rcases eq_or_ne d 0 with (rfl | hd0); - · simp at hpd + if hn0 : n = 0 then simp [hn0] else + if hd0 : d = 0 then simp [hd0] at hpd else rw [← factorization_le_iff_dvd hd0 (ord_compl_pos p hn0).ne', factorization_ord_compl] intro q - rcases eq_or_ne q p with (rfl | hqp) - · simp [factorization_eq_zero_iff, hpd] - · simp [hqp, (factorization_le_iff_dvd hd0 hn0).2 hdn q] + if hqp : q = p then + simp [factorization_eq_zero_iff, hqp, hpd] + else + simp [hqp, (factorization_le_iff_dvd hd0 hn0).2 hdn q] #align nat.dvd_ord_compl_of_dvd_not_dvd Nat.dvd_ord_compl_of_dvd_not_dvd /-- If `n` is a nonzero natural number and `p ≠ 1`, then there are natural numbers `e` @@ -591,10 +585,8 @@ theorem ord_compl_dvd_ord_compl_iff_dvd (a b : ℕ) : refine' ⟨fun h => _, fun hab p => ord_compl_dvd_ord_compl_of_dvd hab p⟩ rcases eq_or_ne b 0 with (rfl | hb0) · simp - by_cases pa : a.Prime - case neg => simpa [pa] using h a - by_cases pb : b.Prime - case neg => simpa [pb] using h b + if pa : a.Prime then ?_ else simpa [pa] using h a + if pb : b.Prime then ?_ else simpa [pb] using h b rw [prime_dvd_prime_iff_eq pa pb] by_contra hab apply pa.ne_one diff --git a/Mathlib/Data/Nat/ForSqrt.lean b/Mathlib/Data/Nat/ForSqrt.lean index 3b65c86705b99..cc60bdfbc1620 100644 --- a/Mathlib/Data/Nat/ForSqrt.lean +++ b/Mathlib/Data/Nat/ForSqrt.lean @@ -20,16 +20,15 @@ section Misc -- porting note: Miscellaneous lemmas that should be integrated with `Mathlib` in the future protected lemma mul_le_of_le_div (k x y : ℕ) (h : x ≤ y / k) : x * k ≤ y := by - by_cases hk : k = 0 - case pos => rw [hk, mul_zero]; exact zero_le _ - case neg => rwa [← le_div_iff_mul_le (pos_iff_ne_zero.2 hk)] + if hk : k = 0 then + rw [hk, mul_zero]; exact zero_le _ + else + rwa [← le_div_iff_mul_le (pos_iff_ne_zero.2 hk)] protected lemma div_mul_div_le (a b c d : ℕ) : (a / b) * (c / d) ≤ (a * c) / (b * d) := by - by_cases hb : b = 0 - case pos => simp [hb] - by_cases hd : d = 0 - case pos => simp [hd] + if hb : b = 0 then simp [hb] else + if hd : d = 0 then simp [hd] else have hbd : b * d ≠ 0 := mul_ne_zero hb hd rw [le_div_iff_mul_le (Nat.pos_of_ne_zero hbd)] transitivity ((a / b) * b) * ((c / d) * d) @@ -41,9 +40,10 @@ private lemma iter_fp_bound (n k : ℕ) : sqrt.iter n k ≤ iter_next n (sqrt.iter n k) := by intro iter_next unfold sqrt.iter - by_cases h : (k + n / k) / 2 < k - case pos => simp [if_pos h]; exact iter_fp_bound _ _ - case neg => simp [if_neg h]; exact Nat.le_of_not_lt h + if h : (k + n / k) / 2 < k then + simp [if_pos h]; exact iter_fp_bound _ _ + else + simp [if_neg h]; exact Nat.le_of_not_lt h private lemma AM_GM : {a b : ℕ} → (4 * a * b ≤ (a + b) * (a + b)) | 0, _ => by rw [mul_zero, zero_mul]; exact zero_le _ @@ -63,9 +63,9 @@ section Std lemma sqrt.iter_sq_le (n guess : ℕ) : sqrt.iter n guess * sqrt.iter n guess ≤ n := by unfold sqrt.iter let next := (guess + n / guess) / 2 - by_cases h : next < guess - case pos => simpa only [dif_pos h] using sqrt.iter_sq_le n next - case neg => + if h : next < guess then + simpa only [dif_pos h] using sqrt.iter_sq_le n next + else simp only [dif_neg h] apply Nat.mul_le_of_le_div apply le_of_add_le_add_left (a := guess) @@ -78,8 +78,7 @@ lemma sqrt.lt_iter_succ_sq (n guess : ℕ) (hn : n < (guess + 1) * (guess + 1)) unfold sqrt.iter -- m was `next` let m := (guess + n / guess) / 2 - by_cases h : m < guess - case pos => + if h : m < guess then suffices n < (m + 1) * (m + 1) by simpa only [dif_pos h] using sqrt.lt_iter_succ_sq n m this refine lt_of_mul_lt_mul_left ?_ (4 * (guess * guess)).zero_le @@ -95,7 +94,7 @@ lemma sqrt.lt_iter_succ_sq (n guess : ℕ) (hn : n < (guess + 1) * (guess + 1)) refine lt_of_lt_of_le ?_ (act_rel_act_of_rel _ aux_lemma) rw [add_assoc, mul_add] exact add_lt_add_left (lt_mul_div_succ _ (lt_of_le_of_lt (Nat.zero_le m) h)) _ - case neg => + else simpa only [dif_neg h] using hn end Std diff --git a/Mathlib/Data/Nat/GCD/Basic.lean b/Mathlib/Data/Nat/GCD/Basic.lean index f479a85070d46..bc2dd4c6a0581 100644 --- a/Mathlib/Data/Nat/GCD/Basic.lean +++ b/Mathlib/Data/Nat/GCD/Basic.lean @@ -283,12 +283,12 @@ See `exists_dvd_and_dvd_of_dvd_mul` for the more general but less constructive v `GCDMonoid`s. -/ def prodDvdAndDvdOfDvdProd {m n k : ℕ} (H : k ∣ m * n) : { d : { m' // m' ∣ m } × { n' // n' ∣ n } // k = d.1 * d.2 } := by - cases h0 : gcd k m - case zero => + cases h0 : gcd k m with + | zero => 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 succ tmp => + | succ tmp => have hpos : 0 < gcd k m := h0.symm ▸ Nat.zero_lt_succ _; clear h0 tmp have hd : gcd k m * (k / gcd k m) = k := Nat.mul_div_cancel' (gcd_dvd_left k m) refine' ⟨⟨⟨gcd k m, gcd_dvd_right k m⟩, ⟨k / gcd k m, _⟩⟩, hd.symm⟩ diff --git a/Mathlib/Data/Num/Lemmas.lean b/Mathlib/Data/Num/Lemmas.lean index b4a612239c28f..9aa0fff361729 100644 --- a/Mathlib/Data/Num/Lemmas.lean +++ b/Mathlib/Data/Num/Lemmas.lean @@ -970,10 +970,10 @@ theorem castNum_shiftRight (m : Num) (n : Nat) : ↑(m >>> n) = (m : ℕ) >>> (n @[simp] theorem castNum_testBit (m n) : testBit m n = Nat.testBit m n := by -- Porting note: `unfold` → `dsimp only` - cases m <;> dsimp only [testBit] - case zero => + cases m with dsimp only [testBit] + | zero => rw [show (Num.zero : Nat) = 0 from rfl, Nat.zero_testBit] - case pos m => + | pos m => rw [cast_pos] induction' n with n IH generalizing m <;> cases' m with m m <;> dsimp only [PosNum.testBit, Nat.zero_eq] diff --git a/Mathlib/Data/QPF/Multivariate/Constructions/Cofix.lean b/Mathlib/Data/QPF/Multivariate/Constructions/Cofix.lean index 695ef5d7fedcd..56dc69b12e1a1 100644 --- a/Mathlib/Data/QPF/Multivariate/Constructions/Cofix.lean +++ b/Mathlib/Data/QPF/Multivariate/Constructions/Cofix.lean @@ -266,10 +266,10 @@ theorem Cofix.bisim_rel {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop left rfl · intro x y r'xy - cases r'xy - case inl h => + cases r'xy with + | inl h => rw [h] - case inr r'xy => + | inr r'xy => have : ∀ x y, r x y → r' x y := fun x y h => Or.inr h rw [← Quot.factor_mk_eq _ _ this] dsimp diff --git a/Mathlib/Data/QPF/Multivariate/Constructions/Fix.lean b/Mathlib/Data/QPF/Multivariate/Constructions/Fix.lean index 9f0f96058ea8e..c01cd76908b93 100644 --- a/Mathlib/Data/QPF/Multivariate/Constructions/Fix.lean +++ b/Mathlib/Data/QPF/Multivariate/Constructions/Fix.lean @@ -123,10 +123,10 @@ set_option linter.uppercaseLean3 false in #align mvqpf.Wequiv.refl MvQPF.wEquiv.refl theorem wEquiv.symm {α : TypeVec n} (x y : q.P.W α) : WEquiv x y → WEquiv y x := by - intro h; induction h - case ind a f' f₀ f₁ _h ih => exact WEquiv.ind _ _ _ _ ih - case abs a₀ f'₀ f₀ a₁ f'₁ f₁ h => exact WEquiv.abs _ _ _ _ _ _ h.symm - case trans x y z _e₁ _e₂ ih₁ ih₂ => exact MvQPF.WEquiv.trans _ _ _ ih₂ ih₁ + intro h; induction h with + | ind a f' f₀ f₁ _h ih => exact WEquiv.ind _ _ _ _ ih + | abs a₀ f'₀ f₀ a₁ f'₁ f₁ h => exact WEquiv.abs _ _ _ _ _ _ h.symm + | trans x y z _e₁ _e₂ ih₁ ih₂ => exact MvQPF.WEquiv.trans _ _ _ ih₂ ih₁ set_option linter.uppercaseLean3 false in #align mvqpf.Wequiv.symm MvQPF.wEquiv.symm @@ -156,16 +156,15 @@ set_option linter.uppercaseLean3 false in theorem wEquiv_map {α β : TypeVec n} (g : α ⟹ β) (x y : q.P.W α) : WEquiv x y → WEquiv (g <$$> x) (g <$$> y) := by - intro h; induction h - case ind a f' f₀ f₁ h ih => rw [q.P.w_map_wMk, q.P.w_map_wMk]; apply WEquiv.ind; exact ih - case - abs a₀ f'₀ f₀ a₁ f'₁ f₁ h => + intro h; induction h with + | ind a f' f₀ f₁ h ih => rw [q.P.w_map_wMk, q.P.w_map_wMk]; apply WEquiv.ind; exact ih + | abs a₀ f'₀ f₀ a₁ f'₁ f₁ h => rw [q.P.w_map_wMk, q.P.w_map_wMk]; apply WEquiv.abs show abs (q.P.objAppend1 a₀ (g ⊚ f'₀) fun x => q.P.wMap g (f₀ x)) = abs (q.P.objAppend1 a₁ (g ⊚ f'₁) fun x => q.P.wMap g (f₁ x)) rw [← q.P.map_objAppend1, ← q.P.map_objAppend1, abs_map, abs_map, h] - case trans x y z _ _ ih₁ ih₂ => apply MvQPF.WEquiv.trans; apply ih₁; apply ih₂ + | trans x y z _ _ ih₁ ih₂ => apply MvQPF.WEquiv.trans; apply ih₁; apply ih₂ set_option linter.uppercaseLean3 false in #align mvqpf.Wequiv_map MvQPF.wEquiv_map diff --git a/Mathlib/Data/QPF/Univariate/Basic.lean b/Mathlib/Data/QPF/Univariate/Basic.lean index ee47afa0ec54e..9f3873f283372 100644 --- a/Mathlib/Data/QPF/Univariate/Basic.lean +++ b/Mathlib/Data/QPF/Univariate/Basic.lean @@ -192,10 +192,10 @@ set_option linter.uppercaseLean3 false in theorem recF_eq_of_Wequiv {α : Type u} (u : F α → α) (x y : q.P.W) : Wequiv x y → recF u x = recF u y := by intro h - induction h - case ind a f f' _ ih => simp only [recF_eq', PFunctor.map_eq, Function.comp, ih] - case abs a f a' f' h => simp only [recF_eq', abs_map, h] - case trans x y z _ _ ih₁ ih₂ => exact Eq.trans ih₁ ih₂ + induction h with + | ind a f f' _ ih => simp only [recF_eq', PFunctor.map_eq, Function.comp, ih] + | abs a f a' f' h => simp only [recF_eq', abs_map, h] + | trans x y z _ _ ih₁ ih₂ => exact Eq.trans ih₁ ih₂ set_option linter.uppercaseLean3 false in #align qpf.recF_eq_of_Wequiv QPF.recF_eq_of_Wequiv @@ -215,10 +215,10 @@ set_option linter.uppercaseLean3 false in theorem Wequiv.symm (x y : q.P.W) : Wequiv x y → Wequiv y x := by intro h - induction h - case ind a f f' _ ih => exact Wequiv.ind _ _ _ ih - case abs a f a' f' h => exact Wequiv.abs _ _ _ _ h.symm - case trans x y z _ _ ih₁ ih₂ => exact QPF.Wequiv.trans _ _ _ ih₂ ih₁ + induction h with + | ind a f f' _ ih => exact Wequiv.ind _ _ _ ih + | abs a f a' f' h => exact Wequiv.abs _ _ _ _ h.symm + | trans x y z _ _ ih₁ ih₂ => exact QPF.Wequiv.trans _ _ _ ih₂ ih₁ set_option linter.uppercaseLean3 false in #align qpf.Wequiv.symm QPF.Wequiv.symm diff --git a/Mathlib/Data/Set/Enumerate.lean b/Mathlib/Data/Set/Enumerate.lean index 0d80176c23ea9..c41c89c9a0da6 100644 --- a/Mathlib/Data/Set/Enumerate.lean +++ b/Mathlib/Data/Set/Enumerate.lean @@ -49,10 +49,9 @@ theorem enumerate_eq_none : | s, n + 1, m => fun h hm ↦ by cases hs : sel s · exact enumerate_eq_none_of_sel sel hs - · cases m - case zero => - contradiction - case succ m' => + · cases m with + | zero => contradiction + | succ m' => simp? [hs, enumerate] at h ⊢ says simp only [enumerate, hs, Nat.add_eq, add_zero] at h ⊢ have hm : n ≤ m' := Nat.le_of_succ_le_succ hm exact enumerate_eq_none h hm @@ -62,9 +61,9 @@ theorem enumerate_mem (h_sel : ∀ s a, sel s = some a → a ∈ s) : ∀ {s n a}, enumerate sel s n = some a → a ∈ s | s, 0, a => h_sel s a | s, n + 1, a => by - cases h : sel s - case none => simp [enumerate_eq_none_of_sel, h] - case some a' => + cases h : sel s with + | none => simp [enumerate_eq_none_of_sel, h] + | some a' => simp only [enumerate, h, Nat.add_eq, add_zero] exact fun h' : enumerate sel (s \ {a'}) n = some a ↦ have : a ∈ s \ {a'} := enumerate_mem h_sel h' @@ -80,21 +79,21 @@ theorem enumerate_inj {n₁ n₂ : ℕ} {a : α} {s : Set α} (h_sel : ∀ s a, all_goals rcases Nat.le.dest hn with ⟨m, rfl⟩ clear hn - induction n₁ generalizing s - case zero => - cases m - case zero => rfl - case succ m => + induction n₁ generalizing s with + | zero => + cases m with + | zero => rfl + | succ m => have h' : enumerate sel (s \ {a}) m = some a := by simp_all only [enumerate, Nat.zero_eq, Nat.add_eq, zero_add]; exact h₂ have : a ∈ s \ {a} := enumerate_mem sel h_sel h' simp_all [Set.mem_diff_singleton] - case succ k ih => - cases h : sel s + | succ k ih => + cases h : sel s with /- porting note : The original covered both goals with just `simp_all <;> tauto` -/ - case none => + | none => simp_all only [add_comm, self_eq_add_left, Nat.add_succ, enumerate_eq_none_of_sel _ h] - case some _ => + | some => simp_all only [add_comm, self_eq_add_left, enumerate, Option.some.injEq, Nat.add_succ, enumerate._eq_2, Nat.succ.injEq] exact ih h₁ h₂ diff --git a/Mathlib/Data/Stream/Init.lean b/Mathlib/Data/Stream/Init.lean index f49b1f28083b4..91d7f74a4b541 100644 --- a/Mathlib/Data/Stream/Init.lean +++ b/Mathlib/Data/Stream/Init.lean @@ -606,8 +606,9 @@ theorem get?_take_succ (n : Nat) (s : Stream' α) : @[simp] theorem dropLast_take {xs : Stream' α} : (Stream'.take n xs).dropLast = Stream'.take (n-1) xs := by - cases n; case zero => simp - case succ n => rw [take_succ', List.dropLast_concat, Nat.add_one_sub_one] + cases n with + | zero => simp + | succ n => rw [take_succ', List.dropLast_concat, Nat.add_one_sub_one] @[simp] theorem append_take_drop : ∀ (n : Nat) (s : Stream' α), diff --git a/Mathlib/Data/TypeVec.lean b/Mathlib/Data/TypeVec.lean index fbba2143b40e0..e5a84d7624755 100644 --- a/Mathlib/Data/TypeVec.lean +++ b/Mathlib/Data/TypeVec.lean @@ -489,9 +489,9 @@ def ofRepeat {α : Sort _} : ∀ {n i}, «repeat» n α i → α #align typevec.of_repeat TypeVec.ofRepeat theorem const_iff_true {α : TypeVec n} {i x p} : ofRepeat (TypeVec.const p α i x) ↔ p := by - induction i - case fz => rfl - case fs _ ih => erw [TypeVec.const, @ih (drop α) x] + induction i with + | fz => rfl + | fs _ ih => erw [TypeVec.const, @ih (drop α) x] #align typevec.const_iff_true TypeVec.const_iff_true @@ -556,28 +556,28 @@ protected def prod.map : ∀ {n} {α α' β β' : TypeVec.{u} n}, α ⟹ β → theorem fst_prod_mk {α α' β β' : TypeVec n} (f : α ⟹ β) (g : α' ⟹ β') : TypeVec.prod.fst ⊚ (f ⊗' g) = f ⊚ TypeVec.prod.fst := by - funext i; induction i - case fz => rfl - case fs _ _ i_ih => apply i_ih + funext i; induction i with + | fz => rfl + | fs _ i_ih => apply i_ih #align typevec.fst_prod_mk TypeVec.fst_prod_mk theorem snd_prod_mk {α α' β β' : TypeVec n} (f : α ⟹ β) (g : α' ⟹ β') : TypeVec.prod.snd ⊚ (f ⊗' g) = g ⊚ TypeVec.prod.snd := by - funext i; induction i - case fz => rfl - case fs _ _ i_ih => apply i_ih + funext i; induction i with + | fz => rfl + | fs _ i_ih => apply i_ih #align typevec.snd_prod_mk TypeVec.snd_prod_mk theorem fst_diag {α : TypeVec n} : TypeVec.prod.fst ⊚ (prod.diag : α ⟹ _) = id := by - funext i; induction i - case fz => rfl - case fs _ _ i_ih => apply i_ih + funext i; induction i with + | fz => rfl + | fs _ i_ih => apply i_ih #align typevec.fst_diag TypeVec.fst_diag theorem snd_diag {α : TypeVec n} : TypeVec.prod.snd ⊚ (prod.diag : α ⟹ _) = id := by - funext i; induction i - case fz => rfl - case fs _ _ i_ih => apply i_ih + funext i; induction i with + | fz => rfl + | fs _ i_ih => apply i_ih #align typevec.snd_diag TypeVec.snd_diag theorem repeatEq_iff_eq {α : TypeVec n} {i x y} : diff --git a/Mathlib/Data/Vector/Basic.lean b/Mathlib/Data/Vector/Basic.lean index e3001bb438f2f..37fbf3562f6f6 100644 --- a/Mathlib/Data/Vector/Basic.lean +++ b/Mathlib/Data/Vector/Basic.lean @@ -799,10 +799,10 @@ variable (ys : Vector β n) theorem get_map₂ (v₁ : Vector α n) (v₂ : Vector β n) (f : α → β → γ) (i : Fin n) : get (map₂ f v₁ v₂) i = f (get v₁ i) (get v₂ i) := by clear * - v₁ v₂ - induction v₁, v₂ using inductionOn₂ - case nil => + induction v₁, v₂ using inductionOn₂ with + | nil => exact Fin.elim0 i - case cons x xs y ys ih => + | cons ih => rw [map₂_cons] cases i using Fin.cases · simp only [get_zero, head_cons] diff --git a/Mathlib/Data/Vector/MapLemmas.lean b/Mathlib/Data/Vector/MapLemmas.lean index 7790a8ff975bd..056653ebd02d6 100644 --- a/Mathlib/Data/Vector/MapLemmas.lean +++ b/Mathlib/Data/Vector/MapLemmas.lean @@ -342,10 +342,9 @@ variable {xs : Vector α n} {ys : Vector β n} theorem mapAccumr₂_unused_input_left [Inhabited α] (f : α → β → σ → σ × γ) (h : ∀ a b s, f default b s = f a b s) : mapAccumr₂ f xs ys s = mapAccumr (fun b s => f default b s) ys s := by - induction xs, ys using Vector.revInductionOn₂ generalizing s - case nil => rfl - case snoc xs ys x y ih => - simp[h x y s, ih] + induction xs, ys using Vector.revInductionOn₂ generalizing s with + | nil => rfl + | snoc xs ys x y ih => simp [h x y s, ih] /-- If `f` returns the same output and next state for every value of it's second argument, then @@ -355,10 +354,9 @@ theorem mapAccumr₂_unused_input_left [Inhabited α] (f : α → β → σ → theorem mapAccumr₂_unused_input_right [Inhabited β] (f : α → β → σ → σ × γ) (h : ∀ a b s, f a default s = f a b s) : mapAccumr₂ f xs ys s = mapAccumr (fun a s => f a default s) xs s := by - induction xs, ys using Vector.revInductionOn₂ generalizing s - case nil => rfl - case snoc xs ys x y ih => - simp[h x y s, ih] + induction xs, ys using Vector.revInductionOn₂ generalizing s with + | nil => rfl + | snoc xs ys x y ih => simp [h x y s, ih] end UnusedInput diff --git a/Mathlib/Data/Vector/Snoc.lean b/Mathlib/Data/Vector/Snoc.lean index f9afb271985ed..e619a76d802ba 100644 --- a/Mathlib/Data/Vector/Snoc.lean +++ b/Mathlib/Data/Vector/Snoc.lean @@ -55,14 +55,12 @@ theorem reverse_snoc : reverse (xs.snoc x) = x ::ᵥ (reverse xs) := by theorem replicate_succ_to_snoc (val : α) : replicate (n+1) val = (replicate n val).snoc val := by clear xs - induction n - case zero => rfl - case succ n ih => + induction n with + | zero => rfl + | succ n ih => rw [replicate_succ] - conv => { - rhs; rw [replicate_succ] - } - rw[snoc_cons, ih] + conv => rhs; rw [replicate_succ] + rw [snoc_cons, ih] end Simp diff --git a/Mathlib/Deprecated/Submonoid.lean b/Mathlib/Deprecated/Submonoid.lean index 74979843dd31b..e1fa90237a3b4 100644 --- a/Mathlib/Deprecated/Submonoid.lean +++ b/Mathlib/Deprecated/Submonoid.lean @@ -370,10 +370,10 @@ a list of elements of `s` whose product is `a`. -/ a set `s`, there exists a list of elements of `s` whose sum is `a`."] theorem exists_list_of_mem_closure {s : Set M} {a : M} (h : a ∈ Closure s) : ∃ l : List M, (∀ x ∈ l, x ∈ s) ∧ l.prod = a := by - induction h - case basic a ha => exists [a]; simp [ha] - case one => exists []; simp - case mul a b _ _ ha hb => + induction h with + | @basic a ha => exists [a]; simp [ha] + | one => exists []; simp + | mul _ _ ha hb => rcases ha with ⟨la, ha, eqa⟩ rcases hb with ⟨lb, hb, eqb⟩ exists la ++ lb diff --git a/Mathlib/FieldTheory/PerfectClosure.lean b/Mathlib/FieldTheory/PerfectClosure.lean index a74acb381759f..0489e266fb725 100644 --- a/Mathlib/FieldTheory/PerfectClosure.lean +++ b/Mathlib/FieldTheory/PerfectClosure.lean @@ -286,11 +286,11 @@ theorem eq_iff' (x y : ℕ × K) : constructor · intro H replace H := Quot.exact _ H - induction H - case rel x y H => cases' H with n x; exact ⟨0, rfl⟩ - case refl H => exact ⟨0, rfl⟩ - case symm x y H ih => cases' ih with w ih; exact ⟨w, ih.symm⟩ - case trans x y z H1 H2 ih1 ih2 => + induction H with + | rel x y H => cases' H with n x; exact ⟨0, rfl⟩ + | refl H => exact ⟨0, rfl⟩ + | symm x y H ih => cases' ih with w ih; exact ⟨w, ih.symm⟩ + | trans x y z H1 H2 ih1 ih2 => cases' ih1 with z1 ih1 cases' ih2 with z2 ih2 exists z2 + (y.1 + z1) @@ -344,9 +344,9 @@ theorem frobenius_mk (x : ℕ × K) : dsimp only suffices ∀ p' : ℕ, mk K p (n, x) ^ p' = mk K p (n, x ^ p') by apply this intro p - induction' p with p ih - case zero => apply R.sound; rw [(frobenius _ _).iterate_map_one, pow_zero] - case succ => + induction p with + | zero => apply R.sound; rw [(frobenius _ _).iterate_map_one, pow_zero] + | succ p ih => rw [pow_succ, ih] symm apply R.sound diff --git a/Mathlib/GroupTheory/Coprod/Basic.lean b/Mathlib/GroupTheory/Coprod/Basic.lean index 223653e25dcc6..27f597591adbf 100644 --- a/Mathlib/GroupTheory/Coprod/Basic.lean +++ b/Mathlib/GroupTheory/Coprod/Basic.lean @@ -573,9 +573,9 @@ theorem mk_of_inv_mul : ∀ x : G ⊕ H, mk (of (x.map Inv.inv Inv.inv)) * mk (o theorem con_mul_left_inv (x : FreeMonoid (G ⊕ H)) : coprodCon G H (ofList (x.toList.map (Sum.map Inv.inv Inv.inv)).reverse * x) 1 := by rw [← mk_eq_mk, map_mul, map_one] - induction x using FreeMonoid.recOn - case h0 => simp [map_one mk] -- TODO: fails without `[map_one mk]` - case ih x xs ihx => + induction x using FreeMonoid.recOn with + | h0 => simp [map_one mk] -- TODO: fails without `[map_one mk]` + | ih x xs ihx => simp only [toList_of_mul, map_cons, reverse_cons, ofList_append, map_mul, ihx, ofList_singleton] rwa [mul_assoc, ← mul_assoc (mk (of _)), mk_of_inv_mul, one_mul] diff --git a/Mathlib/GroupTheory/FreeGroup/Basic.lean b/Mathlib/GroupTheory/FreeGroup/Basic.lean index 2dad3da8a9ef3..4a10af8348449 100644 --- a/Mathlib/GroupTheory/FreeGroup/Basic.lean +++ b/Mathlib/GroupTheory/FreeGroup/Basic.lean @@ -402,8 +402,8 @@ theorem length_le (h : Red L₁ L₂) : L₂.length ≤ L₁.length := theorem sizeof_of_step : ∀ {L₁ L₂ : List (α × Bool)}, Step L₁ L₂ → sizeOf L₂ < sizeOf L₁ | _, _, @Step.not _ L1 L2 x b => by - induction' L1 with hd tl ih - case nil => + induction L1 with + | nil => -- dsimp [sizeOf] dsimp simp only [Bool.sizeOf_eq_one] @@ -416,7 +416,7 @@ theorem sizeof_of_step : ∀ {L₁ L₂ : List (α × Bool)}, apply Nat.lt_add_of_pos_right apply Nat.lt_add_right apply Nat.zero_lt_one - case cons => + | cons hd tl ih => dsimp exact Nat.add_lt_add_left ih _ #align free_group.red.sizeof_of_step FreeGroup.Red.sizeof_of_step @@ -1123,16 +1123,16 @@ theorem reduce.cons (x) : @[to_additive "The first theorem that characterises the function `reduce`: a word reduces to its maximal reduction."] theorem reduce.red : Red L (reduce L) := by - induction' L with hd1 tl1 ih - case nil => constructor - case cons => + induction L with + | nil => constructor + | cons hd1 tl1 ih => dsimp revert ih generalize htl : reduce tl1 = TL intro ih - cases' TL with hd2 tl2 - case nil => exact Red.cons_cons ih - case cons => + cases TL with + | nil => exact Red.cons_cons ih + | cons hd2 tl2 => dsimp only split_ifs with h · trans @@ -1147,41 +1147,37 @@ theorem reduce.red : Red L (reduce L) := by #align free_group.reduce.red FreeGroup.reduce.red #align free_add_group.reduce.red FreeAddGroup.reduce.red --- porting notes: deleted mathport junk and manually formatted below. @[to_additive] -theorem reduce.not {p : Prop} : ∀ {L₁ L₂ L₃ : List (α × Bool)} {x : α} {b}, - ((reduce L₁) = L₂ ++ ((x,b)::(x ,!b)::L₃)) → p - | [], L2 ,L3, _, _ => fun h => by cases L2 <;> injections - | (x, b)::L1, L2, L3, x', b' => by - dsimp - cases r : reduce L1 with - | nil => - dsimp - intro h - exfalso - have := congr_arg List.length h - simp? [List.length] at this says - simp only [List.length, zero_add, List.length_append] at this - rw [add_comm, add_assoc, add_assoc, add_comm, <-add_assoc] at this - simp [Nat.one_eq_succ_zero, Nat.succ_add] at this - -- Porting note: needed to add this step in #3414. - -- This is caused by https://github.com/leanprover/lean4/pull/2146. - -- Nevertheless the proof could be cleaned up. - cases this - | cons hd tail => - cases' hd with y c - dsimp only - split_ifs with h <;> intro H - · rw [ H ] at r - exact @reduce.not _ L1 ((y, c)::L2) L3 x' b' r - · rcases L2 with ( _ | ⟨ a , L2 ⟩ ) - · injections - subst_vars - simp at h - · refine' @reduce.not _ L1 L2 L3 x' b' _ - injection H with _ H - rw [ r , H ] - rfl +theorem reduce.not {p : Prop} : + ∀ {L₁ L₂ L₃ : List (α × Bool)} {x b}, reduce L₁ = L₂ ++ (x, b) :: (x, !b) :: L₃ → p + | [], L2, L3, _, _ => fun h => by cases L2 <;> injections + | (x, b) :: L1, L2, L3, x', b' => by + dsimp + cases r : reduce L1 with + | nil => + dsimp; intro h + exfalso + have := congr_arg List.length h + simp? [List.length] at this says + simp only [List.length, zero_add, List.length_append] at this + rw [add_comm, add_assoc, add_assoc, add_comm, <-add_assoc] at this + simp [Nat.one_eq_succ_zero, Nat.succ_add] at this + -- Porting note: needed to add this step in #3414. + -- This is caused by https://github.com/leanprover/lean4/pull/2146. + -- Nevertheless the proof could be cleaned up. + cases this + | cons hd tail => + cases' hd with y c + dsimp only + split_ifs with h <;> intro H + · rw [H] at r + exact @reduce.not _ L1 ((y, c) :: L2) L3 x' b' r + rcases L2 with (_ | ⟨a, L2⟩) + · injections; subst_vars + simp at h + · refine' @reduce.not _ L1 L2 L3 x' b' _ + injection H with _ H + rw [r, H]; rfl #align free_group.reduce.not FreeGroup.reduce.not #align free_add_group.reduce.not FreeAddGroup.reduce.not diff --git a/Mathlib/Init/Data/Nat/Bitwise.lean b/Mathlib/Init/Data/Nat/Bitwise.lean index e275366c33b1e..4c90b75b8f2df 100644 --- a/Mathlib/Init/Data/Nat/Bitwise.lean +++ b/Mathlib/Init/Data/Nat/Bitwise.lean @@ -116,12 +116,7 @@ theorem div2_two : div2 2 = 1 := @[simp] theorem div2_succ (n : ℕ) : div2 (succ n) = cond (bodd n) (succ (div2 n)) (div2 n) := by simp only [bodd, boddDiv2, div2] - cases' boddDiv2 n with fst snd - cases fst - case mk.false => - simp - case mk.true => - simp + rcases boddDiv2 n with ⟨_|_, _⟩ <;> simp #align nat.div2_succ Nat.div2_succ attribute [local simp] Nat.add_comm Nat.add_assoc Nat.add_left_comm Nat.mul_comm Nat.mul_assoc @@ -325,24 +320,19 @@ theorem testBit_succ (m b n) : testBit (bit b n) (succ m) = testBit n m := by theorem binaryRec_eq {C : Nat → Sort u} {z : C 0} {f : ∀ b n, C n → C (bit b n)} (h : f false 0 z = z) (b n) : binaryRec z f (bit b n) = f b n (binaryRec z f n) := by rw [binaryRec] - by_cases h : bit b n = 0 - -- Note: this renames the original `h : f false 0 z = z` to `h'` and leaves `h : bit b n = 0` - case pos h' => - simp only [dif_pos h] - generalize binaryRec z f (bit b n) = e + split <;> rename_i h' + · generalize binaryRec z f (bit b n) = e revert e have bf := bodd_bit b n have n0 := div2_bit b n - rw [h] at bf n0 + rw [h'] at bf n0 simp only [bodd_zero, div2_zero] at bf n0 subst bf n0 rw [binaryRec_zero] intros - rw [h'] + rw [h] rfl - case neg h' => - simp only [dif_neg h] - generalize_proofs h + · simp only; generalize_proofs h revert h rw [bodd_bit, div2_bit] intros; rfl diff --git a/Mathlib/Init/Data/Nat/Lemmas.lean b/Mathlib/Init/Data/Nat/Lemmas.lean index 87b1725ce4bdf..25a14c70fd10b 100644 --- a/Mathlib/Init/Data/Nat/Lemmas.lean +++ b/Mathlib/Init/Data/Nat/Lemmas.lean @@ -734,9 +734,9 @@ lemma to_digits_core_lens_eq_aux (b f : Nat) : induction f with (simp only [Nat.toDigitsCore, List.length]; intro n l1 l2 hlen) | zero => assumption | succ f ih => - by_cases hx : n / b = 0 - case pos => simp only [hx, if_true, List.length, congrArg (fun l ↦ l + 1) hlen] - case neg => + if hx : n / b = 0 then + simp only [hx, if_true, List.length, congrArg (fun l ↦ l + 1) hlen] + else simp only [hx, if_false] specialize ih (n / b) (Nat.digitChar (n % b) :: l1) (Nat.digitChar (n % b) :: l2) simp only [List.length, congrArg (fun l ↦ l + 1) hlen] at ih @@ -746,9 +746,9 @@ lemma to_digits_core_lens_eq (b f : Nat) : ∀ (n : Nat) (c : Char) (tl : List C (Nat.toDigitsCore b f n (c :: tl)).length = (Nat.toDigitsCore b f n tl).length + 1 := by induction f with (intro n c tl; simp only [Nat.toDigitsCore, List.length]) | succ f ih => - by_cases hnb : (n / b) = 0 - case pos => simp only [hnb, if_true, List.length] - case neg => + if hnb : (n / b) = 0 then + simp only [hnb, if_true, List.length] + else generalize hx: Nat.digitChar (n % b) = x simp only [hx, hnb, if_false] at ih simp only [hnb, if_false] @@ -773,17 +773,16 @@ lemma to_digits_core_length (b : Nat) (h : 2 <= b) (f n e : Nat) cases e with | zero => exact False.elim (Nat.lt_irrefl 0 h_e_pos) | succ e => - by_cases h_pred_pos : 0 < e - case pos => + if h_pred_pos : 0 < e then have _ : 0 < b := Nat.lt_trans (by decide) h specialize ih (n / b) e (nat_repr_len_aux n b e ‹0 < b› hlt) h_pred_pos - by_cases hdiv_ten : n / b = 0 - case pos => simp only [hdiv_ten]; exact Nat.le.step h_pred_pos - case neg => + if hdiv_ten : n / b = 0 then + simp only [hdiv_ten]; exact Nat.le.step h_pred_pos + else simp only [hdiv_ten, to_digits_core_lens_eq b f (n / b) (Nat.digitChar $ n % b), if_false] exact Nat.succ_le_succ ih - case neg => + else obtain rfl : e = 0 := Nat.eq_zero_of_not_pos h_pred_pos have _ : b ^ 1 = b := by simp only [pow_succ, pow_zero, Nat.one_mul] have _ : n < b := ‹b ^ 1 = b› ▸ hlt @@ -797,8 +796,9 @@ lemma repr_length (n e : Nat) : 0 < e → n < 10 ^ e → (Nat.repr n).length <= (intro e0 he; simp only [Nat.repr, Nat.toDigits, String.length, List.asString]) | zero => assumption | succ n => - by_cases hterm : n.succ / 10 = 0 - case pos => simp only [hterm, Nat.toDigitsCore]; assumption - case neg => exact to_digits_core_length 10 (by decide) (Nat.succ n + 1) (Nat.succ n) e he e0 + if hterm : n.succ / 10 = 0 then + simp only [hterm, Nat.toDigitsCore]; assumption + else + exact to_digits_core_length 10 (by decide) (Nat.succ n + 1) (Nat.succ n) e he e0 end Nat diff --git a/Mathlib/Init/Order/Defs.lean b/Mathlib/Init/Order/Defs.lean index b823526c32e79..c0f97b9393654 100644 --- a/Mathlib/Init/Order/Defs.lean +++ b/Mathlib/Init/Order/Defs.lean @@ -430,7 +430,7 @@ theorem compare_gt_iff_gt {a b : α} : (compare a b = .gt) ↔ a > b := by theorem compare_eq_iff_eq {a b : α} : (compare a b = .eq) ↔ a = b := by rw [LinearOrder.compare_eq_compareOfLessAndEq, compareOfLessAndEq] - split_ifs <;> try simp only [] + split_ifs <;> try simp only case _ h => exact false_iff_iff.2 <| ne_iff_lt_or_gt.2 <| .inl h case _ _ h => exact true_iff_iff.2 h case _ _ h => exact false_iff_iff.2 h diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean index 2aacfde94d665..5f83f8a7c9375 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean @@ -156,11 +156,11 @@ theorem reverse_comp_involute : (involute.toLinearMap.comp reverse : _ →ₗ[R] CliffordAlgebra Q) := by ext x simp only [LinearMap.comp_apply, AlgHom.toLinearMap_apply] - induction x using CliffordAlgebra.induction - case h_grade0 => simp - case h_grade1 => simp - case h_mul a b ha hb => simp only [ha, hb, reverse.map_mul, AlgHom.map_mul] - case h_add a b ha hb => simp only [ha, hb, reverse.map_add, AlgHom.map_add] + induction x using CliffordAlgebra.induction with + | h_grade0 => simp + | h_grade1 => simp + | h_mul a b ha hb => simp only [ha, hb, reverse.map_mul, AlgHom.map_mul] + | h_add a b ha hb => simp only [ha, hb, reverse.map_add, AlgHom.map_add] #align clifford_algebra.reverse_comp_involute CliffordAlgebra.reverse_comp_involute /-- `CliffordAlgebra.reverse` and `CliffordAlgebra.involute` commute. Note that the composition diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean index 694a974931491..278eb81150964 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean @@ -80,20 +80,20 @@ theorem ι_eq_zero : ι (0 : QuadraticForm R Unit) = 0 := instance : CommRing (CliffordAlgebra (0 : QuadraticForm R Unit)) := { CliffordAlgebra.instRing _ with mul_comm := fun x y => by - induction x using CliffordAlgebra.induction - case h_grade0 r => apply Algebra.commutes - case h_grade1 x => simp - case h_add x₁ x₂ hx₁ hx₂ => rw [mul_add, add_mul, hx₁, hx₂] - case h_mul x₁ x₂ hx₁ hx₂ => rw [mul_assoc, hx₂, ← mul_assoc, hx₁, ← mul_assoc] } + induction x using CliffordAlgebra.induction with + | h_grade0 r => apply Algebra.commutes + | h_grade1 x => simp + | h_add x₁ x₂ hx₁ hx₂ => rw [mul_add, add_mul, hx₁, hx₂] + | h_mul x₁ x₂ hx₁ hx₂ => rw [mul_assoc, hx₂, ← mul_assoc, hx₁, ← mul_assoc] } -- Porting note: Changed `x.reverse` to `reverse (R := R) x` theorem reverse_apply (x : CliffordAlgebra (0 : QuadraticForm R Unit)) : reverse (R := R) x = x := by - induction x using CliffordAlgebra.induction - case h_grade0 r => exact reverse.commutes _ - case h_grade1 x => rw [ι_eq_zero, LinearMap.zero_apply, reverse.map_zero] - case h_mul x₁ x₂ hx₁ hx₂ => rw [reverse.map_mul, mul_comm, hx₁, hx₂] - case h_add x₁ x₂ hx₁ hx₂ => rw [reverse.map_add, hx₁, hx₂] + induction x using CliffordAlgebra.induction with + | h_grade0 r => exact reverse.commutes _ + | h_grade1 x => rw [ι_eq_zero, LinearMap.zero_apply, reverse.map_zero] + | h_mul x₁ x₂ hx₁ hx₂ => rw [reverse.map_mul, mul_comm, hx₁, hx₂] + | h_add x₁ x₂ hx₁ hx₂ => rw [reverse.map_add, hx₁, hx₂] #align clifford_algebra_ring.reverse_apply CliffordAlgebraRing.reverse_apply @[simp] @@ -221,11 +221,11 @@ instance : CommRing (CliffordAlgebra Q) := -- Porting note: Changed `x.reverse` to `reverse (R := ℝ) x` /-- `reverse` is a no-op over `CliffordAlgebraComplex.Q`. -/ theorem reverse_apply (x : CliffordAlgebra Q) : reverse (R := ℝ) x = x := by - induction x using CliffordAlgebra.induction - case h_grade0 r => exact reverse.commutes _ - case h_grade1 x => rw [reverse_ι] - case h_mul x₁ x₂ hx₁ hx₂ => rw [reverse.map_mul, mul_comm, hx₁, hx₂] - case h_add x₁ x₂ hx₁ hx₂ => rw [reverse.map_add, hx₁, hx₂] + induction x using CliffordAlgebra.induction with + | h_grade0 r => exact reverse.commutes _ + | h_grade1 x => rw [reverse_ι] + | h_mul x₁ x₂ hx₁ hx₂ => rw [reverse.map_mul, mul_comm, hx₁, hx₂] + | h_add x₁ x₂ hx₁ hx₂ => rw [reverse.map_add, hx₁, hx₂] #align clifford_algebra_complex.reverse_apply CliffordAlgebraComplex.reverse_apply @[simp] @@ -311,15 +311,15 @@ theorem toQuaternion_ι (v : R × R) : theorem toQuaternion_star (c : CliffordAlgebra (Q c₁ c₂)) : toQuaternion (star c) = star (toQuaternion c) := by simp only [CliffordAlgebra.star_def'] - induction c using CliffordAlgebra.induction - case h_grade0 r => + induction c using CliffordAlgebra.induction with + | h_grade0 r => simp only [reverse.commutes, AlgHom.commutes, QuaternionAlgebra.coe_algebraMap, QuaternionAlgebra.star_coe] - case h_grade1 x => + | h_grade1 x => rw [reverse_ι, involute_ι, toQuaternion_ι, AlgHom.map_neg, toQuaternion_ι, QuaternionAlgebra.neg_mk, star_mk, neg_zero] - case h_mul x₁ x₂ hx₁ hx₂ => simp only [reverse.map_mul, AlgHom.map_mul, hx₁, hx₂, star_mul] - case h_add x₁ x₂ hx₁ hx₂ => simp only [reverse.map_add, AlgHom.map_add, hx₁, hx₂, star_add] + | h_mul x₁ x₂ hx₁ hx₂ => simp only [reverse.map_mul, AlgHom.map_mul, hx₁, hx₂, star_mul] + | h_add x₁ x₂ hx₁ hx₂ => simp only [reverse.map_add, AlgHom.map_add, hx₁, hx₂, star_add] #align clifford_algebra_quaternion.to_quaternion_star CliffordAlgebraQuaternion.toQuaternion_star /-- Map a quaternion into the clifford algebra. -/ diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean index e04848f971f0c..d72a3af554a56 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean @@ -247,15 +247,15 @@ subalgebra is just the reverse of the representation. -/ theorem coe_toEven_reverse_involute (x : CliffordAlgebra Q) : ↑(toEven Q (reverse (involute x))) = reverse (Q := Q' Q) (toEven Q x : CliffordAlgebra (Q' Q)) := by - induction x using CliffordAlgebra.induction - case h_grade0 r => simp only [AlgHom.commutes, Subalgebra.coe_algebraMap, reverse.commutes] - case h_grade1 m => + induction x using CliffordAlgebra.induction with + | h_grade0 r => simp only [AlgHom.commutes, Subalgebra.coe_algebraMap, reverse.commutes] + | h_grade1 m => -- porting note: added `letI` letI : SubtractionMonoid (even (Q' Q)) := AddGroup.toSubtractionMonoid simp only [involute_ι, Subalgebra.coe_neg, toEven_ι, reverse.map_mul, reverse_v, reverse_e0, reverse_ι, neg_e0_mul_v, map_neg] - case h_mul x y hx hy => simp only [map_mul, Subalgebra.coe_mul, reverse.map_mul, hx, hy] - case h_add x y hx hy => simp only [map_add, Subalgebra.coe_add, hx, hy] + | h_mul x y hx hy => simp only [map_mul, Subalgebra.coe_mul, reverse.map_mul, hx, hy] + | h_add x y hx hy => simp only [map_add, Subalgebra.coe_add, hx, hy] #align clifford_algebra.coe_to_even_reverse_involute CliffordAlgebra.coe_toEven_reverse_involute /-! ### Constructions needed for `CliffordAlgebra.evenEquivEvenNeg` -/ diff --git a/Mathlib/Logic/Denumerable.lean b/Mathlib/Logic/Denumerable.lean index 1ce3fe95aea04..c28dd184e9cd1 100644 --- a/Mathlib/Logic/Denumerable.lean +++ b/Mathlib/Logic/Denumerable.lean @@ -127,11 +127,11 @@ theorem ofNat_nat (n) : ofNat ℕ n = n := /-- If `α` is denumerable, then so is `Option α`. -/ instance option : Denumerable (Option α) := ⟨fun n => by - cases n - case zero => + cases n with + | zero => refine' ⟨none, _, encode_none⟩ rw [decode_option_zero, Option.mem_def] - case succ n => + | succ n => refine' ⟨some (ofNat α n), _, _⟩ · rw [decode_option_succ, decode_eq_ofNat, Option.map_some', Option.mem_def] rw [encode_some, encode_ofNat]⟩ diff --git a/Mathlib/Logic/Hydra.lean b/Mathlib/Logic/Hydra.lean index 9130d740a1e83..915fa10f264b2 100644 --- a/Mathlib/Logic/Hydra.lean +++ b/Mathlib/Logic/Hydra.lean @@ -125,9 +125,9 @@ theorem cutExpand_fibration (r : α → α → Prop) : assuming `r` is irreflexive. -/ theorem acc_of_singleton [IsIrrefl α r] {s : Multiset α} (hs : ∀ a ∈ s, Acc (CutExpand r) {a}) : Acc (CutExpand r) s := by - induction s using Multiset.induction - case empty => exact Acc.intro 0 fun s h ↦ (not_cutExpand_zero s h).elim - case cons a s ihs => + induction s using Multiset.induction with + | empty => exact Acc.intro 0 fun s h ↦ (not_cutExpand_zero s h).elim + | @cons a s ihs => rw [← s.singleton_add a] rw [forall_mem_cons] at hs exact (hs.1.prod_gameAdd <| ihs fun a ha ↦ hs.2 a ha).of_fibration _ (cutExpand_fibration r) diff --git a/Mathlib/Logic/Relation.lean b/Mathlib/Logic/Relation.lean index 3f4fbdaf26df9..544154eba73fb 100644 --- a/Mathlib/Logic/Relation.lean +++ b/Mathlib/Logic/Relation.lean @@ -296,9 +296,9 @@ namespace ReflTransGen @[trans] theorem trans (hab : ReflTransGen r a b) (hbc : ReflTransGen r b c) : ReflTransGen r a c := by - induction hbc - case refl => assumption - case tail c d _ hcd hac => exact hac.tail hcd + induction hbc with + | refl => assumption + | tail _ hcd hac => exact hac.tail hcd #align relation.refl_trans_gen.trans Relation.ReflTransGen.trans theorem single (hab : r a b) : ReflTransGen r a b := @@ -306,9 +306,9 @@ theorem single (hab : r a b) : ReflTransGen r a b := #align relation.refl_trans_gen.single Relation.ReflTransGen.single theorem head (hab : r a b) (hbc : ReflTransGen r b c) : ReflTransGen r a c := by - induction hbc - case refl => exact refl.tail hab - case tail c d _ hcd hac => exact hac.tail hcd + induction hbc with + | refl => exact refl.tail hab + | tail _ hcd hac => exact hac.tail hcd #align relation.refl_trans_gen.head Relation.ReflTransGen.head theorem symmetric (h : Symmetric r) : Symmetric (ReflTransGen r) := by @@ -326,13 +326,13 @@ theorem cases_tail : ReflTransGen r a b → b = a ∨ ∃ c, ReflTransGen r a c theorem head_induction_on {P : ∀ a : α, ReflTransGen r a b → Prop} {a : α} (h : ReflTransGen r a b) (refl : P b refl) (head : ∀ {a c} (h' : r a c) (h : ReflTransGen r c b), P c h → P a (h.head h')) : P a h := by - induction h - case refl => exact refl - case tail b c _ hbc ih => + induction h with + | refl => exact refl + | @tail b c _ hbc ih => -- Porting note: Lean 3 figured out the motive and `apply ih` worked refine @ih (λ {a : α} (hab : ReflTransGen r a b) => P a (ReflTransGen.tail hab hbc)) ?_ ?_ - { exact head hbc _ refl } - { exact fun h1 h2 ↦ head h1 (h2.tail hbc) } + · exact head hbc _ refl + · exact fun h1 h2 ↦ head h1 (h2.tail hbc) #align relation.refl_trans_gen.head_induction_on Relation.ReflTransGen.head_induction_on @[elab_as_elim] @@ -340,9 +340,9 @@ theorem trans_induction_on {P : ∀ {a b : α}, ReflTransGen r a b → Prop} {a (h : ReflTransGen r a b) (ih₁ : ∀ a, @P a a refl) (ih₂ : ∀ {a b} (h : r a b), P (single h)) (ih₃ : ∀ {a b c} (h₁ : ReflTransGen r a b) (h₂ : ReflTransGen r b c), P h₁ → P h₂ → P (h₁.trans h₂)) : P h := by - induction h - case refl => exact ih₁ a - case tail b c hab hbc ih => exact ih₃ hab (single hbc) ih (ih₂ hbc) + induction h with + | refl => exact ih₁ a + | tail hab hbc ih => exact ih₃ hab (single hbc) ih (ih₂ hbc) #align relation.refl_trans_gen.trans_induction_on Relation.ReflTransGen.trans_induction_on theorem cases_head (h : ReflTransGen r a b) : a = b ∨ ∃ c, r a c ∧ ReflTransGen r c b := by @@ -384,9 +384,9 @@ theorem to_reflTransGen {a b} (h : TransGen r a b) : ReflTransGen r a b := by #align relation.trans_gen.to_refl Relation.TransGen.to_reflTransGen theorem trans_left (hab : TransGen r a b) (hbc : ReflTransGen r b c) : TransGen r a c := by - induction hbc - case refl => assumption - case tail c d _ hcd hac => exact hac.tail hcd + induction hbc with + | refl => assumption + | tail _ hcd hac => exact hac.tail hcd #align relation.trans_gen.trans_left Relation.TransGen.trans_left instance : Trans (TransGen r) (ReflTransGen r) (TransGen r) := @@ -405,9 +405,9 @@ theorem head' (hab : r a b) (hbc : ReflTransGen r b c) : TransGen r a c := #align relation.trans_gen.head' Relation.TransGen.head' theorem tail' (hab : ReflTransGen r a b) (hbc : r b c) : TransGen r a c := by - induction hab generalizing c - case refl => exact single hbc - case tail _ _ _ hdb IH => exact tail (IH hdb) hbc + induction hab generalizing c with + | refl => exact single hbc + | tail _ hdb IH => exact tail (IH hdb) hbc #align relation.trans_gen.tail' Relation.TransGen.tail' theorem head (hab : r a b) (hbc : TransGen r b c) : TransGen r a c := @@ -418,9 +418,9 @@ theorem head (hab : r a b) (hbc : TransGen r b c) : TransGen r a c := theorem head_induction_on {P : ∀ a : α, TransGen r a b → Prop} {a : α} (h : TransGen r a b) (base : ∀ {a} (h : r a b), P a (single h)) (ih : ∀ {a c} (h' : r a c) (h : TransGen r c b), P c h → P a (h.head h')) : P a h := by - induction h - case single a h => exact base h - case tail b c _ hbc h_ih => + induction h with + | single h => exact base h + | @tail b c _ hbc h_ih => -- Lean 3 could figure out the motive and `apply h_ih` worked refine @h_ih (λ {a : α} (hab : @TransGen α r a b) => P a (TransGen.tail hab hbc)) ?_ ?_; exact fun h ↦ ih h (single hbc) (base hbc) @@ -438,9 +438,9 @@ theorem trans_induction_on {P : ∀ {a b : α}, TransGen r a b → Prop} {a b : #align relation.trans_gen.trans_induction_on Relation.TransGen.trans_induction_on theorem trans_right (hab : ReflTransGen r a b) (hbc : TransGen r b c) : TransGen r a c := by - induction hbc - case single c hbc => exact tail' hab hbc - case tail c d _ hcd hac => exact hac.tail hcd + induction hbc with + | single hbc => exact tail' hab hbc + | tail _ hcd hac => exact hac.tail hcd #align relation.trans_gen.trans_right Relation.TransGen.trans_right instance : Trans (ReflTransGen r) (TransGen r) (TransGen r) := @@ -455,9 +455,9 @@ theorem tail'_iff : TransGen r a c ↔ ∃ b, ReflTransGen r a b ∧ r b c := by theorem head'_iff : TransGen r a c ↔ ∃ b, r a b ∧ ReflTransGen r b c := by refine' ⟨fun h ↦ _, fun ⟨b, hab, hbc⟩ ↦ head' hab hbc⟩ - induction h - case single c hac => exact ⟨_, hac, by rfl⟩ - case tail b c _ hbc IH => + induction h with + | single hac => exact ⟨_, hac, by rfl⟩ + | tail _ hbc IH => rcases IH with ⟨d, had, hdb⟩ exact ⟨_, had, hdb.tail hbc⟩ #align relation.trans_gen.head'_iff Relation.TransGen.head'_iff @@ -498,9 +498,9 @@ section TransGen theorem transGen_eq_self (trans : Transitive r) : TransGen r = r := funext fun a ↦ funext fun b ↦ propext <| ⟨fun h ↦ by - induction h - case single _ hc => exact hc - case tail c d _ hcd hac => exact trans hac hcd, TransGen.single⟩ + induction h with + | single hc => exact hc + | tail _ hcd hac => exact trans hac hcd, TransGen.single⟩ #align relation.trans_gen_eq_self Relation.transGen_eq_self theorem transitive_transGen : Transitive (TransGen r) := fun _ _ _ ↦ TransGen.trans @@ -515,9 +515,9 @@ theorem transGen_idem : TransGen (TransGen r) = TransGen r := theorem TransGen.lift {p : β → β → Prop} {a b : α} (f : α → β) (h : ∀ a b, r a b → p (f a) (f b)) (hab : TransGen r a b) : TransGen p (f a) (f b) := by - induction hab - case single c hac => exact TransGen.single (h a c hac) - case tail c d _ hcd hac => exact TransGen.tail hac (h c d hcd) + induction hab with + | single hac => exact TransGen.single (h a _ hac) + | tail _ hcd hac => exact TransGen.tail hac (h _ _ hcd) #align relation.trans_gen.lift Relation.TransGen.lift theorem TransGen.lift' {p : β → β → Prop} {a b : α} (f : α → β) @@ -675,24 +675,24 @@ open ReflTransGen ReflGen /-- A sufficient condition for the Church-Rosser property. -/ theorem church_rosser (h : ∀ a b c, r a b → r a c → ∃ d, ReflGen r b d ∧ ReflTransGen r c d) (hab : ReflTransGen r a b) (hac : ReflTransGen r a c) : Join (ReflTransGen r) b c := by - induction hab - case refl => exact ⟨c, hac, refl⟩ - case tail d e _ hde ih => - rcases ih with ⟨b, hdb, hcb⟩ - have : ∃ a, ReflTransGen r e a ∧ ReflGen r b a := by - clear hcb - induction hdb - case refl => exact ⟨e, refl, ReflGen.single hde⟩ - case tail f b _ hfb ih => - rcases ih with ⟨a, hea, hfa⟩ - cases' hfa with _ hfa - · exact ⟨b, hea.tail hfb, ReflGen.refl⟩ - · rcases h _ _ _ hfb hfa with ⟨c, hbc, hac⟩ - exact ⟨c, hea.trans hac, hbc⟩ - rcases this with ⟨a, hea, hba⟩ - cases' hba with _ hba - · exact ⟨b, hea, hcb⟩ - · exact ⟨a, hea, hcb.tail hba⟩ + induction hab with + | refl => exact ⟨c, hac, refl⟩ + | @tail d e _ hde ih => + rcases ih with ⟨b, hdb, hcb⟩ + have : ∃ a, ReflTransGen r e a ∧ ReflGen r b a := by + clear hcb + induction hdb with + | refl => exact ⟨e, refl, ReflGen.single hde⟩ + | @tail f b _ hfb ih => + rcases ih with ⟨a, hea, hfa⟩ + cases' hfa with _ hfa + · exact ⟨b, hea.tail hfb, ReflGen.refl⟩ + · rcases h _ _ _ hfb hfa with ⟨c, hbc, hac⟩ + exact ⟨c, hea.trans hac, hbc⟩ + rcases this with ⟨a, hea, hba⟩ + cases' hba with _ hba + · exact ⟨b, hea, hcb⟩ + · exact ⟨a, hea, hcb.tail hba⟩ #align relation.church_rosser Relation.church_rosser diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index 1d0e05cec9e24..8f0d99b868349 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -82,12 +82,11 @@ theorem borel_eq_generateFrom_of_subbasis {s : Set (Set α)} [t : TopologicalSpa le_antisymm (generateFrom_le fun u (hu : t.IsOpen u) => by rw [hs] at hu - induction hu - case basic u hu => exact GenerateMeasurable.basic u hu - case univ => exact @MeasurableSet.univ α (generateFrom s) - case inter s₁ s₂ _ _ hs₁ hs₂ => exact @MeasurableSet.inter α (generateFrom s) _ _ hs₁ hs₂ - case - sUnion f hf ih => + induction hu with + | basic u hu => exact GenerateMeasurable.basic u hu + | univ => exact @MeasurableSet.univ α (generateFrom s) + | inter s₁ s₂ _ _ hs₁ hs₂ => exact @MeasurableSet.inter α (generateFrom s) _ _ hs₁ hs₂ + | sUnion f hf ih => rcases isOpen_sUnion_countable f (by rwa [hs]) with ⟨v, hv, vf, vu⟩ rw [← vu] exact @MeasurableSet.sUnion α (generateFrom s) _ hv fun x xv => ih _ (vf xv)) diff --git a/Mathlib/MeasureTheory/Integral/Marginal.lean b/Mathlib/MeasureTheory/Integral/Marginal.lean index 6568cf9f2ea25..d0a3fe41a9b4d 100644 --- a/Mathlib/MeasureTheory/Integral/Marginal.lean +++ b/Mathlib/MeasureTheory/Integral/Marginal.lean @@ -203,9 +203,9 @@ theorem lmarginal_image [DecidableEq δ'] {e : δ' → δ} (he : Injective e) (s (∫⋯∫⁻_s.image e, f ∘ (· ∘' e) ∂μ) x = (∫⋯∫⁻_s, f ∂μ ∘' e) (x ∘' e) := by have h : Measurable ((· ∘' e) : (∀ i, π i) → _) := measurable_pi_iff.mpr <| λ i ↦ measurable_pi_apply (e i) - induction s using Finset.induction generalizing x - case empty => simp - case insert i s hi ih => + induction s using Finset.induction generalizing x with + | empty => simp + | insert hi ih => rw [image_insert, lmarginal_insert _ (hf.comp h) (he.mem_finset_image.not.mpr hi), lmarginal_insert _ hf hi] simp_rw [ih, ← update_comp_eq_of_injective' x he] @@ -213,9 +213,9 @@ theorem lmarginal_image [DecidableEq δ'] {e : δ' → δ} (he : Injective e) (s theorem lmarginal_update_of_not_mem {i : δ} {f : (∀ i, π i) → ℝ≥0∞} (hf : Measurable f) (hi : i ∉ s) (x : ∀ i, π i) (y : π i) : (∫⋯∫⁻_s, f ∂μ) (Function.update x i y) = (∫⋯∫⁻_s, f ∘ (Function.update · i y) ∂μ) x := by - induction s using Finset.induction generalizing x - case empty => simp - case insert i' s hi' ih => + induction s using Finset.induction generalizing x with + | empty => simp + | @insert i' s hi' ih => rw [lmarginal_insert _ hf hi', lmarginal_insert _ (hf.comp measurable_update_left) hi'] have hii' : i ≠ i' := mt (by rintro rfl; exact mem_insert_self i s) hi simp_rw [update_comm hii', ih (mt Finset.mem_insert_of_mem hi)] diff --git a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean index 53f6968182cf1..ed66ca6f091de 100644 --- a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean +++ b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean @@ -205,10 +205,10 @@ theorem lintegral_prod_norm_pow_le {α ι : Type*} [MeasurableSpace α] {μ : Me (s : Finset ι) {f : ι → α → ℝ≥0∞} (hf : ∀ i ∈ s, AEMeasurable (f i) μ) {p : ι → ℝ} (hp : ∑ i in s, p i = 1) (h2p : ∀ i ∈ s, 0 ≤ p i) : ∫⁻ a, ∏ i in s, f i a ^ p i ∂μ ≤ ∏ i in s, (∫⁻ a, f i a ∂μ) ^ p i := by - induction s using Finset.induction generalizing p - case empty => + induction s using Finset.induction generalizing p with + | empty => simp at hp - case insert i₀ s hi₀ ih => + | @insert i₀ s hi₀ ih => rcases eq_or_ne (p i₀) 1 with h2i₀|h2i₀ · simp [hi₀] have h2p : ∀ i ∈ s, p i = 0 := by diff --git a/Mathlib/ModelTheory/Satisfiability.lean b/Mathlib/ModelTheory/Satisfiability.lean index ea357f76a7d62..106e1c287e6a3 100644 --- a/Mathlib/ModelTheory/Satisfiability.lean +++ b/Mathlib/ModelTheory/Satisfiability.lean @@ -260,11 +260,11 @@ direction between then `M` and a structure of cardinality `κ`. -/ theorem exists_elementaryEmbedding_card_eq (M : Type w') [L.Structure M] [iM : Infinite M] (κ : Cardinal.{w}) (h1 : ℵ₀ ≤ κ) (h2 : lift.{w} L.card ≤ Cardinal.lift.{max u v} κ) : ∃ N : Bundled L.Structure, (Nonempty (N ↪ₑ[L] M) ∨ Nonempty (M ↪ₑ[L] N)) ∧ #N = κ := by - cases le_or_gt (lift.{w'} κ) (Cardinal.lift.{w} #M) - case inl h => + cases le_or_gt (lift.{w'} κ) (Cardinal.lift.{w} #M) with + | inl h => obtain ⟨N, hN1, hN2⟩ := exists_elementaryEmbedding_card_eq_of_le L M κ h1 h2 h exact ⟨N, Or.inl hN1, hN2⟩ - case inr h => + | inr h => obtain ⟨N, hN1, hN2⟩ := exists_elementaryEmbedding_card_eq_of_ge L M κ h2 (le_of_lt h) exact ⟨N, Or.inr hN1, hN2⟩ #align first_order.language.exists_elementary_embedding_card_eq FirstOrder.Language.exists_elementaryEmbedding_card_eq diff --git a/Mathlib/ModelTheory/Ultraproducts.lean b/Mathlib/ModelTheory/Ultraproducts.lean index e7e2cc3eeaebf..1f192cae9a913 100644 --- a/Mathlib/ModelTheory/Ultraproducts.lean +++ b/Mathlib/ModelTheory/Ultraproducts.lean @@ -86,12 +86,9 @@ theorem term_realize_cast {β : Type*} (x : β → ∀ a, M a) (t : L.Term β) : convert @Term.realize_quotient_mk' L _ ((u : Filter α).productSetoid M) (Ultraproduct.setoidPrestructure M u) _ t x using 2 ext a - induction t - case var => - rfl - case func _ _ _ t_ih => - simp only [Term.realize, t_ih] - rfl + induction t with + | var => rfl + | func _ _ t_ih => simp only [Term.realize, t_ih]; rfl #align first_order.language.ultraproduct.term_realize_cast FirstOrder.Language.Ultraproduct.term_realize_cast variable [∀ a : α, Nonempty (M a)] diff --git a/Mathlib/Order/Atoms.lean b/Mathlib/Order/Atoms.lean index 2110a42e4bbaf..f967ed6d32a64 100644 --- a/Mathlib/Order/Atoms.lean +++ b/Mathlib/Order/Atoms.lean @@ -499,7 +499,7 @@ instance {α} [CompleteAtomicBooleanAlgebra α] : IsAtomistic α where have : (⨅ c : α, ⨆ x, b ⊓ cond x c (cᶜ)) = b := by simp [iSup_bool_eq, iInf_const] rw [← this]; clear this simp_rw [iInf_iSup_eq, iSup_le_iff]; intro g - by_cases h : (⨅ a, b ⊓ cond (g a) a (aᶜ)) = ⊥; case pos => simp [h] + if h : (⨅ a, b ⊓ cond (g a) a (aᶜ)) = ⊥ then simp [h] else refine le_sSup ⟨⟨h, fun c hc => ?_⟩, le_trans (by rfl) (le_iSup _ g)⟩; clear h have := lt_of_lt_of_le hc (le_trans (iInf_le _ c) inf_le_right) revert this @@ -1002,7 +1002,7 @@ theorem isAtom_iff {f : ∀ i, π i} [∀ i, PartialOrder (π i)] [∀ i, OrderB refine ⟨fun h => hfi ((Pi.eq_bot_iff.1 h) _), fun g hgf => Pi.eq_bot_iff.2 fun j => ?_⟩ have ⟨hgf, k, hgfk⟩ := Pi.lt_def.1 hgf obtain rfl : i = k := of_not_not fun hki => by rw [hbot _ (Ne.symm hki)] at hgfk; simp at hgfk - by_cases hij : j = i; case pos => subst hij; refine hlt _ hgfk + if hij : j = i then subst hij; refine hlt _ hgfk else refine eq_bot_iff.2 <| le_trans (hgf _) (eq_bot_iff.1 (hbot _ hij)) case mp => rintro ⟨hbot, h⟩ @@ -1063,14 +1063,12 @@ instance isAtomistic [∀ i, CompleteLattice (π i)] [∀ i, IsAtomistic (π i)] refine le_antisymm ?le ?ge case le => refine sSup_le fun a ⟨ha, hle⟩ => ?_ - refine le_sSup ⟨⟨_, ⟨_, _, ha, rfl⟩, ?_⟩, by simp⟩ - intro j; by_cases hij : j = i - case pos => subst hij; simpa - case neg => simp [hij] + refine le_sSup ⟨⟨_, ⟨_, _, ha, rfl⟩, fun j => ?_⟩, by simp⟩ + if hij : j = i then subst hij; simpa else simp [hij] case ge => refine sSup_le ?_ rintro _ ⟨⟨_, ⟨j, a, ha, rfl⟩, hle⟩, rfl⟩ - by_cases hij : i = j; case neg => simp [Function.update_noteq hij] + if hij : i = j then ?_ else simp [Function.update_noteq hij] subst hij; simp only [Function.update_same] exact le_sSup ⟨ha, by simpa using hle i⟩ diff --git a/Mathlib/Order/Chain.lean b/Mathlib/Order/Chain.lean index e6a3dd37055cf..74968f2a45755 100644 --- a/Mathlib/Order/Chain.lean +++ b/Mathlib/Order/Chain.lean @@ -219,24 +219,24 @@ theorem chainClosure_maxChain : ChainClosure r (maxChain r) := private theorem chainClosure_succ_total_aux (hc₁ : ChainClosure r c₁) (h : ∀ ⦃c₃⦄, ChainClosure r c₃ → c₃ ⊆ c₂ → c₂ = c₃ ∨ SuccChain r c₃ ⊆ c₂) : SuccChain r c₂ ⊆ c₁ ∨ c₁ ⊆ c₂ := by - induction hc₁ - case succ c₃ hc₃ ih => + induction hc₁ with + | @succ c₃ hc₃ ih => cases' ih with ih ih · exact Or.inl (ih.trans subset_succChain) · exact (h hc₃ ih).imp_left fun (h : c₂ = c₃) => h ▸ Subset.rfl - case union s _ ih => + | union _ ih => refine' or_iff_not_imp_left.2 fun hn => sUnion_subset fun a ha => _ exact (ih a ha).resolve_left fun h => hn <| h.trans <| subset_sUnion_of_mem ha private theorem chainClosure_succ_total (hc₁ : ChainClosure r c₁) (hc₂ : ChainClosure r c₂) (h : c₁ ⊆ c₂) : c₂ = c₁ ∨ SuccChain r c₁ ⊆ c₂ := by - induction hc₂ generalizing c₁ hc₁ - case succ c₂ _ ih => + induction hc₂ generalizing c₁ hc₁ with + | succ _ ih => refine' ((chainClosure_succ_total_aux hc₁) fun c₁ => ih).imp h.antisymm' fun h₁ => _ obtain rfl | h₂ := ih hc₁ h₁ · exact Subset.rfl · exact h₂.trans subset_succChain - case union s _ ih => + | union _ ih => apply Or.imp_left h.antisymm' apply by_contradiction simp only [sUnion_subset_iff, not_or, not_forall, exists_prop, and_imp, forall_exists_index] @@ -255,9 +255,9 @@ theorem ChainClosure.total (hc₁ : ChainClosure r c₁) (hc₂ : ChainClosure r theorem ChainClosure.succ_fixpoint (hc₁ : ChainClosure r c₁) (hc₂ : ChainClosure r c₂) (hc : SuccChain r c₂ = c₂) : c₁ ⊆ c₂ := by - induction hc₁ - case succ s₁ hc₁ h => exact (chainClosure_succ_total hc₁ hc₂ h).elim (fun h => h ▸ hc.subset) id - case union s _ ih => exact sUnion_subset ih + induction hc₁ with + | succ hc₁ h => exact (chainClosure_succ_total hc₁ hc₂ h).elim (fun h => h ▸ hc.subset) id + | union _ ih => exact sUnion_subset ih #align chain_closure.succ_fixpoint ChainClosure.succ_fixpoint theorem ChainClosure.succ_fixpoint_iff (hc : ChainClosure r c) : @@ -267,9 +267,9 @@ theorem ChainClosure.succ_fixpoint_iff (hc : ChainClosure r c) : #align chain_closure.succ_fixpoint_iff ChainClosure.succ_fixpoint_iff theorem ChainClosure.isChain (hc : ChainClosure r c) : IsChain r c := by - induction hc - case succ c _ h => exact h.succ - case union s hs h => + induction hc with + | succ _ h => exact h.succ + | union hs h => exact fun c₁ ⟨t₁, ht₁, (hc₁ : c₁ ∈ t₁)⟩ c₂ ⟨t₂, ht₂, (hc₂ : c₂ ∈ t₂)⟩ hneq => ((hs _ ht₁).total <| hs _ ht₂).elim (fun ht => h t₂ ht₂ (ht hc₁) hc₂ hneq) fun ht => h t₁ ht₁ hc₁ (ht hc₂) hneq diff --git a/Mathlib/Order/CompleteBooleanAlgebra.lean b/Mathlib/Order/CompleteBooleanAlgebra.lean index cebbaedd062a1..685d2f21ba9c7 100644 --- a/Mathlib/Order/CompleteBooleanAlgebra.lean +++ b/Mathlib/Order/CompleteBooleanAlgebra.lean @@ -139,9 +139,9 @@ instance (priority := 100) CompletelyDistribLattice.toCompleteDistribLattice _ = ⨅ b : s, ⨆ x : Bool, cond x a b := by simp_rw [iInf_subtype, iSup_bool_eq, cond] _ = _ := iInf_iSup_eq _ ≤ _ := iSup_le fun f => by - by_cases h : ∀ i, f i = false - case pos => simp [h, iInf_subtype, ← sInf_eq_iInf] - case neg => + if h : ∀ i, f i = false then + simp [h, iInf_subtype, ← sInf_eq_iInf] + else have ⟨i, h⟩ : ∃ i, f i = true := by simpa using h refine le_trans (iInf_le _ i) ?_ simp [h] @@ -162,8 +162,7 @@ instance (priority := 100) CompleteLinearOrder.toCompletelyDistribLattice [Compl let lhs := ⨅ a, ⨆ b, g a b let rhs := ⨆ h : ∀ a, β a, ⨅ a, g a (h a) suffices lhs ≤ rhs from le_antisymm this le_iInf_iSup - by_cases h : ∃ x, rhs < x ∧ x < lhs - case pos => + if h : ∃ x, rhs < x ∧ x < lhs then rcases h with ⟨x, hr, hl⟩ suffices rhs ≥ x from nomatch not_lt.2 this hr have : ∀ a, ∃ b, x < g a b := fun a => @@ -172,7 +171,7 @@ instance (priority := 100) CompleteLinearOrder.toCompletelyDistribLattice [Compl choose f hf using this refine le_trans ?_ (le_iSup _ f) refine le_iInf fun a => le_of_lt (hf a) - case neg => + else refine le_of_not_lt fun hrl : rhs < lhs => not_le_of_lt hrl ?_ replace h : ∀ x, x ≤ rhs ∨ lhs ≤ x := by simpa only [not_exists, not_and_or, not_or, not_lt] using h diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index 69553696881f4..dcd3fe24bb720 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -375,14 +375,14 @@ theorem le_generate_iff {s : Set (Set α)} {f : Filter α} : f ≤ generate s theorem mem_generate_iff {s : Set <| Set α} {U : Set α} : U ∈ generate s ↔ ∃ t ⊆ s, Set.Finite t ∧ ⋂₀ t ⊆ U := by constructor <;> intro h - · induction h - case basic V V_in => + · induction h with + | @basic V V_in => exact ⟨{V}, singleton_subset_iff.2 V_in, finite_singleton _, (sInter_singleton _).subset⟩ - case univ => exact ⟨∅, empty_subset _, finite_empty, subset_univ _⟩ - case superset V W _ hVW hV => + | univ => exact ⟨∅, empty_subset _, finite_empty, subset_univ _⟩ + | superset _ hVW hV => rcases hV with ⟨t, hts, ht, htV⟩ exact ⟨t, hts, ht, htV.trans hVW⟩ - case inter V W _ _ hV hW => + | inter _ _ hV hW => rcases hV, hW with ⟨⟨t, hts, ht, htV⟩, u, hus, hu, huW⟩ exact ⟨t ∪ u, union_subset hts hus, ht.union hu, @@ -972,9 +972,9 @@ theorem iInf_sets_induct {f : ι → Filter α} {s : Set α} (hs : s ∈ iInf f) rw [mem_iInf_finite'] at hs simp only [← Finset.inf_eq_iInf] at hs rcases hs with ⟨is, his⟩ - induction is using Finset.induction_on generalizing s - case empty => rwa [mem_top.1 his] - case insert ih => + induction is using Finset.induction_on generalizing s with + | empty => rwa [mem_top.1 his] + | insert _ ih => rw [Finset.inf_insert, mem_inf_iff] at his rcases his with ⟨s₁, hs₁, s₂, hs₂, rfl⟩ exact ins hs₁ (ih hs₂) @@ -2957,11 +2957,11 @@ theorem mem_traverse_iff (fs : List β') (t : Set (List α')) : t ∈ traverse f fs ↔ ∃ us : List (Set α'), Forall₂ (fun b (s : Set α') => s ∈ f b) fs us ∧ sequence us ⊆ t := by constructor - · induction fs generalizing t - case nil => + · induction fs generalizing t with + | nil => simp only [sequence, mem_pure, imp_self, forall₂_nil_left_iff, exists_eq_left, Set.pure_def, singleton_subset_iff, traverse_nil] - case cons b fs ih => + | cons b fs ih => intro ht rcases mem_seq_iff.1 ht with ⟨u, hu, v, hv, ht⟩ rcases mem_map_iff_exists_image.1 hu with ⟨w, hw, hwu⟩ diff --git a/Mathlib/RingTheory/Int/Basic.lean b/Mathlib/RingTheory/Int/Basic.lean index c616f9e1b1eb4..7bcb9fc5d5e92 100644 --- a/Mathlib/RingTheory/Int/Basic.lean +++ b/Mathlib/RingTheory/Int/Basic.lean @@ -304,9 +304,9 @@ theorem Int.exists_prime_and_dvd {n : ℤ} (hn : n.natAbs ≠ 1) : ∃ p, Prime open UniqueFactorizationMonoid theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by - cases n - case zero => simp - case succ n => + cases n with + | zero => simp + | succ n => rw [← Multiset.rel_eq, ← associated_eq_eq] apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _ · rw [Multiset.coe_prod, Nat.prod_factors n.succ_ne_zero] diff --git a/Mathlib/RingTheory/PrincipalIdealDomain.lean b/Mathlib/RingTheory/PrincipalIdealDomain.lean index 6bf87d61e679d..d5b05d9da86d0 100644 --- a/Mathlib/RingTheory/PrincipalIdealDomain.lean +++ b/Mathlib/RingTheory/PrincipalIdealDomain.lean @@ -173,12 +173,12 @@ theorem to_maximal_ideal [CommRing R] [IsDomain R] [IsPrincipalIdealRing R] {S : ⟨(ne_top_iff_one S).1 hpi.1, by intro T x hST hxS hxT cases' (mem_iff_generator_dvd _).1 (hST <| generator_mem S) with z hz - cases hpi.mem_or_mem (show generator T * z ∈ S from hz ▸ generator_mem S) - case inl h => + cases hpi.mem_or_mem (show generator T * z ∈ S from hz ▸ generator_mem S) with + | inl h => have hTS : T ≤ S rwa [← T.span_singleton_generator, Ideal.span_le, singleton_subset_iff] exact (hxS <| hTS hxT).elim - case inr h => + | inr h => cases' (mem_iff_generator_dvd _).1 h with y hy have : generator S ≠ 0 := mt (eq_bot_iff_generator_eq_zero _).2 hS rw [← mul_one (generator S), hy, mul_left_comm, mul_right_inj' this] at hz diff --git a/Mathlib/Topology/Connected/Basic.lean b/Mathlib/Topology/Connected/Basic.lean index 6369a5f29a852..3baa51a8817de 100644 --- a/Mathlib/Topology/Connected/Basic.lean +++ b/Mathlib/Topology/Connected/Basic.lean @@ -99,12 +99,12 @@ theorem isPreconnected_of_forall {s : Set α} (x : α) rcases H y ys with ⟨t, ts, xt, -, -⟩ exact ts xt -- porting note: todo: use `wlog xu : x ∈ u := hs xs using u v y z, v u z y` - cases hs xs - case inl xu => + cases hs xs with + | inl xu => rcases H y ys with ⟨t, ts, xt, yt, ht⟩ have := ht u v hu hv (ts.trans hs) ⟨x, xt, xu⟩ ⟨y, yt, yv⟩ exact this.imp fun z hz => ⟨ts hz.1, hz.2⟩ - case inr xv => + | inr xv => rcases H z zs with ⟨t, ts, xt, zt, ht⟩ have := ht v u hv hu (ts.trans <| by rwa [union_comm]) ⟨x, xt, xv⟩ ⟨z, zt, zu⟩ exact this.imp fun _ h => ⟨ts h.1, h.2.2, h.2.1⟩ @@ -172,12 +172,12 @@ theorem IsPreconnected.biUnion_of_reflTransGen {ι : Type*} {t : Set ι} {s : ι let R := fun i j : ι => (s i ∩ s j).Nonempty ∧ i ∈ t have P : ∀ i, i ∈ t → ∀ j, j ∈ t → ReflTransGen R i j → ∃ p, p ⊆ t ∧ i ∈ p ∧ j ∈ p ∧ IsPreconnected (⋃ j ∈ p, s j) := fun i hi j hj h => by - induction h - case refl => + induction h with + | refl => refine ⟨{i}, singleton_subset_iff.mpr hi, mem_singleton i, mem_singleton i, ?_⟩ rw [biUnion_singleton] exact H i hi - case tail j k _ hjk ih => + | @tail j k _ hjk ih => obtain ⟨p, hpt, hip, hjp, hp⟩ := ih hjk.2 refine ⟨insert k p, insert_subset_iff.mpr ⟨hj, hpt⟩, mem_insert_of_mem k hip, mem_insert k p, ?_⟩ @@ -1043,9 +1043,9 @@ theorem isConnected_iff_sUnion_disjoint_open {s : Set α} : (∀ u ∈ U, IsOpen u) → (s ⊆ ⋃₀ ↑U) → ∃ u ∈ U, s ⊆ u := by rw [IsConnected, isPreconnected_iff_subset_of_disjoint] refine ⟨fun ⟨hne, h⟩ U hU hUo hsU => ?_, fun h => ⟨?_, fun u v hu hv hs hsuv => ?_⟩⟩ - · induction U using Finset.induction_on - case empty => exact absurd (by simpa using hsU) hne.not_subset_empty - case insert u U uU IH => + · induction U using Finset.induction_on with + | empty => exact absurd (by simpa using hsU) hne.not_subset_empty + | @insert u U uU IH => simp only [← ball_cond_comm, Finset.forall_mem_insert, Finset.exists_mem_insert, Finset.coe_insert, sUnion_insert, implies_true, true_and] at * refine (h _ hUo.1 (⋃₀ ↑U) (isOpen_sUnion hUo.2) hsU ?_).imp_right ?_ diff --git a/Mathlib/Topology/EMetricSpace/Basic.lean b/Mathlib/Topology/EMetricSpace/Basic.lean index cfd536a0463f5..fb0f39723ead5 100644 --- a/Mathlib/Topology/EMetricSpace/Basic.lean +++ b/Mathlib/Topology/EMetricSpace/Basic.lean @@ -132,9 +132,9 @@ theorem edist_triangle4 (x y z t : α) : edist x t ≤ edist x y + edist y z + e /-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/ theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) : edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by - induction n, h using Nat.le_induction - case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self] - case succ n hle ihn => + induction n, h using Nat.le_induction with + | base => rw [Finset.Ico_self, Finset.sum_empty, edist_self] + | succ n hle ihn => calc edist (f m) (f (n + 1)) ≤ edist (f m) (f n) + edist (f n) (f (n + 1)) := edist_triangle _ _ _ _ ≤ (∑ i in Finset.Ico m n, _) + _ := add_le_add ihn le_rfl diff --git a/Mathlib/Topology/Irreducible.lean b/Mathlib/Topology/Irreducible.lean index 8f7f08d59a901..e829987f55b54 100644 --- a/Mathlib/Topology/Irreducible.lean +++ b/Mathlib/Topology/Irreducible.lean @@ -254,9 +254,9 @@ theorem isIrreducible_iff_sInter : ∀ (U : Finset (Set X)), (∀ u ∈ U, IsOpen u) → (∀ u ∈ U, (s ∩ u).Nonempty) → (s ∩ ⋂₀ ↑U).Nonempty := by refine ⟨fun h U hu hU => ?_, fun h => ⟨?_, ?_⟩⟩ - · induction U using Finset.induction_on - case empty => simpa using h.nonempty - case insert u U _ IH => + · induction U using Finset.induction_on with + | empty => simpa using h.nonempty + | @insert u U _ IH => rw [Finset.coe_insert, sInter_insert] rw [Finset.forall_mem_insert] at hu hU exact h.2 _ _ hu.1 (U.finite_toSet.isOpen_sInter hu.2) hU.1 (IH hu.2 hU.2) diff --git a/Mathlib/Topology/List.lean b/Mathlib/Topology/List.lean index 2720ef7c2e1b0..7d3e3e3eba950 100644 --- a/Mathlib/Topology/List.lean +++ b/Mathlib/Topology/List.lean @@ -26,9 +26,9 @@ instance : TopologicalSpace (List α) := theorem nhds_list (as : List α) : 𝓝 as = traverse 𝓝 as := by refine' nhds_mkOfNhds _ _ _ _ · intro l - induction l - case nil => exact le_rfl - case cons a l ih => + induction l with + | nil => exact le_rfl + | cons a l ih => suffices List.cons <$> pure a <*> pure l ≤ List.cons <$> 𝓝 a <*> traverse 𝓝 l by simpa only [functor_norm] using this exact Filter.seq_mono (Filter.map_mono <| pure_le_nhds a) ih @@ -36,13 +36,13 @@ theorem nhds_list (as : List α) : 𝓝 as = traverse 𝓝 as := by rcases (mem_traverse_iff _ _).1 hs with ⟨u, hu, hus⟩ clear as hs have : ∃ v : List (Set α), l.Forall₂ (fun a s => IsOpen s ∧ a ∈ s) v ∧ sequence v ⊆ s - induction hu generalizing s - case nil _hs => + induction hu generalizing s with + | nil => exists [] simp only [List.forall₂_nil_left_iff, exists_eq_left] exact ⟨trivial, hus⟩ -- porting note -- renamed reordered variables based on previous types - case cons a s as ss hts h ht _ ih => + | cons ht _ ih => rcases mem_nhds_iff.1 ht with ⟨u, hut, hu⟩ rcases ih _ Subset.rfl with ⟨v, hv, hvss⟩ exact diff --git a/Mathlib/Topology/Order/LowerUpperTopology.lean b/Mathlib/Topology/Order/LowerUpperTopology.lean index 7bfb62fc347cb..273580aee242c 100644 --- a/Mathlib/Topology/Order/LowerUpperTopology.lean +++ b/Mathlib/Topology/Order/LowerUpperTopology.lean @@ -241,11 +241,11 @@ theorem isClosed_upperClosure (h : s.Finite) : IsClosed (upperClosure s : Set α theorem isLowerSet_of_isOpen (h : IsOpen s) : IsLowerSet s := by -- porting note: `rw` leaves a shadowed assumption replace h := isOpen_iff_generate_Ici_compl.1 h - induction h - case basic u h' => obtain ⟨a, rfl⟩ := h'; exact (isUpperSet_Ici a).compl - case univ => exact isLowerSet_univ - case inter u v _ _ hu2 hv2 => exact hu2.inter hv2 - case sUnion _ _ ih => exact isLowerSet_sUnion ih + induction h with + | basic u h' => obtain ⟨a, rfl⟩ := h'; exact (isUpperSet_Ici a).compl + | univ => exact isLowerSet_univ + | inter u v _ _ hu2 hv2 => exact hu2.inter hv2 + | sUnion _ _ ih => exact isLowerSet_sUnion ih #align lower_topology.is_lower_set_of_is_open Topology.IsLower.isLowerSet_of_isOpen theorem isUpperSet_of_isClosed (h : IsClosed s) : IsUpperSet s := From 4be645d524c30fdfef15297940afd38cb4622f07 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 29 Dec 2023 10:03:01 +0000 Subject: [PATCH 274/353] chore: bump to nightly-2023-12-29 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 400a8aac3fbbc..040f43d41bbbd 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-24 +leanprover/lean4:nightly-2023-12-29 From b060d4a1a3b92d46405ba092def333a37af6c397 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 30 Dec 2023 02:31:11 +0000 Subject: [PATCH 275/353] chore(Data/Fintype/Fin): golf a proof (#9336) We already have it for `Set.range`. --- Mathlib/Data/Fintype/Fin.lean | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/Mathlib/Data/Fintype/Fin.lean b/Mathlib/Data/Fintype/Fin.lean index 280e2fcc31950..4a4a832ea71b7 100644 --- a/Mathlib/Data/Fintype/Fin.lean +++ b/Mathlib/Data/Fintype/Fin.lean @@ -28,24 +28,13 @@ theorem map_valEmbedding_univ : (Finset.univ : Finset (Fin n)).map Fin.valEmbedd #align fin.map_subtype_embedding_univ Fin.map_valEmbedding_univ @[simp] -theorem Ioi_zero_eq_map : Ioi (0 : Fin n.succ) = univ.map (Fin.succEmbedding _).toEmbedding := by - ext i - simp only [mem_Ioi, mem_map, mem_univ, Function.Embedding.coeFn_mk, exists_true_left] - constructor - · refine' cases _ _ i - · rintro ⟨⟨⟩⟩ - · intro j _ - use j - simp only [val_succEmbedding, and_self, RelEmbedding.coe_toEmbedding] - · rintro ⟨i, _, rfl⟩ - exact succ_pos _ +theorem Ioi_zero_eq_map : Ioi (0 : Fin n.succ) = univ.map (Fin.succEmbedding _).toEmbedding := + coe_injective <| by ext; simp [pos_iff_ne_zero] #align fin.Ioi_zero_eq_map Fin.Ioi_zero_eq_map @[simp] -theorem Iio_last_eq_map : Iio (Fin.last n) = Finset.univ.map Fin.castSuccEmb.toEmbedding := by - apply Finset.map_injective Fin.valEmbedding - rw [Finset.map_map, Fin.map_valEmbedding_Iio, Fin.val_last] - exact map_valEmbedding_univ.symm +theorem Iio_last_eq_map : Iio (Fin.last n) = Finset.univ.map Fin.castSuccEmb.toEmbedding := + coe_injective <| by ext; simp [lt_def] #align fin.Iio_last_eq_map Fin.Iio_last_eq_map @[simp] From 42060a27a3a7be4eda7a115d7b990cb31aefb120 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Sat, 30 Dec 2023 02:50:59 +0000 Subject: [PATCH 276/353] chore: reduce imports in Mathlib.RingTheory.Noetherian (#9322) --- Mathlib/RingTheory/Filtration.lean | 1 + Mathlib/RingTheory/Noetherian.lean | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Mathlib/RingTheory/Filtration.lean b/Mathlib/RingTheory/Filtration.lean index 107850e6a4a87..24b66f943c582 100644 --- a/Mathlib/RingTheory/Filtration.lean +++ b/Mathlib/RingTheory/Filtration.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ +import Mathlib.Algebra.Ring.Idempotents import Mathlib.RingTheory.Ideal.LocalRing import Mathlib.RingTheory.Noetherian import Mathlib.RingTheory.ReesAlgebra diff --git a/Mathlib/RingTheory/Noetherian.lean b/Mathlib/RingTheory/Noetherian.lean index 3eef173dc2b31..9cc5f70c24e04 100644 --- a/Mathlib/RingTheory/Noetherian.lean +++ b/Mathlib/RingTheory/Noetherian.lean @@ -3,14 +3,7 @@ Copyright (c) 2018 Mario Carneiro, Kevin Buzzard. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Kevin Buzzard -/ -import Mathlib.Algebra.Algebra.Subalgebra.Basic -import Mathlib.Algebra.Algebra.Tower -import Mathlib.Algebra.Ring.Idempotents -import Mathlib.GroupTheory.Finiteness -import Mathlib.LinearAlgebra.LinearIndependent -import Mathlib.Order.CompactlyGenerated import Mathlib.Order.Filter.EventuallyConst -import Mathlib.Order.OrderIsoNat import Mathlib.RingTheory.Finiteness import Mathlib.RingTheory.Nilpotent From d8b7c07348d5c5fe16c07c2274eb944ecce69daf Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Sat, 30 Dec 2023 02:51:00 +0000 Subject: [PATCH 277/353] chore: rename `IsScalarTower.of_ring_hom` (#9330) It's about `AlgHom` not `RingHom`. Co-authored-by: Junyan Xu --- Mathlib/Algebra/Algebra/Tower.lean | 4 ++-- Mathlib/NumberTheory/Cyclotomic/Basic.lean | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Algebra/Algebra/Tower.lean b/Mathlib/Algebra/Algebra/Tower.lean index 99a994bf4f4b0..dc89d28b24128 100644 --- a/Mathlib/Algebra/Algebra/Tower.lean +++ b/Mathlib/Algebra/Algebra/Tower.lean @@ -175,12 +175,12 @@ instance (priority := 999) subsemiring (U : Subsemiring S) : IsScalarTower U S A #align is_scalar_tower.subsemiring IsScalarTower.subsemiring -- Porting note: @[nolint instance_priority] -instance (priority := 999) of_ring_hom {R A B : Type*} [CommSemiring R] [CommSemiring A] +instance (priority := 999) of_algHom {R A B : Type*} [CommSemiring R] [CommSemiring A] [CommSemiring B] [Algebra R A] [Algebra R B] (f : A →ₐ[R] B) : @IsScalarTower R A B _ f.toRingHom.toAlgebra.toSMul _ := letI := (f : A →+* B).toAlgebra of_algebraMap_eq fun x => (f.commutes x).symm -#align is_scalar_tower.of_ring_hom IsScalarTower.of_ring_hom +#align is_scalar_tower.of_ring_hom IsScalarTower.of_algHom end Semiring diff --git a/Mathlib/NumberTheory/Cyclotomic/Basic.lean b/Mathlib/NumberTheory/Cyclotomic/Basic.lean index 992a152e28996..072f72e49bc12 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Basic.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Basic.lean @@ -285,7 +285,7 @@ theorem equiv {C : Type*} [CommRing C] [Algebra A C] [h : IsCyclotomicExtension (f : B ≃ₐ[A] C) : IsCyclotomicExtension S A C := by letI : Algebra B C := f.toAlgHom.toRingHom.toAlgebra haveI : IsCyclotomicExtension {1} B C := singleton_one_of_algebraMap_bijective f.surjective - haveI : IsScalarTower A B C := IsScalarTower.of_ring_hom f.toAlgHom + haveI : IsScalarTower A B C := IsScalarTower.of_algHom f.toAlgHom exact (iff_union_singleton_one _ _ _).2 (trans S {1} A B C f.injective) #align is_cyclotomic_extension.equiv IsCyclotomicExtension.equiv From 7392ea7cefb714816ac6592ade9910a3fd7b3c9b Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Sat, 30 Dec 2023 03:42:51 +0000 Subject: [PATCH 278/353] chore: deduplicate `LinearIndependent.set_finite_of_isNoetherian` (#9300) Also moved several lemmas into `Mathlib/LinearAlgebra/Basis.lean`. Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib/FieldTheory/Finiteness.lean | 2 +- Mathlib/LinearAlgebra/Basis.lean | 152 ++++++++++++++++++ Mathlib/LinearAlgebra/Dimension.lean | 154 ------------------- Mathlib/LinearAlgebra/FiniteDimensional.lean | 6 +- Mathlib/RingTheory/Noetherian.lean | 42 +++-- 5 files changed, 176 insertions(+), 180 deletions(-) diff --git a/Mathlib/FieldTheory/Finiteness.lean b/Mathlib/FieldTheory/Finiteness.lean index b9bf6414c6792..c0b87f5efd188 100644 --- a/Mathlib/FieldTheory/Finiteness.lean +++ b/Mathlib/FieldTheory/Finiteness.lean @@ -32,7 +32,7 @@ theorem iff_rank_lt_aleph0 : IsNoetherian K V ↔ Module.rank K V < ℵ₀ := by rw [← b.mk_eq_rank'', lt_aleph0_iff_set_finite] constructor · intro - exact finite_of_linearIndependent (Basis.ofVectorSpaceIndex.linearIndependent K V) + exact (Basis.ofVectorSpaceIndex.linearIndependent K V).set_finite_of_isNoetherian · intro hbfinite refine' @isNoetherian_of_linearEquiv K (⊤ : Submodule K V) V _ _ _ _ _ (LinearEquiv.ofTop _ rfl) diff --git a/Mathlib/LinearAlgebra/Basis.lean b/Mathlib/LinearAlgebra/Basis.lean index 7587b3e25a41b..82ce4f3fdf46b 100644 --- a/Mathlib/LinearAlgebra/Basis.lean +++ b/Mathlib/LinearAlgebra/Basis.lean @@ -10,6 +10,7 @@ import Mathlib.LinearAlgebra.Finsupp import Mathlib.LinearAlgebra.LinearIndependent import Mathlib.LinearAlgebra.LinearPMap import Mathlib.LinearAlgebra.Projection +import Mathlib.SetTheory.Cardinal.Cofinality #align_import linear_algebra.basis from "leanprover-community/mathlib"@"13bce9a6b6c44f6b4c91ac1c1d2a816e2533d395" @@ -1492,3 +1493,154 @@ theorem Basis.mem_span_iff_repr_mem (m : M) : #align basis.mem_span_iff_repr_mem Basis.mem_span_iff_repr_mem end RestrictScalars + +section Finite + +open Basis Cardinal + +universe v v' v'' u₁' w w' + +variable {R : Type u} {M M₁ : Type v} {M' : Type v'} {ι : Type w} + +variable [Ring R] [AddCommGroup M] [AddCommGroup M'] [AddCommGroup M₁] [Nontrivial R] + +variable [Module R M] [Module R M'] [Module R M₁] + +-- One might hope that a finite spanning set implies that any linearly independent set is finite. +-- While this is true over a division ring +-- (simply because any linearly independent set can be extended to a basis), +-- or more generally over a ring satisfying the strong rank condition +-- (which covers all commutative rings; see `LinearIndependent.finite_of_le_span_finite`), +-- this is not true in general. +-- For example, the left ideal generated by the variables in a noncommutative polynomial ring +-- (`FreeAlgebra R ι`) in infinitely many variables (indexed by `ι`) is free +-- with an infinite basis (consisting of the variables). +-- As another example, for any commutative ring R, the ring of column-finite matrices +-- `Module.End R (ℕ →₀ R)` is isomorphic to `ℕ → Module.End R (ℕ →₀ R)` as a module over itself, +-- which also clearly contains an infinite linearly independent set. +/-- +Over any nontrivial ring, the existence of a finite spanning set implies that any basis is finite. +-/ +lemma basis_finite_of_finite_spans (w : Set M) (hw : w.Finite) (s : span R w = ⊤) {ι : Type w} + (b : Basis ι R M) : Finite ι := by + classical + haveI := hw.to_subtype + cases nonempty_fintype w + -- We'll work by contradiction, assuming `ι` is infinite. + rw [← not_infinite_iff_finite] + intro i + -- Let `S` be the union of the supports of `x ∈ w` expressed as linear combinations of `b`. + -- This is a finite set since `w` is finite. + let S : Finset ι := Finset.univ.sup fun x : w => (b.repr x).support + let bS : Set M := b '' S + have h : ∀ x ∈ w, x ∈ span R bS := by + intro x m + rw [← b.total_repr x, Finsupp.span_image_eq_map_total, Submodule.mem_map] + use b.repr x + simp only [and_true_iff, eq_self_iff_true, Finsupp.mem_supported] + change (b.repr x).support ≤ S + convert Finset.le_sup (α := Finset ι) (by simp : (⟨x, m⟩ : w) ∈ Finset.univ) + rfl + -- Thus this finite subset of the basis elements spans the entire module. + have k : span R bS = ⊤ := eq_top_iff.2 (le_trans s.ge (span_le.2 h)) + -- Now there is some `x : ι` not in `S`, since `ι` is infinite. + obtain ⟨x, nm⟩ := Infinite.exists_not_mem_finset S + -- However it must be in the span of the finite subset, + have k' : b x ∈ span R bS := by + rw [k] + exact mem_top + -- giving the desire contradiction. + exact b.linearIndependent.not_mem_span_image nm k' +#align basis_fintype_of_finite_spans basis_finite_of_finite_spansₓ + +-- From [Les familles libres maximales d'un module ont-elles le meme cardinal?][lazarus1973] +/-- Over any ring `R`, if `b` is a basis for a module `M`, +and `s` is a maximal linearly independent set, +then the union of the supports of `x ∈ s` (when written out in the basis `b`) is all of `b`. +-/ +theorem union_support_maximal_linearIndependent_eq_range_basis {ι : Type w} (b : Basis ι R M) + {κ : Type w'} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : + ⋃ k, ((b.repr (v k)).support : Set ι) = Set.univ := by + -- If that's not the case, + by_contra h + simp only [← Ne.def, ne_univ_iff_exists_not_mem, mem_iUnion, not_exists_not, + Finsupp.mem_support_iff, Finset.mem_coe] at h + -- We have some basis element `b b'` which is not in the support of any of the `v i`. + obtain ⟨b', w⟩ := h + -- Using this, we'll construct a linearly independent family strictly larger than `v`, + -- by also using this `b b'`. + let v' : Option κ → M := fun o => o.elim (b b') v + have r : range v ⊆ range v' := by + rintro - ⟨k, rfl⟩ + use some k + rfl + have r' : b b' ∉ range v := by + rintro ⟨k, p⟩ + simpa [w] using congr_arg (fun m => (b.repr m) b') p + have r'' : range v ≠ range v' := by + intro e + have p : b b' ∈ range v' := by + use none + rfl + rw [← e] at p + exact r' p + -- The key step in the proof is checking that this strictly larger family is linearly independent. + have i' : LinearIndependent R ((↑) : range v' → M) := by + apply LinearIndependent.to_subtype_range + rw [linearIndependent_iff] + intro l z + rw [Finsupp.total_option] at z + simp only [Option.elim'] at z + change _ + Finsupp.total κ M R v l.some = 0 at z + -- We have some linear combination of `b b'` and the `v i`, which we want to show is trivial. + -- We'll first show the coefficient of `b b'` is zero, + -- by expressing the `v i` in the basis `b`, and using that the `v i` have no `b b'` term. + have l₀ : l none = 0 := by + rw [← eq_neg_iff_add_eq_zero] at z + replace z := neg_eq_iff_eq_neg.mpr z + apply_fun fun x => b.repr x b' at z + simp only [repr_self, LinearEquiv.map_smul, mul_one, Finsupp.single_eq_same, Pi.neg_apply, + Finsupp.smul_single', LinearEquiv.map_neg, Finsupp.coe_neg] at z + erw [FunLike.congr_fun (Finsupp.apply_total R (b.repr : M →ₗ[R] ι →₀ R) v l.some) b'] at z + simpa [Finsupp.total_apply, w] using z + -- Then all the other coefficients are zero, because `v` is linear independent. + have l₁ : l.some = 0 := by + rw [l₀, zero_smul, zero_add] at z + exact linearIndependent_iff.mp i _ z + -- Finally we put those facts together to show the linear combination is trivial. + ext (_ | a) + · simp only [l₀, Finsupp.coe_zero, Pi.zero_apply] + · erw [FunLike.congr_fun l₁ a] + simp only [Finsupp.coe_zero, Pi.zero_apply] + rw [LinearIndependent.Maximal] at m + specialize m (range v') i' r + exact r'' m +#align union_support_maximal_linear_independent_eq_range_basis union_support_maximal_linearIndependent_eq_range_basis + +/-- Over any ring `R`, if `b` is an infinite basis for a module `M`, +and `s` is a maximal linearly independent set, +then the cardinality of `b` is bounded by the cardinality of `s`. +-/ +theorem infinite_basis_le_maximal_linearIndependent' {ι : Type w} (b : Basis ι R M) [Infinite ι] + {κ : Type w'} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : + Cardinal.lift.{w'} #ι ≤ Cardinal.lift.{w} #κ := by + let Φ := fun k : κ => (b.repr (v k)).support + have w₁ : #ι ≤ #(Set.range Φ) := by + apply Cardinal.le_range_of_union_finset_eq_top + exact union_support_maximal_linearIndependent_eq_range_basis b v i m + have w₂ : Cardinal.lift.{w'} #(Set.range Φ) ≤ Cardinal.lift.{w} #κ := Cardinal.mk_range_le_lift + exact (Cardinal.lift_le.mpr w₁).trans w₂ +#align infinite_basis_le_maximal_linear_independent' infinite_basis_le_maximal_linearIndependent' + +-- (See `infinite_basis_le_maximal_linearIndependent'` for the more general version +-- where the index types can live in different universes.) +/-- Over any ring `R`, if `b` is an infinite basis for a module `M`, +and `s` is a maximal linearly independent set, +then the cardinality of `b` is bounded by the cardinality of `s`. +-/ +theorem infinite_basis_le_maximal_linearIndependent {ι : Type w} (b : Basis ι R M) [Infinite ι] + {κ : Type w} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : #ι ≤ #κ := + Cardinal.lift_le.mp (infinite_basis_le_maximal_linearIndependent' b v i m) +#align infinite_basis_le_maximal_linear_independent infinite_basis_le_maximal_linearIndependent + +end Finite diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean index 6b7927f9d8055..88b62d39a7e7e 100644 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ b/Mathlib/LinearAlgebra/Dimension.lean @@ -345,160 +345,6 @@ theorem exists_mem_ne_zero_of_rank_pos {s : Submodule R M} (h : 0 < Module.rank exists_mem_ne_zero_of_ne_bot fun eq => by rw [eq, rank_bot] at h; exact lt_irrefl _ h #align exists_mem_ne_zero_of_rank_pos exists_mem_ne_zero_of_rank_pos -/-- A linearly-independent family of vectors in a module over a non-trivial ring must be finite if -the module is Noetherian. -/ -theorem LinearIndependent.finite_of_isNoetherian [IsNoetherian R M] {v : ι → M} - (hv : LinearIndependent R v) : Finite ι := by - have hwf := isNoetherian_iff_wellFounded.mp (by infer_instance : IsNoetherian R M) - refine' CompleteLattice.WellFounded.finite_of_independent hwf hv.independent_span_singleton - fun i contra => _ - apply hv.ne_zero i - have : v i ∈ R ∙ v i := Submodule.mem_span_singleton_self (v i) - rwa [contra, Submodule.mem_bot] at this -#align linear_independent.finite_of_is_noetherian LinearIndependent.finite_of_isNoetherian - -theorem LinearIndependent.set_finite_of_isNoetherian [IsNoetherian R M] {s : Set M} - (hi : LinearIndependent R ((↑) : s → M)) : s.Finite := - @Set.toFinite _ _ hi.finite_of_isNoetherian -#align linear_independent.set_finite_of_is_noetherian LinearIndependent.set_finite_of_isNoetherian - --- One might hope that a finite spanning set implies that any linearly independent set is finite. --- While this is true over a division ring --- (simply because any linearly independent set can be extended to a basis), --- or over a ring satisfying the strong rank condition --- (which covers all commutative rings; see `LinearIndependent.finite_of_le_span_finite`). --- this is not true in general. --- For example, the left ideal generated by the variables in a noncommutative polynomial ring --- (`FreeAlgebra R ι`) in infinitely many variables (indexed by `ι`) is free --- with an infinite basis (consisting of the variables). --- As another example, for any commutative ring R, the ring of column-finite matrices --- `Module.End R (ℕ →₀ R)` is isomorphic to `ℕ → Module.End R (ℕ →₀ R)` as a module over itself, --- which also clearly contains an infinite linearly independent set. -/-- -Over any nontrivial ring, the existence of a finite spanning set implies that any basis is finite. --/ -lemma basis_finite_of_finite_spans (w : Set M) (hw : w.Finite) (s : span R w = ⊤) {ι : Type w} - (b : Basis ι R M) : Finite ι := by - classical - haveI := hw.to_subtype - cases nonempty_fintype w - -- We'll work by contradiction, assuming `ι` is infinite. - rw [← not_infinite_iff_finite] - intro i - -- Let `S` be the union of the supports of `x ∈ w` expressed as linear combinations of `b`. - -- This is a finite set since `w` is finite. - let S : Finset ι := Finset.univ.sup fun x : w => (b.repr x).support - let bS : Set M := b '' S - have h : ∀ x ∈ w, x ∈ span R bS := by - intro x m - rw [← b.total_repr x, Finsupp.span_image_eq_map_total, Submodule.mem_map] - use b.repr x - simp only [and_true_iff, eq_self_iff_true, Finsupp.mem_supported] - change (b.repr x).support ≤ S - convert Finset.le_sup (α := Finset ι) (by simp : (⟨x, m⟩ : w) ∈ Finset.univ) - rfl - -- Thus this finite subset of the basis elements spans the entire module. - have k : span R bS = ⊤ := eq_top_iff.2 (le_trans s.ge (span_le.2 h)) - -- Now there is some `x : ι` not in `S`, since `ι` is infinite. - obtain ⟨x, nm⟩ := Infinite.exists_not_mem_finset S - -- However it must be in the span of the finite subset, - have k' : b x ∈ span R bS := by - rw [k] - exact mem_top - -- giving the desire contradiction. - exact b.linearIndependent.not_mem_span_image nm k' -#align basis_fintype_of_finite_spans basis_finite_of_finite_spansₓ - --- From [Les familles libres maximales d'un module ont-elles le meme cardinal?][lazarus1973] -/-- Over any ring `R`, if `b` is a basis for a module `M`, -and `s` is a maximal linearly independent set, -then the union of the supports of `x ∈ s` (when written out in the basis `b`) is all of `b`. --/ -theorem union_support_maximal_linearIndependent_eq_range_basis {ι : Type w} (b : Basis ι R M) - {κ : Type w'} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : - ⋃ k, ((b.repr (v k)).support : Set ι) = Set.univ := by - -- If that's not the case, - by_contra h - simp only [← Ne.def, ne_univ_iff_exists_not_mem, mem_iUnion, not_exists_not, - Finsupp.mem_support_iff, Finset.mem_coe] at h - -- We have some basis element `b b'` which is not in the support of any of the `v i`. - obtain ⟨b', w⟩ := h - -- Using this, we'll construct a linearly independent family strictly larger than `v`, - -- by also using this `b b'`. - let v' : Option κ → M := fun o => o.elim (b b') v - have r : range v ⊆ range v' := by - rintro - ⟨k, rfl⟩ - use some k - rfl - have r' : b b' ∉ range v := by - rintro ⟨k, p⟩ - simpa [w] using congr_arg (fun m => (b.repr m) b') p - have r'' : range v ≠ range v' := by - intro e - have p : b b' ∈ range v' := by - use none - rfl - rw [← e] at p - exact r' p - -- The key step in the proof is checking that this strictly larger family is linearly independent. - have i' : LinearIndependent R ((↑) : range v' → M) := by - apply LinearIndependent.to_subtype_range - rw [linearIndependent_iff] - intro l z - rw [Finsupp.total_option] at z - simp only [Option.elim'] at z - change _ + Finsupp.total κ M R v l.some = 0 at z - -- We have some linear combination of `b b'` and the `v i`, which we want to show is trivial. - -- We'll first show the coefficient of `b b'` is zero, - -- by expressing the `v i` in the basis `b`, and using that the `v i` have no `b b'` term. - have l₀ : l none = 0 := by - rw [← eq_neg_iff_add_eq_zero] at z - replace z := neg_eq_iff_eq_neg.mpr z - apply_fun fun x => b.repr x b' at z - simp only [repr_self, LinearEquiv.map_smul, mul_one, Finsupp.single_eq_same, Pi.neg_apply, - Finsupp.smul_single', LinearEquiv.map_neg, Finsupp.coe_neg] at z - erw [FunLike.congr_fun (Finsupp.apply_total R (b.repr : M →ₗ[R] ι →₀ R) v l.some) b'] at z - simpa [Finsupp.total_apply, w] using z - -- Then all the other coefficients are zero, because `v` is linear independent. - have l₁ : l.some = 0 := by - rw [l₀, zero_smul, zero_add] at z - exact linearIndependent_iff.mp i _ z - -- Finally we put those facts together to show the linear combination is trivial. - ext (_ | a) - · simp only [l₀, Finsupp.coe_zero, Pi.zero_apply] - · erw [FunLike.congr_fun l₁ a] - simp only [Finsupp.coe_zero, Pi.zero_apply] - rw [LinearIndependent.Maximal] at m - specialize m (range v') i' r - exact r'' m -#align union_support_maximal_linear_independent_eq_range_basis union_support_maximal_linearIndependent_eq_range_basis - -/-- Over any ring `R`, if `b` is an infinite basis for a module `M`, -and `s` is a maximal linearly independent set, -then the cardinality of `b` is bounded by the cardinality of `s`. --/ -theorem infinite_basis_le_maximal_linearIndependent' {ι : Type w} (b : Basis ι R M) [Infinite ι] - {κ : Type w'} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : - Cardinal.lift.{w'} #ι ≤ Cardinal.lift.{w} #κ := by - let Φ := fun k : κ => (b.repr (v k)).support - have w₁ : #ι ≤ #(Set.range Φ) := by - apply Cardinal.le_range_of_union_finset_eq_top - exact union_support_maximal_linearIndependent_eq_range_basis b v i m - have w₂ : Cardinal.lift.{w'} #(Set.range Φ) ≤ Cardinal.lift.{w} #κ := Cardinal.mk_range_le_lift - exact (Cardinal.lift_le.mpr w₁).trans w₂ -#align infinite_basis_le_maximal_linear_independent' infinite_basis_le_maximal_linearIndependent' - --- (See `infinite_basis_le_maximal_linearIndependent'` for the more general version --- where the index types can live in different universes.) -/-- Over any ring `R`, if `b` is an infinite basis for a module `M`, -and `s` is a maximal linearly independent set, -then the cardinality of `b` is bounded by the cardinality of `s`. --/ -theorem infinite_basis_le_maximal_linearIndependent {ι : Type w} (b : Basis ι R M) [Infinite ι] - {κ : Type w} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : #ι ≤ #κ := - Cardinal.lift_le.mp (infinite_basis_le_maximal_linearIndependent' b v i m) -#align infinite_basis_le_maximal_linear_independent infinite_basis_le_maximal_linearIndependent - theorem CompleteLattice.Independent.subtype_ne_bot_le_rank [NoZeroSMulDivisors R M] {V : ι → Submodule R M} (hV : CompleteLattice.Independent V) : Cardinal.lift.{v} #{ i : ι // V i ≠ ⊥ } ≤ Cardinal.lift.{w} (Module.rank R M) := by diff --git a/Mathlib/LinearAlgebra/FiniteDimensional.lean b/Mathlib/LinearAlgebra/FiniteDimensional.lean index c7e7c1b0ce4ee..3851077c96242 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean @@ -235,11 +235,11 @@ theorem _root_.Submodule.eq_top_of_finrank_eq [FiniteDimensional K V] {S : Submo set b := Basis.extend this with b_eq -- porting note: `letI` now uses `this` so we need to give different names letI i1 : Fintype (this.extend _) := - (finite_of_linearIndependent (by simpa using b.linearIndependent)).fintype + (LinearIndependent.set_finite_of_isNoetherian (by simpa using b.linearIndependent)).fintype letI i2 : Fintype (((↑) : S → V) '' Basis.ofVectorSpaceIndex K S) := - (finite_of_linearIndependent this).fintype + (LinearIndependent.set_finite_of_isNoetherian this).fintype letI i3 : Fintype (Basis.ofVectorSpaceIndex K S) := - (finite_of_linearIndependent (by simpa using bS.linearIndependent)).fintype + (LinearIndependent.set_finite_of_isNoetherian (by simpa using bS.linearIndependent)).fintype have : (↑) '' Basis.ofVectorSpaceIndex K S = this.extend (Set.subset_univ _) := Set.eq_of_subset_of_card_le (this.subset_extend _) (by diff --git a/Mathlib/RingTheory/Noetherian.lean b/Mathlib/RingTheory/Noetherian.lean index 9cc5f70c24e04..610dba1027af7 100644 --- a/Mathlib/RingTheory/Noetherian.lean +++ b/Mathlib/RingTheory/Noetherian.lean @@ -385,28 +385,26 @@ lemma Submodule.finite_ne_bot_of_independent {ι : Type*} {N : ι → Submodule CompleteLattice.WellFounded.finite_ne_bot_of_independent (isNoetherian_iff_wellFounded.mp inferInstance) h -theorem finite_of_linearIndependent [Nontrivial R] {s : Set M} - (hs : LinearIndependent R ((↑) : s → M)) : s.Finite := by - refine' - by_contradiction fun hf => - (RelEmbedding.wellFounded_iff_no_descending_seq.1 (wellFounded_submodule_gt R M)).elim' _ - have f : ℕ ↪ s := Set.Infinite.natEmbedding s hf - have : ∀ n, (↑) ∘ f '' { m | m ≤ n } ⊆ s := by - rintro n x ⟨y, _, rfl⟩ - exact (f y).2 - let coe' : s → M := (↑) - have : ∀ a b : ℕ, a ≤ b ↔ - span R (coe' ∘ f '' { m | m ≤ a }) ≤ span R ((↑) ∘ f '' { m | m ≤ b }) := by - intro a b - rw [span_le_span_iff hs (this a) (this b), - Set.image_subset_image_iff (Subtype.coe_injective.comp f.injective), Set.subset_def] - exact ⟨fun hab x (hxa : x ≤ a) => le_trans hxa hab, fun hx => hx a (le_refl a)⟩ - exact - ⟨⟨fun n => span R (coe' ∘ f '' { m | m ≤ n }), fun x y => by - rw [le_antisymm_iff, (this x y).symm, (this y x).symm, ← le_antisymm_iff, imp_self] - trivial⟩, - by dsimp [GT.gt]; simp only [lt_iff_le_not_le, (this _ _).symm]; tauto⟩ -#align finite_of_linear_independent finite_of_linearIndependent +/-- A linearly-independent family of vectors in a module over a non-trivial ring must be finite if +the module is Noetherian. -/ +theorem LinearIndependent.finite_of_isNoetherian [Nontrivial R] {ι} {v : ι → M} + (hv : LinearIndependent R v) : Finite ι := by + have hwf := isNoetherian_iff_wellFounded.mp (by infer_instance : IsNoetherian R M) + refine' CompleteLattice.WellFounded.finite_of_independent hwf hv.independent_span_singleton + fun i contra => _ + apply hv.ne_zero i + have : v i ∈ R ∙ v i := Submodule.mem_span_singleton_self (v i) + rwa [contra, Submodule.mem_bot] at this +#align linear_independent.finite_of_is_noetherian LinearIndependent.finite_of_isNoetherian + +theorem LinearIndependent.set_finite_of_isNoetherian [Nontrivial R] {s : Set M} + (hi : LinearIndependent R ((↑) : s → M)) : s.Finite := + @Set.toFinite _ _ hi.finite_of_isNoetherian +#align linear_independent.set_finite_of_is_noetherian LinearIndependent.set_finite_of_isNoetherian + +@[deprecated] +alias finite_of_linearIndependent := LinearIndependent.set_finite_of_isNoetherian +#align finite_of_linear_independent LinearIndependent.set_finite_of_isNoetherian /-- If the first and final modules in a short exact sequence are Noetherian, then the middle module is also Noetherian. -/ From f656e606157a8c250da966907d97ba550d5cec8c Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Sat, 30 Dec 2023 03:42:52 +0000 Subject: [PATCH 279/353] chore: Move misplaced lemmas in `Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean`. (#9301) Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- .../LinearAlgebra/FreeModule/Finite/Rank.lean | 65 ----------------- Mathlib/RingTheory/Finiteness.lean | 72 +++++++++++++++++++ 2 files changed, 72 insertions(+), 65 deletions(-) diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean index 6cab2f64a5f63..92f9259fcb02e 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean @@ -433,23 +433,6 @@ theorem FiniteDimensional.finrank_zero_iff [Module.Finite R V] [NoZeroSMulDiviso (rank_zero_iff (R := R)) #align finite_dimensional.finrank_zero_iff FiniteDimensional.finrank_zero_iff -variable (R K) - -/-- The submodule generated by a finite set is `R`-finite. -/ -theorem Module.Finite.span_of_finite {A : Set V} (hA : Set.Finite A) : - Module.Finite R (Submodule.span R A) := - ⟨(Submodule.fg_top _).mpr ⟨hA.toFinset, hA.coe_toFinset.symm ▸ rfl⟩⟩ - -/-- The submodule generated by a single element is `R`-finite. -/ -instance Module.Finite.span_singleton (x : V) : Module.Finite R (R ∙ x) := - Module.Finite.span_of_finite R <| Set.finite_singleton _ - -/-- The submodule generated by a finset is `R`-finite. -/ -instance Module.Finite.span_finset (s : Finset V) : Module.Finite R (span R (s : Set V)) := - ⟨(Submodule.fg_top _).mpr ⟨s, rfl⟩⟩ - -variable {K R} - theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux [Module.Finite R V] [NoZeroSMulDivisors R V] {ι : Type w} {p : ι → Submodule R V} (hp : CompleteLattice.Independent p) : @@ -607,51 +590,3 @@ theorem Submodule.finrank_eq_zero [StrongRankCondition R] [NoZeroSMulDivisors R #align finrank_eq_zero Submodule.finrank_eq_zero end ZeroRank - -namespace Submodule - -open IsNoetherian FiniteDimensional - -variable [Ring R] [AddCommGroup V] [Module R V] - -theorem fg_iff_finite (s : Submodule R V) : s.FG ↔ Module.Finite R s := - (finite_def.trans (fg_top s)).symm - -/-- The sup of two fg submodules is finite. Also see `Submodule.FG.sup`. -/ -instance finite_sup (S₁ S₂ : Submodule R V) [h₁ : Module.Finite R S₁] - [h₂ : Module.Finite R S₂] : Module.Finite R (S₁ ⊔ S₂ : Submodule R V) := by - rw [finite_def] at * - exact (fg_top _).2 (((fg_top S₁).1 h₁).sup ((fg_top S₂).1 h₂)) - -/-- The submodule generated by a finite supremum of finite dimensional submodules is -finite-dimensional. - -Note that strictly this only needs `∀ i ∈ s, FiniteDimensional K (S i)`, but that doesn't -work well with typeclass search. -/ -instance finite_finset_sup {ι : Type*} (s : Finset ι) (S : ι → Submodule R V) - [∀ i, Module.Finite R (S i)] : Module.Finite R (s.sup S : Submodule R V) := by - refine' - @Finset.sup_induction _ _ _ _ s S (fun i => Module.Finite R ↑i) (Module.finite_bot R V) - _ fun i _ => by infer_instance - · intro S₁ hS₁ S₂ hS₂ - exact Submodule.finite_sup S₁ S₂ - -/-- The submodule generated by a supremum of finite dimensional submodules, indexed by a finite -sort is finite-dimensional. -/ -instance finite_iSup {ι : Sort*} [Finite ι] (S : ι → Submodule R V) - [∀ i, Module.Finite R (S i)] : Module.Finite R ↑(⨆ i, S i) := by - cases nonempty_fintype (PLift ι) - rw [← iSup_plift_down, ← Finset.sup_univ_eq_iSup] - exact Submodule.finite_finset_sup _ _ - -end Submodule - -section - -variable [Ring R] [AddCommGroup V] [Module R V] - -instance Module.Finite.finsupp {ι : Type*} [_root_.Finite ι] [Module.Finite R V] : - Module.Finite R (ι →₀ V) := - Module.Finite.equiv (Finsupp.linearEquivFunOnFinite R V ι).symm - -end diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index 7c5b7f10269ed..cc97605ed93a3 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -647,6 +647,33 @@ theorem equiv_iff (e : M ≃ₗ[R] N) : Finite R M ↔ Finite R N := instance ulift [Finite R M] : Finite R (ULift M) := equiv ULift.moduleEquiv.symm +theorem iff_fg {N : Submodule R M} : Module.Finite R N ↔ N.FG := Module.finite_def.trans (fg_top _) + +variable (R M) + +instance bot : Module.Finite R (⊥ : Submodule R M) := iff_fg.mpr fg_bot + +instance top [Finite R M] : Module.Finite R (⊤ : Submodule R M) := iff_fg.mpr out + +variable {R M} + +variable (R) + +/-- The submodule generated by a finite set is `R`-finite. -/ +theorem span_of_finite {A : Set M} (hA : Set.Finite A) : + Module.Finite R (Submodule.span R A) := + ⟨(Submodule.fg_top _).mpr ⟨hA.toFinset, hA.coe_toFinset.symm ▸ rfl⟩⟩ + +/-- The submodule generated by a single element is `R`-finite. -/ +instance span_singleton (x : M) : Module.Finite R (R ∙ x) := + Module.Finite.span_of_finite R <| Set.finite_singleton _ + +/-- The submodule generated by a finset is `R`-finite. -/ +instance span_finset (s : Finset M) : Module.Finite R (span R (s : Set M)) := + ⟨(Submodule.fg_top _).mpr ⟨s, rfl⟩⟩ + +variable {R} + section Algebra theorem trans {R : Type*} (A M : Type*) [CommSemiring R] [Semiring A] [Algebra R A] @@ -713,6 +740,51 @@ instance Module.Finite.tensorProduct [CommSemiring R] [AddCommMonoid M] [Module end ModuleAndAlgebra +namespace Submodule + +open Module + +variable {R V} [Ring R] [AddCommGroup V] [Module R V] + +/-- The sup of two fg submodules is finite. Also see `Submodule.FG.sup`. -/ +instance finite_sup (S₁ S₂ : Submodule R V) [h₁ : Module.Finite R S₁] + [h₂ : Module.Finite R S₂] : Module.Finite R (S₁ ⊔ S₂ : Submodule R V) := by + rw [finite_def] at * + exact (fg_top _).2 (((fg_top S₁).1 h₁).sup ((fg_top S₂).1 h₂)) + +/-- The submodule generated by a finite supremum of finite dimensional submodules is +finite-dimensional. + +Note that strictly this only needs `∀ i ∈ s, FiniteDimensional K (S i)`, but that doesn't +work well with typeclass search. -/ +instance finite_finset_sup {ι : Type*} (s : Finset ι) (S : ι → Submodule R V) + [∀ i, Module.Finite R (S i)] : Module.Finite R (s.sup S : Submodule R V) := by + refine' + @Finset.sup_induction _ _ _ _ s S (fun i => Module.Finite R ↑i) (Module.Finite.bot R V) + _ fun i _ => by infer_instance + · intro S₁ hS₁ S₂ hS₂ + exact Submodule.finite_sup S₁ S₂ + +/-- The submodule generated by a supremum of finite dimensional submodules, indexed by a finite +sort is finite-dimensional. -/ +instance finite_iSup {ι : Sort*} [Finite ι] (S : ι → Submodule R V) + [∀ i, Module.Finite R (S i)] : Module.Finite R ↑(⨆ i, S i) := by + cases nonempty_fintype (PLift ι) + rw [← iSup_plift_down, ← Finset.sup_univ_eq_iSup] + exact Submodule.finite_finset_sup _ _ + +end Submodule + +section + +variable {R V} [Ring R] [AddCommGroup V] [Module R V] + +instance Module.Finite.finsupp {ι : Type*} [_root_.Finite ι] [Module.Finite R V] : + Module.Finite R (ι →₀ V) := + Module.Finite.equiv (Finsupp.linearEquivFunOnFinite R V ι).symm + +end + namespace RingHom variable {A B C : Type*} [CommRing A] [CommRing B] [CommRing C] From d54b614b541ee33bc803c912a9f1a4098c3291c6 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 30 Dec 2023 05:21:35 +0000 Subject: [PATCH 280/353] feat(*/Pointwise): generalize some lemmas to `SMulZeroClass` (#9243) --- Mathlib/Data/Finset/Pointwise.lean | 41 ++++++++++++++++----------- Mathlib/Data/Set/Pointwise/SMul.lean | 42 ++++++++++++++++------------ 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/Mathlib/Data/Finset/Pointwise.lean b/Mathlib/Data/Finset/Pointwise.lean index 7c3ca6d6c5bba..dd61ba78f05a5 100644 --- a/Mathlib/Data/Finset/Pointwise.lean +++ b/Mathlib/Data/Finset/Pointwise.lean @@ -57,7 +57,7 @@ pointwise subtraction open Function MulOpposite -open BigOperators Pointwise +open scoped BigOperators Pointwise variable {F α β γ : Type*} @@ -2083,7 +2083,31 @@ lemma inv_op_smul_finset_distrib (a : α) (s : Finset α) : (op a • s)⁻¹ = end Group +section SMulZeroClass + +variable [Zero β] [SMulZeroClass α β] [DecidableEq β] {s : Finset α} {t : Finset β} {a : α} + +theorem smul_zero_subset (s : Finset α) : s • (0 : Finset β) ⊆ 0 := by simp [subset_iff, mem_smul] +#align finset.smul_zero_subset Finset.smul_zero_subset + +theorem Nonempty.smul_zero (hs : s.Nonempty) : s • (0 : Finset β) = 0 := + s.smul_zero_subset.antisymm <| by simpa [mem_smul] using hs +#align finset.nonempty.smul_zero Finset.Nonempty.smul_zero + +theorem zero_mem_smul_finset (h : (0 : β) ∈ t) : (0 : β) ∈ a • t := + mem_smul_finset.2 ⟨0, h, smul_zero _⟩ +#align finset.zero_mem_smul_finset Finset.zero_mem_smul_finset + +variable [Zero α] [NoZeroSMulDivisors α β] + +theorem zero_mem_smul_finset_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by + rw [← mem_coe, coe_smul_finset, Set.zero_mem_smul_set_iff ha, mem_coe] +#align finset.zero_mem_smul_finset_iff Finset.zero_mem_smul_finset_iff + +end SMulZeroClass + section SMulWithZero + variable [Zero α] [Zero β] [SMulWithZero α β] [DecidableEq β] {s : Finset α} {t : Finset β} /-! @@ -2091,16 +2115,9 @@ Note that we have neither `SMulWithZero α (Finset β)` nor `SMulWithZero (Finse because `0 * ∅ ≠ 0`. -/ -lemma smul_zero_subset (s : Finset α) : s • (0 : Finset β) ⊆ 0 := by simp [subset_iff, mem_smul] -#align finset.smul_zero_subset Finset.smul_zero_subset - lemma zero_smul_subset (t : Finset β) : (0 : Finset α) • t ⊆ 0 := by simp [subset_iff, mem_smul] #align finset.zero_smul_subset Finset.zero_smul_subset -lemma Nonempty.smul_zero (hs : s.Nonempty) : s • (0 : Finset β) = 0 := - s.smul_zero_subset.antisymm $ by simpa [mem_smul] using hs -#align finset.nonempty.smul_zero Finset.Nonempty.smul_zero - lemma Nonempty.zero_smul (ht : t.Nonempty) : (0 : Finset α) • t = 0 := t.zero_smul_subset.antisymm $ by simpa [mem_smul] using ht #align finset.nonempty.zero_smul Finset.Nonempty.zero_smul @@ -2114,10 +2131,6 @@ lemma zero_smul_finset_subset (s : Finset β) : (0 : α) • s ⊆ 0 := image_subset_iff.2 fun x _ ↦ mem_zero.2 $ zero_smul α x #align finset.zero_smul_finset_subset Finset.zero_smul_finset_subset -lemma zero_mem_smul_finset {t : Finset β} {a : α} (h : (0 : β) ∈ t) : (0 : β) ∈ a • t := - mem_smul_finset.2 ⟨0, h, smul_zero _⟩ -#align finset.zero_mem_smul_finset Finset.zero_mem_smul_finset - variable [NoZeroSMulDivisors α β] {a : α} lemma zero_mem_smul_iff : @@ -2125,10 +2138,6 @@ lemma zero_mem_smul_iff : rw [← mem_coe, coe_smul, Set.zero_mem_smul_iff]; rfl #align finset.zero_mem_smul_iff Finset.zero_mem_smul_iff -lemma zero_mem_smul_finset_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by - rw [← mem_coe, coe_smul_finset, Set.zero_mem_smul_set_iff ha, mem_coe] -#align finset.zero_mem_smul_finset_iff Finset.zero_mem_smul_finset_iff - end SMulWithZero section GroupWithZero diff --git a/Mathlib/Data/Set/Pointwise/SMul.lean b/Mathlib/Data/Set/Pointwise/SMul.lean index 53ad2ad7ce78e..5d80f6acff855 100644 --- a/Mathlib/Data/Set/Pointwise/SMul.lean +++ b/Mathlib/Data/Set/Pointwise/SMul.lean @@ -789,6 +789,30 @@ theorem op_smul_set_smul_eq_smul_smul_set (a : α) (s : Set β) (t : Set γ) end SMul +section SMulZeroClass + +variable [Zero β] [SMulZeroClass α β] {s : Set α} {t : Set β} {a : α} + +theorem smul_zero_subset (s : Set α) : s • (0 : Set β) ⊆ 0 := by simp [subset_def, mem_smul] +#align set.smul_zero_subset Set.smul_zero_subset + +theorem Nonempty.smul_zero (hs : s.Nonempty) : s • (0 : Set β) = 0 := + s.smul_zero_subset.antisymm <| by simpa [mem_smul] using hs +#align set.nonempty.smul_zero Set.Nonempty.smul_zero + +theorem zero_mem_smul_set (h : (0 : β) ∈ t) : (0 : β) ∈ a • t := ⟨0, h, smul_zero _⟩ +#align set.zero_mem_smul_set Set.zero_mem_smul_set + +variable [Zero α] [NoZeroSMulDivisors α β] + +theorem zero_mem_smul_set_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by + refine' ⟨_, zero_mem_smul_set⟩ + rintro ⟨b, hb, h⟩ + rwa [(eq_zero_or_eq_zero_of_smul_eq_zero h).resolve_left ha] at hb +#align set.zero_mem_smul_set_iff Set.zero_mem_smul_set_iff + +end SMulZeroClass + section SMulWithZero variable [Zero α] [Zero β] [SMulWithZero α β] {s : Set α} {t : Set β} @@ -798,17 +822,9 @@ Note that we have neither `SMulWithZero α (Set β)` nor `SMulWithZero (Set α) because `0 * ∅ ≠ 0`. -/ - -theorem smul_zero_subset (s : Set α) : s • (0 : Set β) ⊆ 0 := by simp [subset_def, mem_smul] -#align set.smul_zero_subset Set.smul_zero_subset - theorem zero_smul_subset (t : Set β) : (0 : Set α) • t ⊆ 0 := by simp [subset_def, mem_smul] #align set.zero_smul_subset Set.zero_smul_subset -theorem Nonempty.smul_zero (hs : s.Nonempty) : s • (0 : Set β) = 0 := - s.smul_zero_subset.antisymm <| by simpa [mem_smul] using hs -#align set.nonempty.smul_zero Set.Nonempty.smul_zero - theorem Nonempty.zero_smul (ht : t.Nonempty) : (0 : Set α) • t = 0 := t.zero_smul_subset.antisymm <| by simpa [mem_smul] using ht #align set.nonempty.zero_smul Set.Nonempty.zero_smul @@ -826,10 +842,6 @@ theorem subsingleton_zero_smul_set (s : Set β) : ((0 : α) • s).Subsingleton subsingleton_singleton.anti <| zero_smul_set_subset s #align set.subsingleton_zero_smul_set Set.subsingleton_zero_smul_set -theorem zero_mem_smul_set {t : Set β} {a : α} (h : (0 : β) ∈ t) : (0 : β) ∈ a • t := - ⟨0, h, smul_zero _⟩ -#align set.zero_mem_smul_set Set.zero_mem_smul_set - variable [NoZeroSMulDivisors α β] {a : α} theorem zero_mem_smul_iff : @@ -844,12 +856,6 @@ theorem zero_mem_smul_iff : · exact ⟨a, ha, 0, ht, smul_zero _⟩ #align set.zero_mem_smul_iff Set.zero_mem_smul_iff -theorem zero_mem_smul_set_iff (ha : a ≠ 0) : (0 : β) ∈ a • t ↔ (0 : β) ∈ t := by - refine' ⟨_, zero_mem_smul_set⟩ - rintro ⟨b, hb, h⟩ - rwa [(eq_zero_or_eq_zero_of_smul_eq_zero h).resolve_left ha] at hb -#align set.zero_mem_smul_set_iff Set.zero_mem_smul_set_iff - end SMulWithZero section Semigroup From 3286beabe5f3da3a4d214f0f63b554fec8c40750 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 30 Dec 2023 06:21:32 +0000 Subject: [PATCH 281/353] chore(Topology/CompactOpen): rename type variables (#9328) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use `X`, `Y`, `Z` instead of `α`, `β`, `γ` for topological spaces. --- Mathlib/Topology/CompactOpen.lean | 264 +++++++++++++++--------------- 1 file changed, 132 insertions(+), 132 deletions(-) diff --git a/Mathlib/Topology/CompactOpen.lean b/Mathlib/Topology/CompactOpen.lean index d044be2f36e68..0648669b5504a 100644 --- a/Mathlib/Topology/CompactOpen.lean +++ b/Mathlib/Topology/CompactOpen.lean @@ -15,15 +15,15 @@ topological spaces. ## Main definitions -* `CompactOpen` is the compact-open topology on `C(α, β)`. It is declared as an instance. -* `ContinuousMap.coev` is the coevaluation map `β → C(α, β × α)`. It is always continuous. -* `ContinuousMap.curry` is the currying map `C(α × β, γ) → C(α, C(β, γ))`. This map always exists - and it is continuous as long as `α × β` is locally compact. -* `ContinuousMap.uncurry` is the uncurrying map `C(α, C(β, γ)) → C(α × β, γ)`. For this map to - exist, we need `β` to be locally compact. If `α` is also locally compact, then this map is +* `CompactOpen` is the compact-open topology on `C(X, Y)`. It is declared as an instance. +* `ContinuousMap.coev` is the coevaluation map `Y → C(X, Y × X)`. It is always continuous. +* `ContinuousMap.curry` is the currying map `C(X × Y, Z) → C(X, C(Y, Z))`. This map always exists + and it is continuous as long as `X × Y` is locally compact. +* `ContinuousMap.uncurry` is the uncurrying map `C(X, C(Y, Z)) → C(X × Y, Z)`. For this map to + exist, we need `Y` to be locally compact. If `X` is also locally compact, then this map is continuous. * `Homeomorph.curry` combines the currying and uncurrying operations into a homeomorphism - `C(α × β, γ) ≃ₜ C(α, C(β, γ))`. This homeomorphism exists if `α` and `β` are locally compact. + `C(X × Y, Z) ≃ₜ C(X, C(Y, Z))`. This homeomorphism exists if `X` and `Y` are locally compact. ## Tags @@ -39,121 +39,121 @@ namespace ContinuousMap section CompactOpen -variable {α : Type*} {β : Type*} {γ : Type*} +variable {X : Type*} {Y : Type*} {Z : Type*} -variable [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] +variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] /-- A generating set for the compact-open topology (when `s` is compact and `u` is open). -/ -def CompactOpen.gen (s : Set α) (u : Set β) : Set C(α, β) := +def CompactOpen.gen (s : Set X) (u : Set Y) : Set C(X, Y) := { f | f '' s ⊆ u } #align continuous_map.compact_open.gen ContinuousMap.CompactOpen.gen @[simp] -theorem gen_empty (u : Set β) : CompactOpen.gen (∅ : Set α) u = Set.univ := +theorem gen_empty (u : Set Y) : CompactOpen.gen (∅ : Set X) u = Set.univ := Set.ext fun f => iff_true_intro ((congr_arg (· ⊆ u) (image_empty f)).mpr u.empty_subset) #align continuous_map.gen_empty ContinuousMap.gen_empty @[simp] -theorem gen_univ (s : Set α) : CompactOpen.gen s (Set.univ : Set β) = Set.univ := +theorem gen_univ (s : Set X) : CompactOpen.gen s (Set.univ : Set Y) = Set.univ := Set.ext fun f => iff_true_intro (f '' s).subset_univ #align continuous_map.gen_univ ContinuousMap.gen_univ @[simp] -theorem gen_inter (s : Set α) (u v : Set β) : +theorem gen_inter (s : Set X) (u v : Set Y) : CompactOpen.gen s (u ∩ v) = CompactOpen.gen s u ∩ CompactOpen.gen s v := Set.ext fun _ => subset_inter_iff #align continuous_map.gen_inter ContinuousMap.gen_inter @[simp] -theorem gen_union (s t : Set α) (u : Set β) : +theorem gen_union (s t : Set X) (u : Set Y) : CompactOpen.gen (s ∪ t) u = CompactOpen.gen s u ∩ CompactOpen.gen t u := Set.ext fun f => (iff_of_eq (congr_arg (· ⊆ u) (image_union f s t))).trans union_subset_iff #align continuous_map.gen_union ContinuousMap.gen_union -theorem gen_empty_right {s : Set α} (h : s.Nonempty) : CompactOpen.gen s (∅ : Set β) = ∅ := +theorem gen_empty_right {s : Set X} (h : s.Nonempty) : CompactOpen.gen s (∅ : Set Y) = ∅ := eq_empty_of_forall_not_mem fun _ => (h.image _).not_subset_empty #align continuous_map.gen_empty_right ContinuousMap.gen_empty_right --- The compact-open topology on the space of continuous maps α → β. -instance compactOpen : TopologicalSpace C(α, β) := +-- The compact-open topology on the space of continuous maps X → Y. +instance compactOpen : TopologicalSpace C(X, Y) := TopologicalSpace.generateFrom - { m | ∃ (s : Set α) (_ : IsCompact s) (u : Set β) (_ : IsOpen u), m = CompactOpen.gen s u } + { m | ∃ (s : Set X) (_ : IsCompact s) (u : Set Y) (_ : IsOpen u), m = CompactOpen.gen s u } #align continuous_map.compact_open ContinuousMap.compactOpen /-- Definition of `ContinuousMap.compactOpen` in terms of `Set.image2`. -/ -theorem compactOpen_eq : @compactOpen α β _ _ = +theorem compactOpen_eq : @compactOpen X Y _ _ = .generateFrom (Set.image2 CompactOpen.gen {s | IsCompact s} {t | IsOpen t}) := congr_arg TopologicalSpace.generateFrom <| Set.ext fun _ ↦ by simp [eq_comm] -protected theorem isOpen_gen {s : Set α} (hs : IsCompact s) {u : Set β} (hu : IsOpen u) : +protected theorem isOpen_gen {s : Set X} (hs : IsCompact s) {u : Set Y} (hu : IsOpen u) : IsOpen (CompactOpen.gen s u) := TopologicalSpace.GenerateOpen.basic _ (by dsimp [mem_setOf_eq]; tauto) #align continuous_map.is_open_gen ContinuousMap.isOpen_gen -lemma isOpen_setOf_mapsTo {K : Set α} (hK : IsCompact K) {U : Set β} (hU : IsOpen U) : - IsOpen {f : C(α, β) | MapsTo f K U} := by +lemma isOpen_setOf_mapsTo {K : Set X} (hK : IsCompact K) {U : Set Y} (hU : IsOpen U) : + IsOpen {f : C(X, Y) | MapsTo f K U} := by simpa only [mapsTo'] using ContinuousMap.isOpen_gen hK hU -lemma eventually_mapsTo {f : C(α, β)} {K U} (hK : IsCompact K) (hU : IsOpen U) (h : MapsTo f K U) : - ∀ᶠ g : C(α, β) in 𝓝 f, MapsTo g K U := +lemma eventually_mapsTo {f : C(X, Y)} {K U} (hK : IsCompact K) (hU : IsOpen U) (h : MapsTo f K U) : + ∀ᶠ g : C(X, Y) in 𝓝 f, MapsTo g K U := (isOpen_setOf_mapsTo hK hU).mem_nhds h -lemma tendsto_nhds_compactOpen {α : Type*} {l : Filter α} {f : α → C(β, γ)} {g : C(β, γ)} : +lemma tendsto_nhds_compactOpen {α : Type*} {l : Filter α} {f : α → C(Y, Z)} {g : C(Y, Z)} : Tendsto f l (𝓝 g) ↔ ∀ K, IsCompact K → ∀ U, IsOpen U → MapsTo g K U → ∀ᶠ a in l, MapsTo (f a) K U := by simp_rw [compactOpen_eq, tendsto_nhds_generateFrom_iff, forall_image2_iff, mapsTo']; rfl -lemma continuous_compactOpen {f : α → C(β, γ)} : +lemma continuous_compactOpen {f : X → C(Y, Z)} : Continuous f ↔ ∀ K, IsCompact K → ∀ U, IsOpen U → IsOpen {x | MapsTo (f x) K U} := by simp_rw [compactOpen_eq, continuous_generateFrom_iff, forall_image2_iff, mapsTo']; rfl section Functorial -variable (g : C(β, γ)) +variable (g : C(Y, Z)) -private theorem preimage_gen {s : Set α} {u : Set γ} : +private theorem preimage_gen {s : Set X} {u : Set Z} : ContinuousMap.comp g ⁻¹' CompactOpen.gen s u = CompactOpen.gen s (g ⁻¹' u) := by ext ⟨f, _⟩ change g ∘ f '' s ⊆ u ↔ f '' s ⊆ g ⁻¹' u rw [image_comp, image_subset_iff] -/-- C(α, -) is a functor. -/ -theorem continuous_comp : Continuous (ContinuousMap.comp g : C(α, β) → C(α, γ)) := +/-- C(X, -) is a functor. -/ +theorem continuous_comp : Continuous (ContinuousMap.comp g : C(X, Y) → C(X, Z)) := continuous_generateFrom_iff.2 fun m ⟨s, hs, u, hu, hm⟩ => by rw [hm, preimage_gen g]; exact ContinuousMap.isOpen_gen hs (hu.preimage g.2) #align continuous_map.continuous_comp ContinuousMap.continuous_comp -/-- If `g : C(β, γ)` is a topology inducing map, then the composition -`ContinuousMap.comp g : C(α, β) → C(α, γ)` is a topology inducing map too. -/ -theorem inducing_comp (hg : Inducing g) : Inducing (g.comp : C(α, β) → C(α, γ)) where +/-- If `g : C(Y, Z)` is a topology inducing map, then the composition +`ContinuousMap.comp g : C(X, Y) → C(X, Z)` is a topology inducing map too. -/ +theorem inducing_comp (hg : Inducing g) : Inducing (g.comp : C(X, Y) → C(X, Z)) where induced := by simp only [compactOpen_eq, induced_generateFrom_eq, image_image2, preimage_gen, hg.setOf_isOpen, image2_image_right] -/-- If `g : C(β, γ)` is a topological embedding, then the composition -`ContinuousMap.comp g : C(α, β) → C(α, γ)` is an embedding too. -/ -theorem embedding_comp (hg : Embedding g) : Embedding (g.comp : C(α, β) → C(α, γ)) := +/-- If `g : C(Y, Z)` is a topological embedding, then the composition +`ContinuousMap.comp g : C(X, Y) → C(X, Z)` is an embedding too. -/ +theorem embedding_comp (hg : Embedding g) : Embedding (g.comp : C(X, Y) → C(X, Z)) := ⟨inducing_comp g hg.1, fun _ _ ↦ (cancel_left hg.2).1⟩ -variable (f : C(α, β)) +variable (f : C(X, Y)) -private theorem image_gen {s : Set α} (_ : IsCompact s) {u : Set γ} (_ : IsOpen u) : - (fun g : C(β, γ) => g.comp f) ⁻¹' CompactOpen.gen s u = CompactOpen.gen (f '' s) u := by +private theorem image_gen {s : Set X} (_ : IsCompact s) {u : Set Z} (_ : IsOpen u) : + (fun g : C(Y, Z) => g.comp f) ⁻¹' CompactOpen.gen s u = CompactOpen.gen (f '' s) u := by ext ⟨g, _⟩ change g ∘ f '' s ⊆ u ↔ g '' (f '' s) ⊆ u rw [Set.image_comp] -/-- C(-, γ) is a functor. -/ -theorem continuous_comp_left : Continuous (fun g => g.comp f : C(β, γ) → C(α, γ)) := +/-- C(-, Z) is a functor. -/ +theorem continuous_comp_left : Continuous (fun g => g.comp f : C(Y, Z) → C(X, Z)) := continuous_generateFrom_iff.2 fun m ⟨s, hs, u, hu, hm⟩ => by rw [hm, image_gen f hs hu] exact ContinuousMap.isOpen_gen (hs.image f.2) hu #align continuous_map.continuous_comp_left ContinuousMap.continuous_comp_left -/-- Composition is a continuous map from `C(α, β) × C(β, γ)` to `C(α, γ)`, provided that `β` is +/-- Composition is a continuous map from `C(X, Y) × C(Y, Z)` to `C(X, Z)`, provided that `Y` is locally compact. This is Prop. 9 of Chap. X, §3, №. 4 of Bourbaki's *Topologie Générale*. -/ -theorem continuous_comp' [LocallyCompactPair β γ] : - Continuous fun x : C(α, β) × C(β, γ) => x.2.comp x.1 := by +theorem continuous_comp' [LocallyCompactPair Y Z] : + Continuous fun x : C(X, Y) × C(Y, Z) => x.2.comp x.1 := by simp_rw [continuous_iff_continuousAt, ContinuousAt, tendsto_nhds_compactOpen] intro ⟨f, g⟩ K hK U hU (hKU : MapsTo (g ∘ f) K U) obtain ⟨L, hKL, hLc, hLU⟩ : ∃ L ∈ 𝓝ˢ (f '' K), IsCompact L ∧ MapsTo g L U := @@ -165,8 +165,8 @@ theorem continuous_comp' [LocallyCompactPair β γ] : hg'.comp <| hf'.mono_right interior_subset #align continuous_map.continuous_comp' ContinuousMap.continuous_comp' -theorem continuous.comp' {X : Type*} [TopologicalSpace X] [LocallyCompactPair β γ] {f : X → C(α, β)} - {g : X → C(β, γ)} (hf : Continuous f) (hg : Continuous g) : +theorem continuous.comp' {X : Type*} [TopologicalSpace X] [LocallyCompactPair Y Z] {f : X → C(X, Y)} + {g : X → C(Y, Z)} (hf : Continuous f) (hg : Continuous g) : Continuous fun x => (g x).comp (f x) := continuous_comp'.comp (hf.prod_mk hg : Continuous fun x => (f x, g x)) #align continuous_map.continuous.comp' ContinuousMap.continuous.comp' @@ -175,10 +175,10 @@ end Functorial section Ev -/-- The evaluation map `C(α, β) × α → β` is continuous -if `α, β` is a locally compact pair of spaces. -/ +/-- The evaluation map `C(X, Y) × X → Y` is continuous +if `X, Y` is a locally compact pair of spaces. -/ @[continuity] -theorem continuous_eval [LocallyCompactPair α β] : Continuous fun p : C(α, β) × α => p.1 p.2 := by +theorem continuous_eval [LocallyCompactPair X Y] : Continuous fun p : C(X, Y) × X => p.1 p.2 := by simp_rw [continuous_iff_continuousAt, ContinuousAt, (nhds_basis_opens _).tendsto_right_iff] rintro ⟨f, x⟩ U ⟨hx : f x ∈ U, hU : IsOpen U⟩ rcases exists_mem_nhds_isCompact_mapsTo f.continuous (hU.mem_nhds hx) with ⟨K, hxK, hK, hKU⟩ @@ -188,51 +188,51 @@ theorem continuous_eval [LocallyCompactPair α β] : Continuous fun p : C(α, β @[deprecated] alias continuous_eval' := continuous_eval -/-- Evaluation of a continuous map `f` at a point `a` is continuous in `f`. +/-- Evaluation of a continuous map `f` at a point `x` is continuous in `f`. Porting note: merged `continuous_eval_const` with `continuous_eval_const'` removing unneeded assumptions. -/ @[continuity] -theorem continuous_eval_const (a : α) : - Continuous fun f : C(α, β) => f a := by +theorem continuous_eval_const (x : X) : + Continuous fun f : C(X, Y) => f x := by refine continuous_def.2 fun U hU ↦ ?_ - convert ContinuousMap.isOpen_gen (isCompact_singleton (x := a)) hU using 1 + convert ContinuousMap.isOpen_gen (isCompact_singleton (x := x)) hU using 1 ext; simp [CompactOpen.gen] #align continuous_map.continuous_eval_const' ContinuousMap.continuous_eval_const #align continuous_map.continuous_eval_const ContinuousMap.continuous_eval_const -/-- Coercion from `C(α, β)` with compact-open topology to `α → β` with pointwise convergence +/-- Coercion from `C(X, Y)` with compact-open topology to `X → Y` with pointwise convergence topology is a continuous map. Porting note: merged `continuous_coe` with `continuous_coe'` removing unneeded assumptions. -/ -theorem continuous_coe : Continuous ((⇑) : C(α, β) → (α → β)) := +theorem continuous_coe : Continuous ((⇑) : C(X, Y) → (X → Y)) := continuous_pi continuous_eval_const #align continuous_map.continuous_coe' ContinuousMap.continuous_coe #align continuous_map.continuous_coe ContinuousMap.continuous_coe -lemma isClosed_setOf_mapsTo {t : Set β} (ht : IsClosed t) (s : Set α) : - IsClosed {f : C(α, β) | MapsTo f s t} := +lemma isClosed_setOf_mapsTo {t : Set Y} (ht : IsClosed t) (s : Set X) : + IsClosed {f : C(X, Y) | MapsTo f s t} := ht.setOf_mapsTo fun _ _ ↦ continuous_eval_const _ -lemma isClopen_setOf_mapsTo {K : Set α} (hK : IsCompact K) {U : Set β} (hU : IsClopen U) : - IsClopen {f : C(α, β) | MapsTo f K U} := +lemma isClopen_setOf_mapsTo {K : Set X} (hK : IsCompact K) {U : Set Y} (hU : IsClopen U) : + IsClopen {f : C(X, Y) | MapsTo f K U} := ⟨isOpen_setOf_mapsTo hK hU.isOpen, isClosed_setOf_mapsTo hU.isClosed K⟩ -instance [T0Space β] : T0Space C(α, β) := +instance [T0Space Y] : T0Space C(X, Y) := t0Space_of_injective_of_continuous FunLike.coe_injective continuous_coe -instance [T1Space β] : T1Space C(α, β) := +instance [T1Space Y] : T1Space C(X, Y) := t1Space_of_injective_of_continuous FunLike.coe_injective continuous_coe -instance [T2Space β] : T2Space C(α, β) := +instance [T2Space Y] : T2Space C(X, Y) := .of_injective_continuous FunLike.coe_injective continuous_coe end Ev section InfInduced -theorem compactOpen_le_induced (s : Set α) : - (ContinuousMap.compactOpen : TopologicalSpace C(α, β)) ≤ +theorem compactOpen_le_induced (s : Set X) : + (ContinuousMap.compactOpen : TopologicalSpace C(X, Y)) ≤ TopologicalSpace.induced (ContinuousMap.restrict s) ContinuousMap.compactOpen := by simp only [induced_generateFrom_eq, ContinuousMap.compactOpen] apply TopologicalSpace.generateFrom_anti @@ -240,15 +240,15 @@ theorem compactOpen_le_induced (s : Set α) : refine' ⟨(↑) '' c, hc.image continuous_subtype_val, u, hu, _⟩ ext f simp only [CompactOpen.gen, mem_setOf_eq, mem_preimage, ContinuousMap.coe_restrict] - rw [image_comp f ((↑) : s → α)] + rw [image_comp f ((↑) : s → X)] #align continuous_map.compact_open_le_induced ContinuousMap.compactOpen_le_induced -/-- The compact-open topology on `C(α, β)` is equal to the infimum of the compact-open topologies -on `C(s, β)` for `s` a compact subset of `α`. The key point of the proof is that the union of the -compact subsets of `α` is equal to the union of compact subsets of the compact subsets of `α`. -/ +/-- The compact-open topology on `C(X, Y)` is equal to the infimum of the compact-open topologies +on `C(s, Y)` for `s` a compact subset of `X`. The key point of the proof is that the union of the +compact subsets of `X` is equal to the union of compact subsets of the compact subsets of `X`. -/ theorem compactOpen_eq_sInf_induced : - (ContinuousMap.compactOpen : TopologicalSpace C(α, β)) = - ⨅ (s : Set α) (_ : IsCompact s), + (ContinuousMap.compactOpen : TopologicalSpace C(X, Y)) = + ⨅ (s : Set X) (_ : IsCompact s), TopologicalSpace.induced (ContinuousMap.restrict s) ContinuousMap.compactOpen := by refine' le_antisymm _ _ · refine' le_iInf₂ _ @@ -260,42 +260,42 @@ theorem compactOpen_eq_sInf_induced : refine' ⟨s, hs, _, ⟨univ, isCompact_iff_isCompact_univ.mp hs, u, hu, rfl⟩, _⟩ ext f simp only [CompactOpen.gen, mem_setOf_eq, mem_preimage, ContinuousMap.coe_restrict] - rw [image_comp f ((↑) : s → α)] + rw [image_comp f ((↑) : s → X)] simp #align continuous_map.compact_open_eq_Inf_induced ContinuousMap.compactOpen_eq_sInf_induced -/-- For any subset `s` of `α`, the restriction of continuous functions to `s` is continuous as a -function from `C(α, β)` to `C(s, β)` with their respective compact-open topologies. -/ -theorem continuous_restrict (s : Set α) : Continuous fun F : C(α, β) => F.restrict s := by +/-- For any subset `s` of `X`, the restriction of continuous functions to `s` is continuous as a +function from `C(X, Y)` to `C(s, Y)` with their respective compact-open topologies. -/ +theorem continuous_restrict (s : Set X) : Continuous fun F : C(X, Y) => F.restrict s := by rw [continuous_iff_le_induced] exact compactOpen_le_induced s #align continuous_map.continuous_restrict ContinuousMap.continuous_restrict -theorem nhds_compactOpen_eq_sInf_nhds_induced (f : C(α, β)) : +theorem nhds_compactOpen_eq_sInf_nhds_induced (f : C(X, Y)) : 𝓝 f = ⨅ (s) (hs : IsCompact s), (𝓝 (f.restrict s)).comap (ContinuousMap.restrict s) := by rw [compactOpen_eq_sInf_induced] simp [nhds_iInf, nhds_induced] #align continuous_map.nhds_compact_open_eq_Inf_nhds_induced ContinuousMap.nhds_compactOpen_eq_sInf_nhds_induced -theorem tendsto_compactOpen_restrict {ι : Type*} {l : Filter ι} {F : ι → C(α, β)} {f : C(α, β)} - (hFf : Filter.Tendsto F l (𝓝 f)) (s : Set α) : +theorem tendsto_compactOpen_restrict {ι : Type*} {l : Filter ι} {F : ι → C(X, Y)} {f : C(X, Y)} + (hFf : Filter.Tendsto F l (𝓝 f)) (s : Set X) : Filter.Tendsto (fun i => (F i).restrict s) l (𝓝 (f.restrict s)) := (continuous_restrict s).continuousAt.tendsto.comp hFf #align continuous_map.tendsto_compact_open_restrict ContinuousMap.tendsto_compactOpen_restrict -theorem tendsto_compactOpen_iff_forall {ι : Type*} {l : Filter ι} (F : ι → C(α, β)) (f : C(α, β)) : +theorem tendsto_compactOpen_iff_forall {ι : Type*} {l : Filter ι} (F : ι → C(X, Y)) (f : C(X, Y)) : Filter.Tendsto F l (𝓝 f) ↔ ∀ (s) (hs : IsCompact s), Filter.Tendsto (fun i => (F i).restrict s) l (𝓝 (f.restrict s)) := by rw [compactOpen_eq_sInf_induced] simp [nhds_iInf, nhds_induced, Filter.tendsto_comap_iff, Function.comp] #align continuous_map.tendsto_compact_open_iff_forall ContinuousMap.tendsto_compactOpen_iff_forall -/-- A family `F` of functions in `C(α, β)` converges in the compact-open topology, if and only if -it converges in the compact-open topology on each compact subset of `α`. -/ -theorem exists_tendsto_compactOpen_iff_forall [WeaklyLocallyCompactSpace α] [T2Space β] - {ι : Type*} {l : Filter ι} [Filter.NeBot l] (F : ι → C(α, β)) : +/-- A family `F` of functions in `C(X, Y)` converges in the compact-open topology, if and only if +it converges in the compact-open topology on each compact subset of `X`. -/ +theorem exists_tendsto_compactOpen_iff_forall [WeaklyLocallyCompactSpace X] [T2Space Y] + {ι : Type*} {l : Filter ι} [Filter.NeBot l] (F : ι → C(X, Y)) : (∃ f, Filter.Tendsto F l (𝓝 f)) ↔ - ∀ (s : Set α) (hs : IsCompact s), ∃ f, Filter.Tendsto (fun i => (F i).restrict s) l (𝓝 f) := by + ∀ (s : Set X) (hs : IsCompact s), ∃ f, Filter.Tendsto (fun i => (F i).restrict s) l (𝓝 f) := by constructor · rintro ⟨f, hf⟩ s _ exact ⟨f.restrict s, tendsto_compactOpen_restrict hf s⟩ @@ -304,7 +304,7 @@ theorem exists_tendsto_compactOpen_iff_forall [WeaklyLocallyCompactSpace α] [T2 -- By uniqueness of limits in a `T2Space`, since `fun i ↦ F i x` tends to both `f s₁ hs₁ x` and -- `f s₂ hs₂ x`, we have `f s₁ hs₁ x = f s₂ hs₂ x` have h : - ∀ (s₁) (hs₁ : IsCompact s₁) (s₂) (hs₂ : IsCompact s₂) (x : α) (hxs₁ : x ∈ s₁) (hxs₂ : x ∈ s₂), + ∀ (s₁) (hs₁ : IsCompact s₁) (s₂) (hs₂ : IsCompact s₂) (x : X) (hxs₁ : x ∈ s₁) (hxs₂ : x ∈ s₂), f s₁ hs₁ ⟨x, hxs₁⟩ = f s₂ hs₂ ⟨x, hxs₂⟩ := by rintro s₁ hs₁ s₂ hs₂ x hxs₁ hxs₂ haveI := isCompact_iff_compactSpace.mp hs₁ @@ -325,34 +325,34 @@ end InfInduced section Coev -variable (α β) +variable (X Y) -/-- The coevaluation map `β → C(α, β × α)` sending a point `x : β` to the continuous function -on `α` sending `y` to `(x, y)`. -/ -def coev (b : β) : C(α, β × α) := - { toFun := Prod.mk b } +/-- The coevaluation map `Y → C(X, Y × X)` sending a point `x : Y` to the continuous function +on `X` sending `y` to `(x, y)`. -/ +def coev (y : Y) : C(X, Y × X) := + { toFun := Prod.mk y } #align continuous_map.coev ContinuousMap.coev -variable {α β} +variable {X Y} -theorem image_coev {y : β} (s : Set α) : coev α β y '' s = ({y} : Set β) ×ˢ s := by +theorem image_coev {y : Y} (s : Set X) : coev X Y y '' s = ({y} : Set Y) ×ˢ s := by aesop #align continuous_map.image_coev ContinuousMap.image_coev --- The coevaluation map β → C(α, β × α) is continuous (always). -theorem continuous_coev : Continuous (coev α β) := +-- The coevaluation map Y → C(X, Y × X) is continuous (always). +theorem continuous_coev : Continuous (coev X Y) := continuous_generateFrom_iff.2 <| by rintro _ ⟨s, sc, u, uo, rfl⟩ rw [isOpen_iff_forall_mem_open] intro y hy - have hy' : (↑(coev α β y) '' s ⊆ u) := hy + have hy' : (↑(coev X Y y) '' s ⊆ u) := hy -- porting notes: was below - --change coev α β y '' s ⊆ u at hy + --change coev X Y y '' s ⊆ u at hy rw [image_coev s] at hy' rcases generalized_tube_lemma isCompact_singleton sc uo hy' with ⟨v, w, vo, _, yv, sw, vwu⟩ refine' ⟨v, _, vo, singleton_subset_iff.mp yv⟩ intro y' hy' - change coev α β y' '' s ⊆ u + change coev X Y y' '' s ⊆ u rw [image_coev s] exact (prod_mono (singleton_subset_iff.mpr hy') sw).trans vwu #align continuous_map.continuous_coev ContinuousMap.continuous_coev @@ -362,77 +362,77 @@ end Coev section Curry /-- Auxiliary definition, see `ContinuousMap.curry` and `Homeomorph.curry`. -/ -def curry' (f : C(α × β, γ)) (a : α) : C(β, γ) := - ⟨Function.curry f a, Continuous.comp f.2 (continuous_const.prod_mk continuous_id)⟩ +def curry' (f : C(X × Y, Z)) (x : X) : C(Y, Z) := + ⟨Function.curry f x, Continuous.comp f.2 (continuous_const.prod_mk continuous_id)⟩ -- Porting note: proof was `by continuity` #align continuous_map.curry' ContinuousMap.curry' -/-- If a map `α × β → γ` is continuous, then its curried form `α → C(β, γ)` is continuous. -/ -theorem continuous_curry' (f : C(α × β, γ)) : Continuous (curry' f) := +/-- If a map `X × Y → Z` is continuous, then its curried form `X → C(Y, Z)` is continuous. -/ +theorem continuous_curry' (f : C(X × Y, Z)) : Continuous (curry' f) := Continuous.comp (continuous_comp f) continuous_coev #align continuous_map.continuous_curry' ContinuousMap.continuous_curry' -/-- To show continuity of a map `α → C(β, γ)`, it suffices to show that its uncurried form - `α × β → γ` is continuous. -/ -theorem continuous_of_continuous_uncurry (f : α → C(β, γ)) +/-- To show continuity of a map `X → C(Y, Z)`, it suffices to show that its uncurried form + `X × Y → Z` is continuous. -/ +theorem continuous_of_continuous_uncurry (f : X → C(Y, Z)) (h : Continuous (Function.uncurry fun x y => f x y)) : Continuous f := continuous_curry' ⟨_, h⟩ #align continuous_map.continuous_of_continuous_uncurry ContinuousMap.continuous_of_continuous_uncurry -/-- The curried form of a continuous map `α × β → γ` as a continuous map `α → C(β, γ)`. - If `a × β` is locally compact, this is continuous. If `α` and `β` are both locally +/-- The curried form of a continuous map `X × Y → Z` as a continuous map `X → C(Y, Z)`. + If `X × Y` is locally compact, this is continuous. If `X` and `Y` are both locally compact, then this is a homeomorphism, see `Homeomorph.curry`. -/ -def curry (f : C(α × β, γ)) : C(α, C(β, γ)) := +def curry (f : C(X × Y, Z)) : C(X, C(Y, Z)) := ⟨_, continuous_curry' f⟩ #align continuous_map.curry ContinuousMap.curry @[simp] -theorem curry_apply (f : C(α × β, γ)) (a : α) (b : β) : f.curry a b = f (a, b) := +theorem curry_apply (f : C(X × Y, Z)) (x : X) (y : Y) : f.curry x y = f (x, y) := rfl #align continuous_map.curry_apply ContinuousMap.curry_apply /-- The currying process is a continuous map between function spaces. -/ -theorem continuous_curry [LocallyCompactSpace (α × β)] : - Continuous (curry : C(α × β, γ) → C(α, C(β, γ))) := by +theorem continuous_curry [LocallyCompactSpace (X × Y)] : + Continuous (curry : C(X × Y, Z) → C(X, C(Y, Z))) := by apply continuous_of_continuous_uncurry apply continuous_of_continuous_uncurry rw [← (Homeomorph.prodAssoc _ _ _).symm.comp_continuous_iff'] exact continuous_eval #align continuous_map.continuous_curry ContinuousMap.continuous_curry -/-- The uncurried form of a continuous map `α → C(β, γ)` is a continuous map `α × β → γ`. -/ -theorem continuous_uncurry_of_continuous [LocallyCompactSpace β] (f : C(α, C(β, γ))) : +/-- The uncurried form of a continuous map `X → C(Y, Z)` is a continuous map `X × Y → Z`. -/ +theorem continuous_uncurry_of_continuous [LocallyCompactSpace Y] (f : C(X, C(Y, Z))) : Continuous (Function.uncurry fun x y => f x y) := continuous_eval.comp <| f.continuous.prod_map continuous_id #align continuous_map.continuous_uncurry_of_continuous ContinuousMap.continuous_uncurry_of_continuous -/-- The uncurried form of a continuous map `α → C(β, γ)` as a continuous map `α × β → γ` (if `β` is - locally compact). If `α` is also locally compact, then this is a homeomorphism between the two +/-- The uncurried form of a continuous map `X → C(Y, Z)` as a continuous map `X × Y → Z` (if `Y` is + locally compact). If `X` is also locally compact, then this is a homeomorphism between the two function spaces, see `Homeomorph.curry`. -/ @[simps] -def uncurry [LocallyCompactSpace β] (f : C(α, C(β, γ))) : C(α × β, γ) := +def uncurry [LocallyCompactSpace Y] (f : C(X, C(Y, Z))) : C(X × Y, Z) := ⟨_, continuous_uncurry_of_continuous f⟩ #align continuous_map.uncurry ContinuousMap.uncurry /-- The uncurrying process is a continuous map between function spaces. -/ -theorem continuous_uncurry [LocallyCompactSpace α] [LocallyCompactSpace β] : - Continuous (uncurry : C(α, C(β, γ)) → C(α × β, γ)) := by +theorem continuous_uncurry [LocallyCompactSpace X] [LocallyCompactSpace Y] : + Continuous (uncurry : C(X, C(Y, Z)) → C(X × Y, Z)) := by apply continuous_of_continuous_uncurry rw [← (Homeomorph.prodAssoc _ _ _).comp_continuous_iff'] apply continuous_eval.comp (continuous_eval.prod_map continuous_id) #align continuous_map.continuous_uncurry ContinuousMap.continuous_uncurry -/-- The family of constant maps: `β → C(α, β)` as a continuous map. -/ -def const' : C(β, C(α, β)) := +/-- The family of constant maps: `Y → C(X, Y)` as a continuous map. -/ +def const' : C(Y, C(X, Y)) := curry ContinuousMap.fst #align continuous_map.const' ContinuousMap.const' @[simp] -theorem coe_const' : (const' : β → C(α, β)) = const α := +theorem coe_const' : (const' : Y → C(X, Y)) = const X := rfl #align continuous_map.coe_const' ContinuousMap.coe_const' -theorem continuous_const' : Continuous (const α : β → C(α, β)) := +theorem continuous_const' : Continuous (const X : Y → C(X, Y)) := const'.continuous #align continuous_map.continuous_const' ContinuousMap.continuous_const' @@ -446,36 +446,36 @@ open ContinuousMap namespace Homeomorph -variable {α : Type*} {β : Type*} {γ : Type*} +variable {X : Type*} {Y : Type*} {Z : Type*} -variable [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] +variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] -/-- Currying as a homeomorphism between the function spaces `C(α × β, γ)` and `C(α, C(β, γ))`. -/ -def curry [LocallyCompactSpace α] [LocallyCompactSpace β] : C(α × β, γ) ≃ₜ C(α, C(β, γ)) := +/-- Currying as a homeomorphism between the function spaces `C(X × Y, Z)` and `C(X, C(Y, Z))`. -/ +def curry [LocallyCompactSpace X] [LocallyCompactSpace Y] : C(X × Y, Z) ≃ₜ C(X, C(Y, Z)) := ⟨⟨ContinuousMap.curry, uncurry, by intro; ext; rfl, by intro; ext; rfl⟩, continuous_curry, continuous_uncurry⟩ #align homeomorph.curry Homeomorph.curry -/-- If `α` has a single element, then `β` is homeomorphic to `C(α, β)`. -/ -def continuousMapOfUnique [Unique α] : β ≃ₜ C(α, β) where - toFun := const α +/-- If `X` has a single element, then `Y` is homeomorphic to `C(X, Y)`. -/ +def continuousMapOfUnique [Unique X] : Y ≃ₜ C(X, Y) where + toFun := const X invFun f := f default - left_inv a := rfl + left_inv _ := rfl right_inv f := by - ext a - rw [Unique.eq_default a] + ext x + rw [Unique.eq_default x] rfl continuous_toFun := continuous_const' continuous_invFun := continuous_eval_const _ #align homeomorph.continuous_map_of_unique Homeomorph.continuousMapOfUnique @[simp] -theorem continuousMapOfUnique_apply [Unique α] (b : β) (a : α) : continuousMapOfUnique b a = b := +theorem continuousMapOfUnique_apply [Unique X] (y : Y) (x : X) : continuousMapOfUnique y x = y := rfl #align homeomorph.continuous_map_of_unique_apply Homeomorph.continuousMapOfUnique_apply @[simp] -theorem continuousMapOfUnique_symm_apply [Unique α] (f : C(α, β)) : +theorem continuousMapOfUnique_symm_apply [Unique X] (f : C(X, Y)) : continuousMapOfUnique.symm f = f default := rfl #align homeomorph.continuous_map_of_unique_symm_apply Homeomorph.continuousMapOfUnique_symm_apply From d641c6806feda500505482917c46ed17d38a5d9f Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Sat, 30 Dec 2023 16:05:21 +0000 Subject: [PATCH 282/353] feat(AlgebraicTopology): definition of Kan complex and quasicategory (#9357) --- Mathlib.lean | 2 + Mathlib/AlgebraicTopology/KanComplex.lean | 37 +++++++++++++ Mathlib/AlgebraicTopology/Quasicategory.lean | 58 ++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 Mathlib/AlgebraicTopology/KanComplex.lean create mode 100644 Mathlib/AlgebraicTopology/Quasicategory.lean diff --git a/Mathlib.lean b/Mathlib.lean index 47182459bee85..d2026eb119a81 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -547,8 +547,10 @@ import Mathlib.AlgebraicTopology.FundamentalGroupoid.InducedMaps import Mathlib.AlgebraicTopology.FundamentalGroupoid.PUnit import Mathlib.AlgebraicTopology.FundamentalGroupoid.Product import Mathlib.AlgebraicTopology.FundamentalGroupoid.SimplyConnected +import Mathlib.AlgebraicTopology.KanComplex import Mathlib.AlgebraicTopology.MooreComplex import Mathlib.AlgebraicTopology.Nerve +import Mathlib.AlgebraicTopology.Quasicategory import Mathlib.AlgebraicTopology.SimplexCategory import Mathlib.AlgebraicTopology.SimplicialObject import Mathlib.AlgebraicTopology.SimplicialSet diff --git a/Mathlib/AlgebraicTopology/KanComplex.lean b/Mathlib/AlgebraicTopology/KanComplex.lean new file mode 100644 index 0000000000000..73a6d4e026c32 --- /dev/null +++ b/Mathlib/AlgebraicTopology/KanComplex.lean @@ -0,0 +1,37 @@ +/- +Copyright (c) 2023 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin +-/ + +import Mathlib.AlgebraicTopology.SimplicialSet + +/-! +# Kan complexes + +In this file we give the definition of Kan complexes. +In `Mathlib/AlgebraicTopology/Quasicategory.lean` +we show that every Kan complex is a quasicategory. + +## TODO + +- Show that the singular simplicial set of a topological space is a Kan complex. +- Generalize the definition to higher universes. + Since `Λ[n, i]` is an object of `SSet.{0}`, + the current definition of a Kan complex `S` + requires `S : SSet.{0}`. + +-/ + +namespace SSet + +open CategoryTheory Simplicial + +/-- A simplicial set `S` is a *Kan complex* if it satisfies the following horn-filling condition: +for every `n : ℕ` and `0 ≤ i ≤ n`, +every map of simplicial sets `σ₀ : Λ[n, i] → S` can be extended to a map `σ : Δ[n] → S`. -/ +class KanComplex (S : SSet) : Prop where + hornFilling : ∀ ⦃n : ℕ⦄ ⦃i : Fin (n+1)⦄ (σ₀ : Λ[n, i] ⟶ S), + ∃ σ : Δ[n] ⟶ S, σ₀ = hornInclusion n i ≫ σ + +end SSet diff --git a/Mathlib/AlgebraicTopology/Quasicategory.lean b/Mathlib/AlgebraicTopology/Quasicategory.lean new file mode 100644 index 0000000000000..43984872f3089 --- /dev/null +++ b/Mathlib/AlgebraicTopology/Quasicategory.lean @@ -0,0 +1,58 @@ +/- +Copyright (c) 2023 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin +-/ + +import Mathlib.AlgebraicTopology.KanComplex + +/-! +# Quasicategories + +In this file we define quasicategories, +a common model of infinity categories. +We show that every Kan complex is a quasicategory. + +In `Mathlib/AlgebraicTopology/Nerve.lean` +we show (TODO) that the nerve of a category is a quasicategory. + +## TODO + +- Generalize the definition to higher universes. + See the corresponding TODO in `Mathlib/AlgebraicTopology/KanComplex.lean`. + +-/ + +namespace SSet + +open CategoryTheory Simplicial + +/-- A simplicial set `S` is a *quasicategory* if it satisfies the following horn-filling condition: +for every `n : ℕ` and `0 < i < n`, +every map of simplicial sets `σ₀ : Λ[n, i] → S` can be extended to a map `σ : Δ[n] → S`. + +[Kerodon, 003A] -/ +class Quasicategory (S : SSet) : Prop where + hornFilling' : ∀ ⦃n : ℕ⦄ ⦃i : Fin (n+3)⦄ (σ₀ : Λ[n+2, i] ⟶ S) + (_h0 : 0 < i) (_hn : i < Fin.last (n+2)), + ∃ σ : Δ[n+2] ⟶ S, σ₀ = hornInclusion (n+2) i ≫ σ + +lemma Quasicategory.hornFilling {S : SSet} [Quasicategory S] ⦃n : ℕ⦄ ⦃i : Fin (n+1)⦄ + (h0 : 0 < i) (hn : i < Fin.last n) + (σ₀ : Λ[n, i] ⟶ S) : ∃ σ : Δ[n] ⟶ S, σ₀ = hornInclusion n i ≫ σ := by + cases n using Nat.casesAuxOn with + | zero => simp [Fin.lt_iff_val_lt_val] at hn + | succ n => + cases n using Nat.casesAuxOn with + | zero => + simp only [Fin.lt_iff_val_lt_val, Fin.val_zero, Fin.val_last, zero_add, Nat.lt_one_iff] at h0 hn + simp [hn] at h0 + | succ n => exact Quasicategory.hornFilling' σ₀ h0 hn + +/-- Every Kan complex is a quasicategory. + +[Kerodon, 003C] -/ +instance (S : SSet) [KanComplex S] : Quasicategory S where + hornFilling' _ _ σ₀ _ _ := KanComplex.hornFilling σ₀ + +end SSet From b13975ce1c723a0076f2ae99be60f7134efc06cd Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Sat, 30 Dec 2023 16:32:38 +0000 Subject: [PATCH 283/353] chore(AlgebraicTopology/SimplicialSet): add delaborator (#9358) add delaborator for standard simplex and horn notation --- Mathlib/AlgebraicTopology/SimplicialSet.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/AlgebraicTopology/SimplicialSet.lean b/Mathlib/AlgebraicTopology/SimplicialSet.lean index 004125b859f4b..97ac48140b7e6 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet.lean @@ -77,7 +77,7 @@ set_option linter.uppercaseLean3 false in #align sSet.standard_simplex SSet.standardSimplex -- mathport name: standard_simplex -scoped[Simplicial] notation "Δ[" n "]" => SSet.standardSimplex.obj (SimplexCategory.mk n) +scoped[Simplicial] notation3 "Δ[" n "]" => SSet.standardSimplex.obj (SimplexCategory.mk n) instance : Inhabited SSet := ⟨Δ[0]⟩ @@ -131,7 +131,7 @@ set_option linter.uppercaseLean3 false in #align sSet.horn SSet.horn -- mathport name: sSet.horn -scoped[Simplicial] notation "Λ[" n ", " i "]" => SSet.horn (n : ℕ) i +scoped[Simplicial] notation3 "Λ[" n ", " i "]" => SSet.horn (n : ℕ) i /-- The inclusion of the `i`-th horn of the `n`-th standard simplex into that standard simplex. -/ def hornInclusion (n : ℕ) (i : Fin (n + 1)) : Λ[n, i] ⟶ Δ[n] where From ba4be74a354131e437e393120d61bbc0f2c2456e Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Sat, 30 Dec 2023 19:16:20 +0000 Subject: [PATCH 284/353] feat: Kummer extensions are cyclic. (#9119) Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 1 + Mathlib/Algebra/Group/Units/Hom.lean | 4 + Mathlib/Data/Polynomial/RingDivision.lean | 5 + Mathlib/FieldTheory/KummerExtension.lean | 398 ++++++++++++++++++ Mathlib/GroupTheory/Subgroup/Basic.lean | 8 + .../Polynomial/Cyclotomic/Basic.lean | 6 +- .../Polynomial/Cyclotomic/Roots.lean | 2 +- Mathlib/RingTheory/RootsOfUnity/Basic.lean | 144 +++++-- docs/references.bib | 12 + 9 files changed, 537 insertions(+), 43 deletions(-) create mode 100644 Mathlib/FieldTheory/KummerExtension.lean diff --git a/Mathlib.lean b/Mathlib.lean index d2026eb119a81..7e17918a42c8d 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2070,6 +2070,7 @@ import Mathlib.FieldTheory.IsAlgClosed.Classification import Mathlib.FieldTheory.IsAlgClosed.Spectrum import Mathlib.FieldTheory.IsSepClosed import Mathlib.FieldTheory.KrullTopology +import Mathlib.FieldTheory.KummerExtension import Mathlib.FieldTheory.Laurent import Mathlib.FieldTheory.Minpoly.Basic import Mathlib.FieldTheory.Minpoly.Field diff --git a/Mathlib/Algebra/Group/Units/Hom.lean b/Mathlib/Algebra/Group/Units/Hom.lean index 1860fc13f5f76..c9ab629980894 100644 --- a/Mathlib/Algebra/Group/Units/Hom.lean +++ b/Mathlib/Algebra/Group/Units/Hom.lean @@ -93,6 +93,10 @@ theorem map_comp (f : M →* N) (g : N →* P) : map (g.comp f) = (map g).comp ( #align units.map_comp Units.map_comp #align add_units.map_comp AddUnits.map_comp +@[to_additive] +lemma map_injective {f : M →* N} (hf : Function.Injective f) : + Function.Injective (map f) := fun _ _ e => ext (hf (congr_arg val e)) + variable (M) @[to_additive (attr := simp)] diff --git a/Mathlib/Data/Polynomial/RingDivision.lean b/Mathlib/Data/Polynomial/RingDivision.lean index 813b64c838ffa..fe180e2893dc3 100644 --- a/Mathlib/Data/Polynomial/RingDivision.lean +++ b/Mathlib/Data/Polynomial/RingDivision.lean @@ -890,6 +890,11 @@ theorem nthRoots_zero (r : R) : nthRoots 0 r = 0 := by simp only [empty_eq_zero, pow_zero, nthRoots, ← C_1, ← C_sub, roots_C] #align polynomial.nth_roots_zero Polynomial.nthRoots_zero +@[simp] +theorem nthRoots_zero_right {R} [CommRing R] [IsDomain R] (n : ℕ) : + nthRoots n (0 : R) = Multiset.replicate n 0 := by + rw [nthRoots, C.map_zero, sub_zero, roots_pow, roots_X, Multiset.nsmul_singleton] + theorem card_nthRoots (n : ℕ) (a : R) : Multiset.card (nthRoots n a) ≤ n := by classical exact (if hn : n = 0 then diff --git a/Mathlib/FieldTheory/KummerExtension.lean b/Mathlib/FieldTheory/KummerExtension.lean new file mode 100644 index 0000000000000..db15cae26a4c4 --- /dev/null +++ b/Mathlib/FieldTheory/KummerExtension.lean @@ -0,0 +1,398 @@ +/- +Copyright (c) 2023 Andrew Yang, Patrick Lutz. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.RingTheory.RootsOfUnity.Basic +import Mathlib.RingTheory.AdjoinRoot +import Mathlib.LinearAlgebra.Charpoly.Basic +import Mathlib.FieldTheory.Galois +import Mathlib.LinearAlgebra.Eigenspace.Minpoly +/-! +# Kummer Extensions + +## Main result +- `isCyclic_tfae`: +Suppose `L/K` is a finite extension of dimension `n`, and `K` contains all `n`-th roots of unity. +Then `L/K` is cyclic iff +`L` is a splitting field of some irreducible polynomial of the form `Xⁿ - a : K[X]` iff +`L = K[α]` for some `αⁿ ∈ K`. + +- `autEquivRootsOfUnity`: +Given an instance `IsSplittingField K L (X ^ n - C a)` +(perhaps via `isSplittingField_X_pow_sub_C_of_root_adjoin_eq_top`), +then the galois group is isomorphic to `rootsOfUnity n K`, by sending +`σ ↦ σ α / α` for `α ^ n = a`, and the inverse is given by `μ ↦ (α ↦ μ • α)`. + +- `autEquivZmod`: +Furthermore, given an explicit choice `ζ` of a primitive `n`-th root of unity, the galois group is +then isomorphic to `Multiplicative (ZMod n)` whose inverse is given by +`i ↦ (α ↦ ζⁱ • α)`. + +## Other results +Criteria for `X ^ n - C a` to be irreducible is given: +- `X_pow_sub_C_irreducible_iff_of_prime`: `X ^ n - C a` is irreducible iff `a` is not a `p`-power. + +TODO: criteria for general `n`. See [serge_lang_algebra] VI,§9. + +-/ +variable {K : Type*} [Field K] + +open Polynomial IntermediateField AdjoinRoot + +section Splits + +lemma root_X_pow_sub_C_pow (n : ℕ) (a : K) : + (AdjoinRoot.root (X ^ n - C a)) ^ n = AdjoinRoot.of _ a := by + rw [← sub_eq_zero, ← AdjoinRoot.eval₂_root, eval₂_sub, eval₂_C, eval₂_pow, eval₂_X] + +lemma root_X_pow_sub_C_ne_zero {n : ℕ} (hn : 1 < n) (a : K) : + (AdjoinRoot.root (X ^ n - C a)) ≠ 0 := + mk_ne_zero_of_natDegree_lt (monic_X_pow_sub_C _ (Nat.not_eq_zero_of_lt hn)) + X_ne_zero <| by rwa [natDegree_X_pow_sub_C, natDegree_X] + +lemma root_X_pow_sub_C_ne_zero' {n : ℕ} {a : K} (hn : 0 < n) (ha : a ≠ 0) : + (AdjoinRoot.root (X ^ n - C a)) ≠ 0 := by + obtain (rfl|hn) := (Nat.succ_le_iff.mpr hn).eq_or_lt + · rw [← Nat.one_eq_succ_zero, pow_one] + intro e + refine mk_ne_zero_of_natDegree_lt (monic_X_sub_C a) (C_ne_zero.mpr ha) (by simp) ?_ + trans AdjoinRoot.mk (X - C a) (X - (X - C a)) + · rw [sub_sub_cancel] + · rw [map_sub, mk_self, sub_zero, mk_X, e] + · exact root_X_pow_sub_C_ne_zero hn a + +theorem X_pow_sub_C_splits_of_isPrimitiveRoot + {n : ℕ} {ζ : K} (hζ : IsPrimitiveRoot ζ n) {α a : K} (e : α ^ n = a) : + (X ^ n - C a).Splits (RingHom.id _) := by + cases n.eq_zero_or_pos with + | inl hn => + rw [hn, pow_zero, ← C.map_one, ← map_sub] + exact splits_C _ _ + | inr hn => + rw [splits_iff_card_roots, ← nthRoots, hζ.card_nthRoots, natDegree_X_pow_sub_C, if_pos ⟨α, e⟩] + +open BigOperators + +theorem X_pow_sub_C_eq_prod + {n : ℕ} {ζ : K} (hζ : IsPrimitiveRoot ζ n) {α a : K} (hn : 0 < n) (e : α ^ n = a) : + (X ^ n - C a) = ∏ i in Finset.range n, (X - C (ζ ^ i * α)) := by + rw [eq_prod_roots_of_monic_of_splits_id (monic_X_pow_sub_C _ (Nat.pos_iff_ne_zero.mp hn)) + (X_pow_sub_C_splits_of_isPrimitiveRoot hζ e), ← nthRoots, hζ.nthRoots_eq e, Multiset.map_map] + rfl + +end Splits + +section Irreducible + +lemma ne_zero_of_irreducible_X_pow_sub_C {n : ℕ} {a : K} (H : Irreducible (X ^ n - C a)) : + n ≠ 0 := by + rintro rfl + rw [pow_zero, ← C.map_one, ← map_sub] at H + exact not_irreducible_C _ H + +lemma ne_zero_of_irreducible_X_pow_sub_C' {n : ℕ} (hn : n ≠ 1) {a : K} + (H : Irreducible (X ^ n - C a)) : a ≠ 0 := by + rintro rfl + rw [map_zero, sub_zero] at H + exact not_irreducible_pow hn H + +lemma root_X_pow_sub_C_eq_zero_iff {n : ℕ} {a : K} (H : Irreducible (X ^ n - C a)) : + (AdjoinRoot.root (X ^ n - C a)) = 0 ↔ a = 0 := by + have hn := (Nat.pos_iff_ne_zero.mpr (ne_zero_of_irreducible_X_pow_sub_C H)) + refine ⟨not_imp_not.mp (root_X_pow_sub_C_ne_zero' hn), ?_⟩ + rintro rfl + have := not_imp_not.mp (fun hn ↦ ne_zero_of_irreducible_X_pow_sub_C' hn H) rfl + rw [this, pow_one, map_zero, sub_zero, ← mk_X, mk_self] + +lemma root_X_pow_sub_C_ne_zero_iff {n : ℕ} {a : K} (H : Irreducible (X ^ n - C a)) : + (AdjoinRoot.root (X ^ n - C a)) ≠ 0 ↔ a ≠ 0 := + (root_X_pow_sub_C_eq_zero_iff H).not + +end Irreducible + +/-! +### Galois Group of `K[n√a]` +We first develop the theory for a specific `K[n√a] := AdjoinRoot (X ^ n - C a)`. +The main result is the description of the galois group: `autAdjoinRootXPowSubCEquiv`. +-/ + +variable {n : ℕ} (hζ : (primitiveRoots n K).Nonempty) (hn : 0 < n) +variable (a : K) (H : Irreducible (X ^ n - C a)) + +set_option quotPrecheck false in +scoped[KummerExtension] notation3 "K[" n "√" a "]" => AdjoinRoot (Polynomial.X ^ n - Polynomial.C a) + +attribute [nolint docBlame] KummerExtension.«termK[_√_]» + +open scoped KummerExtension + +section AdjoinRoot + +/-- Also see `Polynomial.separable_X_pow_sub_C_unit` -/ +theorem Polynomial.separable_X_pow_sub_C_of_irreducible : (X ^ n - C a).Separable := by + letI := Fact.mk H + letI : Algebra K K[n√a] := inferInstance + have hn := Nat.pos_iff_ne_zero.mpr (ne_zero_of_irreducible_X_pow_sub_C H) + by_cases hn' : n = 1 + · rw [hn', pow_one]; exact separable_X_sub_C + have ⟨ζ, hζ⟩ := hζ + rw [mem_primitiveRoots (Nat.pos_of_ne_zero <| ne_zero_of_irreducible_X_pow_sub_C H)] at hζ + rw [← separable_map (algebraMap K K[n√a]), Polynomial.map_sub, Polynomial.map_pow, map_C, map_X, + algebraMap_eq, X_pow_sub_C_eq_prod (hζ.map_of_injective (algebraMap K _).injective) hn + (root_X_pow_sub_C_pow n a), separable_prod_X_sub_C_iff'] + exact (hζ.map_of_injective (algebraMap K K[n√a]).injective).injOn_pow_mul + (root_X_pow_sub_C_ne_zero (lt_of_le_of_ne (show 1 ≤ n from hn) (Ne.symm hn')) _) + +/-- The natural embedding of the roots of unity of `K` into `Gal(K[ⁿ√a]/K)`, by sending +`η ↦ (ⁿ√a ↦ η • ⁿ√a)`. Also see `autAdjoinRootXPowSubC` for the `AlgEquiv` version. -/ +noncomputable +def autAdjoinRootXPowSubCHom : + rootsOfUnity ⟨n, hn⟩ K →* (K[n√a] →ₐ[K] K[n√a]) where + toFun := fun η ↦ liftHom (X ^ n - C a) (((η : Kˣ) : K) • (root _) : K[n√a]) <| by + have := (mem_rootsOfUnity' _ _).mp η.prop + dsimp at this + rw [map_sub, map_pow, aeval_C, aeval_X, Algebra.smul_def, mul_pow, root_X_pow_sub_C_pow, + AdjoinRoot.algebraMap_eq, ← map_pow, this, map_one, one_mul, sub_self] + map_one' := algHom_ext <| by simp + map_mul' := fun ε η ↦ algHom_ext <| by simp [mul_smul, smul_comm ((ε : Kˣ) : K)] + +/-- The natural embedding of the roots of unity of `K` into `Gal(K[ⁿ√a]/K)`, by sending +`η ↦ (ⁿ√a ↦ η • ⁿ√a)`. This is an isomorphism when `K` contains a primitive root of unity. +See `autAdjoinRootXPowSubCEquiv`. -/ +noncomputable +def autAdjoinRootXPowSubC : + rootsOfUnity ⟨n, hn⟩ K →* (K[n√a] ≃ₐ[K] K[n√a]) := + (AlgEquiv.algHomUnitsEquiv _ _).toMonoidHom.comp (autAdjoinRootXPowSubCHom hn a).toHomUnits + +lemma autAdjoinRootXPowSubC_root (η) : + autAdjoinRootXPowSubC hn a η (root _) = ((η : Kˣ) : K) • root _ := by + dsimp [autAdjoinRootXPowSubC, autAdjoinRootXPowSubCHom, AlgEquiv.algHomUnitsEquiv] + apply liftHom_root + +variable {a} + +/-- The inverse function of `autAdjoinRootXPowSubC` if `K` has all roots of unity. +See `autAdjoinRootXPowSubCEquiv`. -/ +noncomputable +def AdjoinRootXPowSubCEquivToRootsOfUnity (σ : K[n√a] ≃ₐ[K] K[n√a]) : + rootsOfUnity ⟨n, hn⟩ K := + letI := Fact.mk H + letI : IsDomain K[n√a] := inferInstance + letI := Classical.decEq K + (rootsOfUnityEquivOfPrimitiveRoots (n := ⟨n, hn⟩) (algebraMap K K[n√a]).injective hζ).symm + (rootsOfUnity.mkOfPowEq (if a = 0 then 1 else σ (root _) / root _) (by + -- The if is needed in case `n = 1` and `a = 0` and `K[n√a] = K`. + split + · exact one_pow _ + rw [div_pow, ← map_pow] + simp only [PNat.mk_coe, root_X_pow_sub_C_pow, ← algebraMap_eq, AlgEquiv.commutes] + rw [div_self] + rwa [Ne.def, map_eq_zero_iff _ (algebraMap K _).injective])) + +/-- The equivalence between the roots of unity of `K` and `Gal(K[ⁿ√a]/K)`. -/ +noncomputable +def autAdjoinRootXPowSubCEquiv : + rootsOfUnity ⟨n, hn⟩ K ≃* (K[n√a] ≃ₐ[K] K[n√a]) where + __ := autAdjoinRootXPowSubC hn a + invFun := AdjoinRootXPowSubCEquivToRootsOfUnity hζ hn H + left_inv := by + intro η + have := Fact.mk H + have : IsDomain K[n√a] := inferInstance + letI : Algebra K K[n√a] := inferInstance + apply (rootsOfUnityEquivOfPrimitiveRoots + (n := ⟨n, hn⟩) (algebraMap K K[n√a]).injective hζ).injective + ext + simp only [algebraMap_eq, OneHom.toFun_eq_coe, MonoidHom.toOneHom_coe, + autAdjoinRootXPowSubC_root, Algebra.smul_def, ne_eq, MulEquiv.apply_symm_apply, + rootsOfUnity.val_mkOfPowEq_coe, val_rootsOfUnityEquivOfPrimitiveRoots_apply_coe, + AdjoinRootXPowSubCEquivToRootsOfUnity] + split_ifs with h + · obtain rfl := not_imp_not.mp (fun hn ↦ ne_zero_of_irreducible_X_pow_sub_C' hn H) h + have : (η : Kˣ) = 1 := (pow_one _).symm.trans η.prop + simp only [PNat.mk_one, this, Units.val_one, map_one] + · exact mul_div_cancel _ (root_X_pow_sub_C_ne_zero' hn h) + right_inv := by + intro e + have := Fact.mk H + letI : Algebra K K[n√a] := inferInstance + apply AlgEquiv.coe_algHom_injective + apply AdjoinRoot.algHom_ext + simp only [algebraMap_eq, OneHom.toFun_eq_coe, MonoidHom.toOneHom_coe, AlgHom.coe_coe, + autAdjoinRootXPowSubC_root, Algebra.smul_def, PNat.mk_coe, + AdjoinRootXPowSubCEquivToRootsOfUnity] + rw [rootsOfUnityEquivOfPrimitiveRoots_symm_apply, rootsOfUnity.val_mkOfPowEq_coe] + split_ifs with h + · obtain rfl := not_imp_not.mp (fun hn ↦ ne_zero_of_irreducible_X_pow_sub_C' hn H) h + rw [(pow_one _).symm.trans (root_X_pow_sub_C_pow 1 a), one_mul, + ← algebraMap_eq, AlgEquiv.commutes] + · refine div_mul_cancel _ (root_X_pow_sub_C_ne_zero' hn h) + +lemma autAdjoinRootXPowSubCEquiv_root (η) : + autAdjoinRootXPowSubCEquiv hζ hn H η (root _) = ((η : Kˣ) : K) • root _ := + autAdjoinRootXPowSubC_root hn a η + +lemma autAdjoinRootXPowSubCEquiv_symm_smul (σ) : + ((autAdjoinRootXPowSubCEquiv hζ hn H).symm σ : Kˣ) • (root _ : K[n√a]) = σ (root _) := by + have := Fact.mk H + simp only [autAdjoinRootXPowSubCEquiv, OneHom.toFun_eq_coe, MonoidHom.toOneHom_coe, + MulEquiv.symm_mk, MulEquiv.coe_mk, Equiv.coe_fn_symm_mk, AdjoinRootXPowSubCEquivToRootsOfUnity, + algebraMap_eq, Units.smul_def, Algebra.smul_def, rootsOfUnityEquivOfPrimitiveRoots_symm_apply, + rootsOfUnity.mkOfPowEq, PNat.mk_coe, Units.val_ofPowEqOne, ite_mul, one_mul, ne_eq] + simp_rw [← root_X_pow_sub_C_eq_zero_iff H] + split_ifs with h + · rw [h, mul_zero, map_zero] + · rw [div_mul_cancel _ h] + +end AdjoinRoot + +/-! ### Galois Group of `IsSplittingField K L (X ^ n - C a)` -/ + +section IsSplittingField + +variable {a} +variable {L : Type*} [Field L] [Algebra K L] [IsSplittingField K L (X ^ n - C a)] + +lemma isSplittingField_AdjoinRoot_X_pow_sub_C : + haveI := Fact.mk H + letI : Algebra K K[n√a] := inferInstance + IsSplittingField K K[n√a] (X ^ n - C a) := by + have := Fact.mk H + letI : Algebra K K[n√a] := inferInstance + constructor + · rw [← splits_id_iff_splits, Polynomial.map_sub, Polynomial.map_pow, Polynomial.map_C, + Polynomial.map_X] + have ⟨_, hζ⟩ := hζ + rw [mem_primitiveRoots (Nat.pos_of_ne_zero <| ne_zero_of_irreducible_X_pow_sub_C H)] at hζ + exact X_pow_sub_C_splits_of_isPrimitiveRoot (hζ.map_of_injective (algebraMap K _).injective) + (root_X_pow_sub_C_pow n a) + · rw [eq_top_iff, ← AdjoinRoot.adjoinRoot_eq_top] + apply Algebra.adjoin_mono + have := ne_zero_of_irreducible_X_pow_sub_C H + rw [Set.singleton_subset_iff, mem_rootSet_of_ne (X_pow_sub_C_ne_zero + (Nat.pos_of_ne_zero this) a), aeval_def, AdjoinRoot.algebraMap_eq, AdjoinRoot.eval₂_root] + +variable {α : L} (hα : α ^ n = algebraMap K L a) + +/-- Suppose `L/K` is the splitting field of `Xⁿ - a`, then a choice of `ⁿ√a` gives an equivalence of +`L` with `K[n√a]`. -/ +noncomputable +def adjoinRootXPowSubCEquiv : + K[n√a] ≃ₐ[K] L := + AlgEquiv.ofBijective (AdjoinRoot.liftHom (X ^ n - C a) α (by simp [hα])) <| by + haveI := Fact.mk H + letI := isSplittingField_AdjoinRoot_X_pow_sub_C hζ H + refine ⟨(AlgHom.toRingHom _).injective, ?_⟩ + rw [← Algebra.range_top_iff_surjective, ← IsSplittingField.adjoin_rootSet _ (X ^ n - C a), + eq_comm, adjoin_rootSet_eq_range, IsSplittingField.adjoin_rootSet] + exact IsSplittingField.splits _ _ + +lemma adjoinRootXPowSubCEquiv_root : + adjoinRootXPowSubCEquiv hζ H hα (root _) = α := by + rw [adjoinRootXPowSubCEquiv, AlgEquiv.coe_ofBijective, liftHom_root] + +lemma adjoinRootXPowSubCEquiv_symm_eq_root : + (adjoinRootXPowSubCEquiv hζ H hα).symm α = root _ := by + apply (adjoinRootXPowSubCEquiv hζ H hα).injective + rw [(adjoinRootXPowSubCEquiv hζ H hα).apply_symm_apply, adjoinRootXPowSubCEquiv_root] + +lemma Algebra.adjoin_root_eq_top_of_isSplittingField : + Algebra.adjoin K {α} = ⊤ := by + apply Subalgebra.map_injective (f := (adjoinRootXPowSubCEquiv hζ H hα).symm) + (adjoinRootXPowSubCEquiv hζ H hα).symm.injective + rw [Algebra.map_top, (Algebra.range_top_iff_surjective _).mpr + (adjoinRootXPowSubCEquiv hζ H hα).symm.surjective, AlgHom.map_adjoin, + Set.image_singleton, AlgHom.coe_coe, adjoinRootXPowSubCEquiv_symm_eq_root, adjoinRoot_eq_top] + +lemma IntermediateField.adjoin_root_eq_top_of_isSplittingField : + K⟮α⟯ = ⊤ := by + refine (IntermediateField.eq_adjoin_of_eq_algebra_adjoin _ _ _ ?_).symm + exact (Algebra.adjoin_root_eq_top_of_isSplittingField hζ H hα).symm + +variable (a) (L) + +/-- An arbitrary choice of `ⁿ√a` in the splitting field of `Xⁿ - a`. -/ +noncomputable +abbrev rootOfSplitsXPowSubC : L := + (rootOfSplits _ (IsSplittingField.splits L (X ^ n - C a)) + (by simpa [degree_X_pow_sub_C hn] using Nat.pos_iff_ne_zero.mp hn)) + +lemma rootOfSplitsXPowSubC_pow : + (rootOfSplitsXPowSubC hn a L) ^ n = algebraMap K L a := by + have := map_rootOfSplits _ (IsSplittingField.splits L (X ^ n - C a)) + simp only [eval₂_sub, eval₂_X_pow, eval₂_C, sub_eq_zero] at this + exact this _ + +variable {a} + +/-- Suppose `L/K` is the splitting field of `Xⁿ - a`, then `Gal(L/K)` is isomorphic to the +roots of unity in `K` if `K` contains all of them. +Note that this does not depend on a choice of `ⁿ√a`. -/ +noncomputable +def autEquivRootsOfUnity : + (L ≃ₐ[K] L) ≃* (rootsOfUnity ⟨n, hn⟩ K) := + (AlgEquiv.autCongr (adjoinRootXPowSubCEquiv hζ H (rootOfSplitsXPowSubC_pow hn a L)).symm).trans + (autAdjoinRootXPowSubCEquiv hζ hn H).symm + +lemma autEquivRootsOfUnity_apply_rootOfSplit (σ : L ≃ₐ[K] L) : + σ (rootOfSplitsXPowSubC hn a L) = + autEquivRootsOfUnity hζ hn H L σ • (rootOfSplitsXPowSubC hn a L) := by + obtain ⟨η, rfl⟩ := (autEquivRootsOfUnity hζ hn H L).symm.surjective σ + rw [MulEquiv.apply_symm_apply, autEquivRootsOfUnity] + simp only [MulEquiv.symm_trans_apply, AlgEquiv.autCongr_symm, AlgEquiv.symm_symm, + MulEquiv.symm_symm, AlgEquiv.autCongr_apply, AlgEquiv.trans_apply, + adjoinRootXPowSubCEquiv_symm_eq_root, autAdjoinRootXPowSubCEquiv_root, AlgEquiv.map_smul, + adjoinRootXPowSubCEquiv_root] + rfl + +lemma autEquivRootsOfUnity_smul (σ : L ≃ₐ[K] L) : + autEquivRootsOfUnity hζ hn H L σ • α = σ α := by + have ⟨ζ, hζ'⟩ := hζ + rw [mem_primitiveRoots hn] at hζ' + rw [← mem_nthRoots hn, (hζ'.map_of_injective (algebraMap K L).injective).nthRoots_eq + (rootOfSplitsXPowSubC_pow hn a L)] at hα + simp only [Finset.range_val, Multiset.mem_map, Multiset.mem_range] at hα + obtain ⟨i, _, rfl⟩ := hα + simp only [map_mul, ← map_pow, ← Algebra.smul_def, AlgEquiv.map_smul, + autEquivRootsOfUnity_apply_rootOfSplit hζ hn H L] + exact smul_comm _ _ _ + +/-- Suppose `L/K` is the splitting field of `Xⁿ - a`, and `ζ` is a `n`-th primitive root of unity +in `K`, then `Gal(L/K)` is isomorphic to `ZMod n`. -/ +noncomputable +def autEquivZmod {ζ : K} (hζ : IsPrimitiveRoot ζ n) : + (L ≃ₐ[K] L) ≃* Multiplicative (ZMod n) := + haveI hn := Nat.pos_iff_ne_zero.mpr (ne_zero_of_irreducible_X_pow_sub_C H) + (autEquivRootsOfUnity ⟨ζ, (mem_primitiveRoots hn).mpr hζ⟩ hn H L).trans + ((MulEquiv.subgroupCongr (IsPrimitiveRoot.zpowers_eq (k := ⟨n, hn⟩) + (hζ.isUnit_unit' hn)).symm).trans (AddEquiv.toMultiplicative' + (hζ.isUnit_unit' hn).zmodEquivZPowers.symm)) + +lemma autEquivZmod_symm_apply_intCast {ζ : K} (hζ : IsPrimitiveRoot ζ n) (m : ℤ) : + (autEquivZmod H L hζ).symm (Multiplicative.ofAdd (m : ZMod n)) α = ζ ^ m • α := by + have hn := Nat.pos_iff_ne_zero.mpr (ne_zero_of_irreducible_X_pow_sub_C H) + rw [← autEquivRootsOfUnity_smul ⟨ζ, (mem_primitiveRoots hn).mpr hζ⟩ hn H L hα] + simp [MulEquiv.subgroupCongr_symm_apply, Subgroup.smul_def, Units.smul_def, autEquivZmod] + +lemma autEquivZmod_symm_apply_natCast {ζ : K} (hζ : IsPrimitiveRoot ζ n) (m : ℕ) : + (autEquivZmod H L hζ).symm (Multiplicative.ofAdd (m : ZMod n)) α = ζ ^ m • α := by + simpa only [Int.cast_ofNat, zpow_coe_nat] using autEquivZmod_symm_apply_intCast H L hα hζ m + +lemma isCyclic_of_isSplittingField_X_pow_sub_C : IsCyclic (L ≃ₐ[K] L) := + have hn := Nat.pos_iff_ne_zero.mpr (ne_zero_of_irreducible_X_pow_sub_C H) + isCyclic_of_surjective _ + (autEquivZmod H _ <| (mem_primitiveRoots hn).mp hζ.choose_spec).symm.surjective + +lemma isGalois_of_isSplittingField_X_pow_sub_C : IsGalois K L := + IsGalois.of_separable_splitting_field (separable_X_pow_sub_C_of_irreducible hζ a H) + +lemma finrank_of_isSplittingField_X_pow_sub_C : FiniteDimensional.finrank K L = n := by + have := Polynomial.IsSplittingField.finiteDimensional L (X ^ n - C a) + have := isGalois_of_isSplittingField_X_pow_sub_C hζ H L + have hn := Nat.pos_iff_ne_zero.mpr (ne_zero_of_irreducible_X_pow_sub_C H) + have : NeZero n := ⟨ne_zero_of_irreducible_X_pow_sub_C H⟩ + rw [← IsGalois.card_aut_eq_finrank, Fintype.card_congr ((autEquivZmod H L <| + (mem_primitiveRoots hn).mp hζ.choose_spec).toEquiv.trans Multiplicative.toAdd), ZMod.card] + +end IsSplittingField diff --git a/Mathlib/GroupTheory/Subgroup/Basic.lean b/Mathlib/GroupTheory/Subgroup/Basic.lean index 38f49c32bd077..b90f04a0e61dd 100644 --- a/Mathlib/GroupTheory/Subgroup/Basic.lean +++ b/Mathlib/GroupTheory/Subgroup/Basic.lean @@ -3550,6 +3550,14 @@ def subgroupCongr (h : H = K) : H ≃* K := #align mul_equiv.subgroup_congr MulEquiv.subgroupCongr #align add_equiv.add_subgroup_congr AddEquiv.addSubgroupCongr +@[to_additive (attr := simp)] +lemma subgroupCongr_apply (h : H = K) (x) : + (MulEquiv.subgroupCongr h x : G) = x := rfl + +@[to_additive (attr := simp)] +lemma subgroupCongr_symm_apply (h : H = K) (x) : + ((MulEquiv.subgroupCongr h).symm x : G) = x := rfl + /-- A subgroup is isomorphic to its image under an isomorphism. If you only have an injective map, use `Subgroup.equiv_map_of_injective`. -/ @[to_additive diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean index 53eaf0060c3c2..3ce19acbfc083 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean @@ -133,14 +133,14 @@ varies over the `n`-th roots of unity. -/ theorem X_pow_sub_one_eq_prod {ζ : R} {n : ℕ} (hpos : 0 < n) (h : IsPrimitiveRoot ζ n) : X ^ n - 1 = ∏ ζ in nthRootsFinset n R, (X - C ζ) := by classical - rw [nthRootsFinset, ← Multiset.toFinset_eq (IsPrimitiveRoot.nthRoots_nodup h)] + rw [nthRootsFinset, ← Multiset.toFinset_eq (IsPrimitiveRoot.nthRoots_one_nodup h)] simp only [Finset.prod_mk, RingHom.map_one] rw [nthRoots] have hmonic : (X ^ n - C (1 : R)).Monic := monic_X_pow_sub_C (1 : R) (ne_of_lt hpos).symm symm apply prod_multiset_X_sub_C_of_monic_of_roots_card_eq hmonic rw [@natDegree_X_pow_sub_C R _ _ n 1, ← nthRoots] - exact IsPrimitiveRoot.card_nthRoots h + exact IsPrimitiveRoot.card_nthRoots_one h set_option linter.uppercaseLean3 false in #align polynomial.X_pow_sub_one_eq_prod Polynomial.X_pow_sub_one_eq_prod @@ -160,7 +160,7 @@ theorem cyclotomic'_splits (n : ℕ) : Splits (RingHom.id K) (cyclotomic' n K) : /-- If there is a primitive `n`-th root of unity in `K`, then `X ^ n - 1` splits. -/ theorem X_pow_sub_one_splits {ζ : K} {n : ℕ} (h : IsPrimitiveRoot ζ n) : Splits (RingHom.id K) (X ^ n - C (1 : K)) := by - rw [splits_iff_card_roots, ← nthRoots, IsPrimitiveRoot.card_nthRoots h, natDegree_X_pow_sub_C] + rw [splits_iff_card_roots, ← nthRoots, IsPrimitiveRoot.card_nthRoots_one h, natDegree_X_pow_sub_C] set_option linter.uppercaseLean3 false in #align polynomial.X_pow_sub_one_splits Polynomial.X_pow_sub_one_splits diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean index 32185a7304895..1a07077def6dc 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean @@ -113,7 +113,7 @@ theorem roots_cyclotomic_nodup [NeZero (n : R)] : (cyclotomic n R).roots.Nodup : rw [mem_roots <| cyclotomic_ne_zero n R, isRoot_cyclotomic_iff] at hζ refine' Multiset.nodup_of_le (roots.le_of_dvd (X_pow_sub_C_ne_zero (NeZero.pos_of_neZero_natCast R) 1) <| - cyclotomic.dvd_X_pow_sub_one n R) hζ.nthRoots_nodup + cyclotomic.dvd_X_pow_sub_one n R) hζ.nthRoots_one_nodup #align polynomial.roots_cyclotomic_nodup Polynomial.roots_cyclotomic_nodup theorem cyclotomic.roots_to_finset_eq_primitiveRoots [NeZero (n : R)] : diff --git a/Mathlib/RingTheory/RootsOfUnity/Basic.lean b/Mathlib/RingTheory/RootsOfUnity/Basic.lean index 52fc80de2390f..32f9c2555c891 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Basic.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Basic.lean @@ -407,6 +407,12 @@ theorem coe_units_iff {ζ : Mˣ} : IsPrimitiveRoot (ζ : M) k ↔ IsPrimitiveRoo simp only [iff_def, Units.ext_iff, Units.val_pow_eq_pow_val, Units.val_one] #align is_primitive_root.coe_units_iff IsPrimitiveRoot.coe_units_iff +lemma isUnit_unit {ζ : M} {n} (hn) (hζ : IsPrimitiveRoot ζ n) : + IsPrimitiveRoot (hζ.isUnit hn).unit n := coe_units_iff.mp hζ + +lemma isUnit_unit' {ζ : G} {n} (hn) (hζ : IsPrimitiveRoot ζ n) : + IsPrimitiveRoot (hζ.isUnit hn).unit' n := coe_units_iff.mp hζ + -- Porting note `variable` above already contains `(h : IsPrimitiveRoot ζ k)` theorem pow_of_coprime (i : ℕ) (hi : i.Coprime k) : IsPrimitiveRoot (ζ ^ i) k := by by_cases h0 : k = 0 @@ -494,6 +500,16 @@ theorem pow {n : ℕ} {a b : ℕ} (hn : 0 < n) (h : IsPrimitiveRoot ζ n) (hprod exact h.dvd_of_pow_eq_one _ hl #align is_primitive_root.pow IsPrimitiveRoot.pow +lemma injOn_pow {n : ℕ} {ζ : M} (hζ : IsPrimitiveRoot ζ n) : + Set.InjOn (ζ ^ ·) (Finset.range n) := by + obtain (rfl|hn) := n.eq_zero_or_pos; · simp + intros i hi j hj e + rw [Finset.coe_range, Set.mem_Iio] at hi hj + have : (hζ.isUnit hn).unit ^ i = (hζ.isUnit hn).unit ^ j := Units.ext (by simpa using e) + rw [pow_inj_mod, ← orderOf_injective ⟨⟨Units.val, Units.val_one⟩, Units.val_mul⟩ + Units.ext (hζ.isUnit hn).unit] at this + simpa [← hζ.eq_orderOf, Nat.mod_eq_of_lt, hi, hj] using this + section Maps open Function @@ -543,6 +559,17 @@ protected theorem ne_zero [Nontrivial M₀] {ζ : M₀} (h : IsPrimitiveRoot ζ end CommMonoidWithZero +section CancelCommMonoidWithZero + +variable {M₀ : Type*} [CancelCommMonoidWithZero M₀] + +lemma injOn_pow_mul {n : ℕ} {ζ : M₀} (hζ : IsPrimitiveRoot ζ n) + {α : M₀} (hα : α ≠ 0) : + Set.InjOn (ζ ^ · * α) (Finset.range n) := fun i hi j hj e ↦ + hζ.injOn_pow hi hj (by simpa [mul_eq_mul_right_iff, or_iff_left hα] using e) + +end CancelCommMonoidWithZero + section DivisionCommMonoid variable {ζ : G} @@ -754,6 +781,33 @@ theorem zpowers_eq {k : ℕ+} {ζ : Rˣ} (h : IsPrimitiveRoot ζ k) : _ = Fintype.card (Subgroup.zpowers ζ) := Fintype.card_congr h.zmodEquivZPowers.toEquiv #align is_primitive_root.zpowers_eq IsPrimitiveRoot.zpowers_eq +lemma map_rootsOfUnity {S F} [CommRing S] [IsDomain S] [MonoidHomClass F R S] + {ζ : R} {n : ℕ+} (hζ : IsPrimitiveRoot ζ n) {f : F} (hf : Function.Injective f) : + (rootsOfUnity n R).map (Units.map f) = rootsOfUnity n S := by + letI : CommMonoid Sˣ := inferInstance + replace hζ := hζ.isUnit_unit n.2 + rw [← hζ.zpowers_eq, + ← (hζ.map_of_injective (Units.map_injective (f := (f : R →* S)) hf)).zpowers_eq, + MonoidHom.map_zpowers] + +/-- If `R` contains a `n`-th primitive root, and `S/R` is a ring extension, +then the `n`-th roots of unity in `R` and `S` are isomorphic. +Also see `IsPrimitiveRoot.map_rootsOfUnity` for the equality as `Subgroup Sˣ`. -/ +@[simps! (config := .lemmasOnly) apply_coe_val apply_coe_inv_val] +noncomputable +def _root_.rootsOfUnityEquivOfPrimitiveRoots {S F} [CommRing S] [IsDomain S] [MonoidHomClass F R S] + {n : ℕ+} {f : F} (hf : Function.Injective f) (hζ : (primitiveRoots n R).Nonempty) : + (rootsOfUnity n R) ≃* rootsOfUnity n S := + (Subgroup.equivMapOfInjective _ _ (Units.map_injective hf)).trans (MulEquiv.subgroupCongr + (((mem_primitiveRoots (k := n) n.2).mp hζ.choose_spec).map_rootsOfUnity hf)) + +lemma _root_.rootsOfUnityEquivOfPrimitiveRoots_symm_apply + {S F} [CommRing S] [IsDomain S] [MonoidHomClass F R S] + {n : ℕ+} {f : F} (hf : Function.Injective f) (hζ : (primitiveRoots n R).Nonempty) (η) : + f ((rootsOfUnityEquivOfPrimitiveRoots hf hζ).symm η : Rˣ) = (η : Sˣ) := by + obtain ⟨ε, rfl⟩ := (rootsOfUnityEquivOfPrimitiveRoots hf hζ).surjective η + rw [MulEquiv.symm_apply_apply, val_rootsOfUnityEquivOfPrimitiveRoots_apply_coe] + -- Porting note: rephrased the next few lemmas to avoid `∃ (Prop)` theorem eq_pow_of_mem_rootsOfUnity {k : ℕ+} {ζ ξ : Rˣ} (h : IsPrimitiveRoot ζ k) (hξ : ξ ∈ rootsOfUnity k R) : ∃ (i : ℕ), i < k ∧ ζ ^ i = ξ := by @@ -799,6 +853,35 @@ theorem isPrimitiveRoot_iff {k : ℕ} {ζ ξ : R} (h : IsPrimitiveRoot ζ k) (h0 · rintro ⟨i, -, hi, rfl⟩; exact h.pow_of_coprime i hi #align is_primitive_root.is_primitive_root_iff IsPrimitiveRoot.isPrimitiveRoot_iff +theorem nthRoots_eq {n : ℕ} {ζ : R} (hζ : IsPrimitiveRoot ζ n) + {α a : R} (e : α ^ n = a) : + nthRoots n a = (Multiset.range n).map (ζ ^ · * α) := by + obtain (rfl|hn) := n.eq_zero_or_pos; · simp + by_cases hα : α = 0 + · rw [hα, zero_pow hn] at e + simp only [hα, e.symm, nthRoots_zero_right, mul_zero, + Finset.range_val, Multiset.map_const', Multiset.card_range] + classical + symm; apply Multiset.eq_of_le_of_card_le + · rw [← Finset.range_val, + ← Finset.image_val_of_injOn (hζ.injOn_pow_mul hα), Finset.val_le_iff_val_subset] + intro x hx + simp only [Finset.image_val, Finset.range_val, Multiset.mem_dedup, Multiset.mem_map, + Multiset.mem_range] at hx + obtain ⟨m, _, rfl⟩ := hx + rw [mem_nthRoots hn, mul_pow, e, ← pow_mul, mul_comm m, + pow_mul, hζ.pow_eq_one, one_pow, one_mul] + · simpa only [Multiset.card_map, Multiset.card_range] using card_nthRoots n a + +theorem card_nthRoots {n : ℕ} {ζ : R} (hζ : IsPrimitiveRoot ζ n) (a : R) : + Multiset.card (nthRoots n a) = if ∃ α, α ^ n = a then n else 0 := by + split_ifs with h + · obtain ⟨α, hα⟩ := h + rw [nthRoots_eq hζ hα, Multiset.card_map, Multiset.card_range] + · obtain (rfl|hn) := n.eq_zero_or_pos; · simp + push_neg at h + simpa only [Multiset.card_eq_zero, Multiset.eq_zero_iff_forall_not_mem, mem_nthRoots hn] + theorem card_rootsOfUnity' {n : ℕ+} (h : IsPrimitiveRoot ζ n) : Fintype.card (rootsOfUnity n R) = n := by let e := h.zmodEquivZPowers @@ -819,51 +902,34 @@ theorem card_rootsOfUnity {ζ : R} {n : ℕ+} (h : IsPrimitiveRoot ζ n) : /-- The cardinality of the multiset `nthRoots ↑n (1 : R)` is `n` if there is a primitive root of unity in `R`. -/ -nonrec theorem card_nthRoots {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : - Multiset.card (nthRoots n (1 : R)) = n := by - rcases Nat.eq_zero_or_pos n with hzero | hpos - · simp only [hzero, Multiset.card_zero, nthRoots_zero] - rw [eq_iff_le_not_lt] - use card_nthRoots n 1 - · rw [not_lt] - have hcard : - Fintype.card { x // x ∈ nthRoots n (1 : R) } ≤ Multiset.card (nthRoots n (1 : R)).attach := - Multiset.card_le_card (Multiset.dedup_le _) - rw [Multiset.card_attach] at hcard - rw [← PNat.toPNat'_coe hpos] at hcard h ⊢ - set m := Nat.toPNat' n - rw [← Fintype.card_congr (rootsOfUnityEquivNthRoots R m), card_rootsOfUnity h] at hcard - exact hcard -#align is_primitive_root.card_nth_roots IsPrimitiveRoot.card_nthRoots +theorem card_nthRoots_one {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : + Multiset.card (nthRoots n (1 : R)) = n := by rw [card_nthRoots h, if_pos ⟨ζ, h.pow_eq_one⟩] +#align is_primitive_root.card_nth_roots IsPrimitiveRoot.card_nthRoots_one + +theorem nthRoots_nodup {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) {a : R} (ha : a ≠ 0) : + (nthRoots n a).Nodup := by + obtain (rfl|hn) := n.eq_zero_or_pos; · simp + by_cases h : ∃ α, α ^ n = a + · obtain ⟨α, hα⟩ := h + by_cases hα' : α = 0 + · exact (ha (by rwa [hα', zero_pow hn, eq_comm] at hα)).elim + rw [nthRoots_eq h hα, Multiset.nodup_map_iff_inj_on (Multiset.nodup_range n)] + exact h.injOn_pow_mul hα' + · suffices nthRoots n a = 0 by simp [this] + push_neg at h + simpa only [Multiset.card_eq_zero, Multiset.eq_zero_iff_forall_not_mem, mem_nthRoots hn] /-- The multiset `nthRoots ↑n (1 : R)` has no repeated elements if there is a primitive root of unity in `R`. -/ -theorem nthRoots_nodup {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : (nthRoots n (1 : R)).Nodup := by - rcases Nat.eq_zero_or_pos n with hzero | hpos - · simp only [hzero, Multiset.nodup_zero, nthRoots_zero] - apply (Multiset.dedup_eq_self (α := R)).1 - rw [eq_iff_le_not_lt] - constructor - · exact Multiset.dedup_le (nthRoots n (1 : R)) - · by_contra ha - replace ha := Multiset.card_lt_card ha - rw [card_nthRoots h] at ha - have hrw : Multiset.card (nthRoots n (1 : R)).dedup = - Fintype.card { x // x ∈ nthRoots n (1 : R) } := by - set fs := (⟨(nthRoots n (1 : R)).dedup, Multiset.nodup_dedup _⟩ : Finset R) - rw [← Finset.card_mk, Fintype.card_of_subtype fs _] - intro x - simp only [Multiset.mem_dedup, Finset.mem_mk] - rw [← PNat.toPNat'_coe hpos] at h hrw ha - set m := Nat.toPNat' n - rw [hrw, ← Fintype.card_congr (rootsOfUnityEquivNthRoots R m), card_rootsOfUnity h] at ha - exact Nat.lt_asymm ha ha -#align is_primitive_root.nth_roots_nodup IsPrimitiveRoot.nthRoots_nodup +theorem nthRoots_one_nodup {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : + (nthRoots n (1 : R)).Nodup := + h.nthRoots_nodup one_ne_zero +#align is_primitive_root.nth_roots_nodup IsPrimitiveRoot.nthRoots_one_nodup @[simp] theorem card_nthRootsFinset {ζ : R} {n : ℕ} (h : IsPrimitiveRoot ζ n) : (nthRootsFinset n R).card = n := by - rw [nthRootsFinset, ← Multiset.toFinset_eq (nthRoots_nodup h), card_mk, h.card_nthRoots] + rw [nthRootsFinset, ← Multiset.toFinset_eq (nthRoots_one_nodup h), card_mk, h.card_nthRoots_one] #align is_primitive_root.card_nth_roots_finset IsPrimitiveRoot.card_nthRootsFinset open scoped Nat @@ -905,7 +971,7 @@ theorem nthRoots_one_eq_biUnion_primitiveRoots' {ζ : R} {n : ℕ+} (h : IsPrimi symm apply Finset.eq_of_subset_of_card_le · intro x - simp only [nthRootsFinset, ← Multiset.toFinset_eq (nthRoots_nodup h), exists_prop, + simp only [nthRootsFinset, ← Multiset.toFinset_eq (nthRoots_one_nodup h), exists_prop, Finset.mem_biUnion, Finset.mem_filter, Finset.mem_range, mem_nthRoots, Finset.mem_mk, Nat.mem_divisors, and_true_iff, Ne.def, PNat.ne_zero, PNat.pos, not_false_iff] rintro ⟨a, ⟨d, hd⟩, ha⟩ diff --git a/docs/references.bib b/docs/references.bib index cd20bf7e61a75..579d89c03a7e6 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -2469,6 +2469,18 @@ @Book{ seligman1967 mrreviewer = {R. E. Block} } +@Book{ serge_lang_algebra, + author = {Serge Lang}, + title = {Algebra}, + isbn = {978-0-387-95385-4}, + year = {2002}, + publisher = {Springer New York, NY}, + language = {English}, + doi = {10.1007/978-1-4613-0041-0}, + edition = {3}, + series = {Graduate Texts in Mathematics} +} + @Article{ serre1951, author = {Serre, Jean-Pierre}, title = {Homologie singuli\`ere des espaces fibr\'{e}s. From 3694e27d9d9a84a7fc36ef5838cc33183af00403 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 30 Dec 2023 21:45:05 +0000 Subject: [PATCH 285/353] chore(*): drop `$`/`<|` before `fun` (#9361) Subset of #9319 --- Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean | 8 ++++---- Mathlib/Algebra/Algebra/Subalgebra/Basic.lean | 2 +- Mathlib/Algebra/Associated.lean | 10 +++++----- Mathlib/Algebra/BigOperators/Associated.lean | 2 +- Mathlib/Algebra/BigOperators/Basic.lean | 2 +- Mathlib/Algebra/Category/GroupCat/Colimits.lean | 14 +++++++------- Mathlib/Algebra/Category/GroupCat/Kernels.lean | 2 +- .../Algebra/Category/ModuleCat/ChangeOfRings.lean | 2 +- Mathlib/Algebra/Category/MonCat/Colimits.lean | 8 ++++---- Mathlib/Algebra/Category/Ring/Colimits.lean | 10 +++++----- Mathlib/Algebra/GCDMonoid/Finset.lean | 2 +- Mathlib/Algebra/GCDMonoid/Multiset.lean | 8 ++++---- Mathlib/Algebra/GradedMonoid.lean | 2 +- Mathlib/Algebra/Group/Equiv/Basic.lean | 2 +- Mathlib/Algebra/Group/Pi.lean | 4 ++-- Mathlib/Algebra/GroupWithZero/Basic.lean | 2 +- Mathlib/Algebra/GroupWithZero/InjSurj.lean | 2 +- Mathlib/Algebra/Module/Submodule/Pointwise.lean | 2 +- Mathlib/Algebra/MonoidAlgebra/Basic.lean | 4 ++-- Mathlib/Algebra/Order/Module/OrderedSMul.lean | 2 +- Mathlib/Algebra/Order/Monovary.lean | 10 +++++----- Mathlib/Algebra/Order/Ring/WithTop.lean | 2 +- Mathlib/Algebra/Ring/CentroidHom.lean | 6 +++--- Mathlib/Algebra/RingQuot.lean | 4 ++-- Mathlib/Algebra/SMulWithZero.lean | 2 +- Mathlib/AlgebraicTopology/SimplexCategory.lean | 4 ++-- Mathlib/AlgebraicTopology/SimplicialObject.lean | 6 +++--- Mathlib/Analysis/Calculus/ContDiff/Basic.lean | 2 +- Mathlib/Analysis/Calculus/MeanValue.lean | 2 +- Mathlib/Analysis/Complex/CauchyIntegral.lean | 2 +- Mathlib/Analysis/Matrix.lean | 2 +- Mathlib/Analysis/Normed/Field/InfiniteSum.lean | 2 +- Mathlib/Analysis/SpecialFunctions/Bernstein.lean | 2 +- Mathlib/CategoryTheory/Extensive.lean | 4 ++-- Mathlib/CategoryTheory/Limits/VanKampen.lean | 10 +++++----- Mathlib/CategoryTheory/PathCategory.lean | 2 +- Mathlib/Combinatorics/Partition.lean | 2 +- Mathlib/Combinatorics/Pigeonhole.lean | 2 +- Mathlib/Combinatorics/SetFamily/FourFunctions.lean | 2 +- Mathlib/Combinatorics/SetFamily/Shatter.lean | 8 ++++---- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 2 +- Mathlib/Computability/AkraBazzi/AkraBazzi.lean | 2 +- Mathlib/Computability/Primrec.lean | 2 +- Mathlib/Control/EquivFunctor.lean | 4 ++-- Mathlib/Control/Functor.lean | 2 +- Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean | 2 +- Mathlib/Data/Finmap.lean | 6 +++--- Mathlib/Data/Finset/Basic.lean | 2 +- Mathlib/Data/Finset/Powerset.lean | 2 +- Mathlib/Data/Finsupp/Multiset.lean | 2 +- Mathlib/Data/Fintype/Basic.lean | 2 +- Mathlib/Data/Fintype/Pi.lean | 2 +- Mathlib/Data/FunLike/Equiv.lean | 2 +- Mathlib/Data/List/Defs.lean | 2 +- Mathlib/Data/List/Forall2.lean | 2 +- Mathlib/Data/List/Prime.lean | 2 +- Mathlib/Data/List/Sublists.lean | 4 ++-- Mathlib/Data/Matrix/Basic.lean | 2 +- Mathlib/Data/Matroid/Basic.lean | 2 +- Mathlib/Data/Matroid/IndepAxioms.lean | 2 +- Mathlib/Data/Multiset/Antidiagonal.lean | 8 ++++---- Mathlib/Data/Multiset/Basic.lean | 12 ++++++------ Mathlib/Data/Multiset/Nodup.lean | 2 +- Mathlib/Data/Nat/Digits.lean | 2 +- Mathlib/Data/PFun.lean | 4 ++-- Mathlib/Data/Real/CauSeq.lean | 2 +- Mathlib/Data/Real/EReal.lean | 2 +- Mathlib/Data/Real/Hyperreal.lean | 4 ++-- Mathlib/Data/Semiquot.lean | 2 +- Mathlib/Data/Set/Basic.lean | 6 +++--- Mathlib/Data/Set/Finite.lean | 2 +- Mathlib/Data/Set/Function.lean | 6 +++--- Mathlib/Data/Set/Lattice.lean | 4 ++-- Mathlib/Data/Set/List.lean | 2 +- Mathlib/Data/Set/Prod.lean | 2 +- Mathlib/Data/Sigma/Lex.lean | 4 ++-- Mathlib/Data/TypeVec.lean | 2 +- Mathlib/FieldTheory/Fixed.lean | 2 +- Mathlib/FieldTheory/IsSepClosed.lean | 2 +- Mathlib/FieldTheory/Perfect.lean | 4 ++-- Mathlib/FieldTheory/SeparableDegree.lean | 6 +++--- .../Euclidean/Inversion/ImageHyperplane.lean | 2 +- Mathlib/Geometry/Euclidean/PerpBisector.lean | 2 +- Mathlib/GroupTheory/Congruence.lean | 2 +- Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean | 2 +- Mathlib/GroupTheory/OrderOfElement.lean | 2 +- Mathlib/GroupTheory/Perm/Basic.lean | 4 ++-- Mathlib/GroupTheory/PushoutI.lean | 2 +- Mathlib/GroupTheory/Transfer.lean | 2 +- Mathlib/Init/Data/List/Instances.lean | 2 +- Mathlib/Lean/Expr/Traverse.lean | 2 +- Mathlib/LinearAlgebra/BilinearForm/Basic.lean | 6 +++--- .../LinearAlgebra/CliffordAlgebra/Conjugation.lean | 4 ++-- Mathlib/LinearAlgebra/DFinsupp.lean | 2 +- Mathlib/LinearAlgebra/Eigenspace/Basic.lean | 2 +- Mathlib/LinearAlgebra/InvariantBasisNumber.lean | 2 +- Mathlib/LinearAlgebra/Matrix/PosDef.lean | 2 +- Mathlib/LinearAlgebra/Matrix/Spectrum.lean | 2 +- Mathlib/LinearAlgebra/QuadraticForm/Basic.lean | 8 ++++---- Mathlib/LinearAlgebra/QuadraticForm/Prod.lean | 2 +- Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean | 2 +- .../TensorProduct/RightExactness.lean | 8 ++++---- Mathlib/LinearAlgebra/TensorProduct/Tower.lean | 6 +++--- Mathlib/Logic/Function/Basic.lean | 4 ++-- Mathlib/Logic/Relator.lean | 6 +++--- Mathlib/Mathport/Notation.lean | 2 +- Mathlib/MeasureTheory/Function/AEEqFun.lean | 2 +- Mathlib/MeasureTheory/Function/LpSpace.lean | 2 +- Mathlib/MeasureTheory/Group/Measure.lean | 4 ++-- .../MeasureTheory/Integral/IntegralEqImproper.lean | 2 +- .../MeasureTheory/Integral/MeanInequalities.lean | 2 +- Mathlib/NumberTheory/BernoulliPolynomials.lean | 2 +- Mathlib/NumberTheory/NumberField/Embeddings.lean | 2 +- Mathlib/NumberTheory/Padics/PadicNumbers.lean | 2 +- Mathlib/NumberTheory/SmoothNumbers.lean | 6 +++--- Mathlib/NumberTheory/SumPrimeReciprocals.lean | 2 +- Mathlib/Order/Closure.lean | 2 +- Mathlib/Order/CompleteLattice.lean | 6 +++--- Mathlib/Order/Filter/Bases.lean | 6 +++--- Mathlib/Order/Filter/Basic.lean | 6 +++--- Mathlib/Order/Filter/Germ.lean | 8 ++++---- Mathlib/Order/Iterate.lean | 6 +++--- Mathlib/Order/Lattice.lean | 12 ++++++------ Mathlib/Order/Minimal.lean | 4 ++-- Mathlib/Order/OmegaCompletePartialOrder.lean | 2 +- Mathlib/Order/RelSeries.lean | 2 +- Mathlib/Order/Sublattice.lean | 4 ++-- Mathlib/Order/SupClosed.lean | 6 +++--- Mathlib/Order/WellFoundedSet.lean | 2 +- Mathlib/Probability/Kernel/Basic.lean | 2 +- Mathlib/Probability/Kernel/Disintegration.lean | 2 +- .../GroupCohomology/Hilbert90.lean | 2 +- Mathlib/RingTheory/DedekindDomain/Different.lean | 2 +- Mathlib/RingTheory/TensorProduct.lean | 2 +- Mathlib/SetTheory/Game/PGame.lean | 2 +- Mathlib/Tactic/ApplyCongr.lean | 2 +- Mathlib/Tactic/Linarith/Datatypes.lean | 2 +- Mathlib/Tactic/Linarith/Elimination.lean | 2 +- Mathlib/Tactic/Linarith/Parsing.lean | 2 +- Mathlib/Tactic/Linarith/Preprocessing.lean | 4 ++-- Mathlib/Tactic/ReduceModChar.lean | 2 +- Mathlib/Tactic/ToAdditive.lean | 2 +- Mathlib/Tactic/WLOG.lean | 2 +- Mathlib/Testing/SlimCheck/Functions.lean | 2 +- Mathlib/Testing/SlimCheck/Testable.lean | 2 +- Mathlib/Topology/AlexandrovDiscrete.lean | 4 ++-- Mathlib/Topology/Algebra/GroupWithZero.lean | 2 +- Mathlib/Topology/Algebra/Order/Compact.lean | 6 +++--- Mathlib/Topology/Algebra/Order/Floor.lean | 8 ++++---- Mathlib/Topology/Algebra/UniformGroup.lean | 2 +- Mathlib/Topology/Basic.lean | 2 +- Mathlib/Topology/Category/TopCat/Limits/Basic.lean | 2 +- Mathlib/Topology/Compactness/Compact.lean | 2 +- Mathlib/Topology/Connected/LocallyConnected.lean | 2 +- Mathlib/Topology/Constructions.lean | 2 +- Mathlib/Topology/ContinuousOn.lean | 2 +- Mathlib/Topology/EMetricSpace/Basic.lean | 6 +++--- Mathlib/Topology/Homeomorph.lean | 2 +- Mathlib/Topology/LocallyConstant/Basic.lean | 2 +- Mathlib/Topology/MetricSpace/Algebra.lean | 2 +- Mathlib/Topology/MetricSpace/Basic.lean | 2 +- Mathlib/Topology/MetricSpace/Dilation.lean | 2 +- Mathlib/Topology/NoetherianSpace.lean | 2 +- Mathlib/Topology/Order/ScottTopology.lean | 2 +- Mathlib/Topology/PartialHomeomorph.lean | 2 +- Mathlib/Topology/UniformSpace/Basic.lean | 2 +- Mathlib/Topology/UniformSpace/Equiv.lean | 2 +- .../Topology/UniformSpace/UniformConvergence.lean | 6 +++--- Mathlib/Util/Delaborators.lean | 2 +- test/Traversable.lean | 2 +- 170 files changed, 285 insertions(+), 285 deletions(-) diff --git a/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean b/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean index 9f0d12dc92aab..ef4d357684623 100644 --- a/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean +++ b/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean @@ -570,16 +570,16 @@ lemma adjoin_induction' {s : Set A} {p : adjoin R s → Prop} (a : adjoin R s) (Hs : ∀ x (h : x ∈ s), p ⟨x, subset_adjoin R h⟩) (Hadd : ∀ x y, p x → p y → p (x + y)) (H0 : p 0) (Hmul : ∀ x y, p x → p y → p (x * y)) (Hsmul : ∀ (r : R) x, p x → p (r • x)) : p a := - Subtype.recOn a <| fun b hb => by + Subtype.recOn a fun b hb => by refine Exists.elim ?_ (fun (hb : b ∈ adjoin R s) (hc : p ⟨b, hb⟩) => hc) apply adjoin_induction hb · exact fun x hx => ⟨subset_adjoin R hx, Hs x hx⟩ - · exact fun x y hx hy => Exists.elim hx <| fun hx' hx => Exists.elim hy <| fun hy' hy => + · exact fun x y hx hy => Exists.elim hx fun hx' hx => Exists.elim hy fun hy' hy => ⟨add_mem hx' hy', Hadd _ _ hx hy⟩ · exact ⟨_, H0⟩ - · exact fun x y hx hy => Exists.elim hx <| fun hx' hx => Exists.elim hy <| fun hy' hy => + · exact fun x y hx hy => Exists.elim hx fun hx' hx => Exists.elim hy fun hy' hy => ⟨mul_mem hx' hy', Hmul _ _ hx hy⟩ - · exact fun r x hx => Exists.elim hx <| fun hx' hx => + · exact fun r x hx => Exists.elim hx fun hx' hx => ⟨SMulMemClass.smul_mem r hx', Hsmul r _ hx⟩ protected theorem gc : GaloisConnection (adjoin R : Set A → NonUnitalSubalgebra R A) (↑) := diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean index 1a536351ecdc3..926ec1c367fc0 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean @@ -338,7 +338,7 @@ def toSubmodule : Subalgebra R A ↪o Submodule R A where carrier := S smul_mem' := fun c {x} hx ↦ (Algebra.smul_def c x).symm ▸ mul_mem (S.range_le ⟨c, rfl⟩) hx } - inj' := fun _ _ h ↦ ext <| fun x ↦ SetLike.ext_iff.mp h x } + inj' := fun _ _ h ↦ ext fun x ↦ SetLike.ext_iff.mp h x } map_rel_iff' := SetLike.coe_subset_coe.symm.trans SetLike.coe_subset_coe #align subalgebra.to_submodule Subalgebra.toSubmodule diff --git a/Mathlib/Algebra/Associated.lean b/Mathlib/Algebra/Associated.lean index 278d05db08d66..680c895bef388 100644 --- a/Mathlib/Algebra/Associated.lean +++ b/Mathlib/Algebra/Associated.lean @@ -849,13 +849,13 @@ theorem mk_mul_mk {x y : α} : Associates.mk x * Associates.mk y = Associates.mk instance instCommMonoid : CommMonoid (Associates α) where one := 1 mul := (· * ·) - mul_one a' := Quotient.inductionOn a' <| fun a => show ⟦a * 1⟧ = ⟦a⟧ by simp - one_mul a' := Quotient.inductionOn a' <| fun a => show ⟦1 * a⟧ = ⟦a⟧ by simp + mul_one a' := Quotient.inductionOn a' fun a => show ⟦a * 1⟧ = ⟦a⟧ by simp + one_mul a' := Quotient.inductionOn a' fun a => show ⟦1 * a⟧ = ⟦a⟧ by simp mul_assoc a' b' c' := - Quotient.inductionOn₃ a' b' c' <| fun a b c => + Quotient.inductionOn₃ a' b' c' fun a b c => show ⟦a * b * c⟧ = ⟦a * (b * c)⟧ by rw [mul_assoc] mul_comm a' b' := - Quotient.inductionOn₂ a' b' <| fun a b => show ⟦a * b⟧ = ⟦b * a⟧ by rw [mul_comm] + Quotient.inductionOn₂ a' b' fun a b => show ⟦a * b⟧ = ⟦b * a⟧ by rw [mul_comm] instance instPreorder : Preorder (Associates α) where le := Dvd.dvd @@ -890,7 +890,7 @@ theorem dvd_eq_le : ((· ∣ ·) : Associates α → Associates α → Prop) = ( theorem mul_eq_one_iff {x y : Associates α} : x * y = 1 ↔ x = 1 ∧ y = 1 := Iff.intro - (Quotient.inductionOn₂ x y <| fun a b h => + (Quotient.inductionOn₂ x y fun a b h => have : a * b ~ᵤ 1 := Quotient.exact h ⟨Quotient.sound <| associated_one_of_associated_mul_one this, Quotient.sound <| associated_one_of_associated_mul_one <| by rwa [mul_comm] at this⟩) diff --git a/Mathlib/Algebra/BigOperators/Associated.lean b/Mathlib/Algebra/BigOperators/Associated.lean index 6feb4b61756c4..962ceffbfdab8 100644 --- a/Mathlib/Algebra/BigOperators/Associated.lean +++ b/Mathlib/Algebra/BigOperators/Associated.lean @@ -134,7 +134,7 @@ theorem finset_prod_mk {p : Finset β} {f : β → α} : (∏ i in p, Associates.mk (f i)) = Associates.mk (∏ i in p, f i) := by -- Porting note: added have : (fun i => Associates.mk (f i)) = Associates.mk ∘ f := - funext <| fun x => Function.comp_apply + funext fun x => Function.comp_apply rw [Finset.prod_eq_multiset_prod, this, ← Multiset.map_map, prod_mk, ← Finset.prod_eq_multiset_prod] #align associates.finset_prod_mk Associates.finset_prod_mk diff --git a/Mathlib/Algebra/BigOperators/Basic.lean b/Mathlib/Algebra/BigOperators/Basic.lean index 9a4a252031c9c..5135ec83a96d8 100644 --- a/Mathlib/Algebra/BigOperators/Basic.lean +++ b/Mathlib/Algebra/BigOperators/Basic.lean @@ -666,7 +666,7 @@ lemma prod_fiberwise_of_maps_to' {g : ι → κ} (h : ∀ i ∈ s, g i ∈ t) (f ∏ j in t, ∏ _i in s.filter fun i ↦ g i = j, f j = ∏ i in s, f (g i) := by calc _ = ∏ y in t, ∏ x in s.filter fun x ↦ g x = y, f (g x) := - prod_congr rfl $ fun y _ ↦ prod_congr rfl fun x hx ↦ by rw [(mem_filter.1 hx).2] + prod_congr rfl fun y _ ↦ prod_congr rfl fun x hx ↦ by rw [(mem_filter.1 hx).2] _ = _ := prod_fiberwise_of_maps_to h _ variable [Fintype κ] diff --git a/Mathlib/Algebra/Category/GroupCat/Colimits.lean b/Mathlib/Algebra/Category/GroupCat/Colimits.lean index 89441a696195c..8a8b7e6c38c80 100644 --- a/Mathlib/Algebra/Category/GroupCat/Colimits.lean +++ b/Mathlib/Algebra/Category/GroupCat/Colimits.lean @@ -111,13 +111,13 @@ def ColimitType : Type max u v w := instance : AddCommGroup (ColimitType.{w} F) where zero := Quotient.mk _ zero neg := Quotient.map neg Relation.neg_1 - add := Quotient.map₂ add <| fun x x' rx y y' ry => + add := Quotient.map₂ add fun x x' rx y y' ry => Setoid.trans (Relation.add_1 _ _ y rx) (Relation.add_2 x' _ _ ry) - zero_add := Quotient.ind <| fun _ => Quotient.sound <| Relation.zero_add _ - add_zero := Quotient.ind <| fun _ => Quotient.sound <| Relation.add_zero _ - add_left_neg := Quotient.ind <| fun _ => Quotient.sound <| Relation.add_left_neg _ - add_comm := Quotient.ind₂ <| fun _ _ => Quotient.sound <| Relation.add_comm _ _ - add_assoc := Quotient.ind <| fun _ => Quotient.ind₂ <| fun _ _ => + zero_add := Quotient.ind fun _ => Quotient.sound <| Relation.zero_add _ + add_zero := Quotient.ind fun _ => Quotient.sound <| Relation.add_zero _ + add_left_neg := Quotient.ind fun _ => Quotient.sound <| Relation.add_left_neg _ + add_comm := Quotient.ind₂ fun _ _ => Quotient.sound <| Relation.add_comm _ _ + add_assoc := Quotient.ind fun _ => Quotient.ind₂ fun _ _ => Quotient.sound <| Relation.add_assoc _ _ _ instance ColimitTypeInhabited : Inhabited (ColimitType.{w} F) := ⟨0⟩ @@ -227,7 +227,7 @@ def descMorphism (s : Cocone F) : colimit.{w} F ⟶ s.pt where /-- Evidence that the proposed colimit is the colimit. -/ def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where desc s := descMorphism F s - uniq s m w := FunLike.ext _ _ <| fun x => Quot.inductionOn x fun x => by + uniq s m w := FunLike.ext _ _ fun x => Quot.inductionOn x fun x => by change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _ induction x using Prequotient.recOn with | of j x => exact FunLike.congr_fun (w j) x diff --git a/Mathlib/Algebra/Category/GroupCat/Kernels.lean b/Mathlib/Algebra/Category/GroupCat/Kernels.lean index 48087ae001490..6c31088d5667c 100644 --- a/Mathlib/Algebra/Category/GroupCat/Kernels.lean +++ b/Mathlib/Algebra/Category/GroupCat/Kernels.lean @@ -26,7 +26,7 @@ def kernelCone : KernelFork f := /-- The kernel of a group homomorphism is a kernel in the categorical sense. -/ def kernelIsLimit : IsLimit <| kernelCone f := Fork.IsLimit.mk _ - (fun s => (by exact Fork.ι s : _ →+ G).codRestrict _ <| fun c => f.mem_ker.mpr <| + (fun s => (by exact Fork.ι s : _ →+ G).codRestrict _ fun c => f.mem_ker.mpr <| by exact FunLike.congr_fun s.condition c) (fun _ => by rfl) (fun _ _ h => ext fun x => Subtype.ext_iff_val.mpr <| by exact FunLike.congr_fun h x) diff --git a/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean b/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean index 1aeea9fc159b1..327de68231ce1 100644 --- a/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean +++ b/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean @@ -129,7 +129,7 @@ instance (priority := 100) sMulCommClass_mk {R : Type u₁} {S : Type u₂} [Rin haveI : SMul R M := (RestrictScalars.obj' f (ModuleCat.mk M)).isModule.toSMul SMulCommClass R S M := @SMulCommClass.mk R S M (_) _ - <| fun r s m => (by simp [← mul_smul, mul_comm] : f r • s • m = s • f r • m) + fun r s m => (by simp [← mul_smul, mul_comm] : f r • s • m = s • f r • m) #align category_theory.Module.smul_comm_class_mk ModuleCat.sMulCommClass_mk /-- Semilinear maps `M →ₛₗ[f] N` identify to diff --git a/Mathlib/Algebra/Category/MonCat/Colimits.lean b/Mathlib/Algebra/Category/MonCat/Colimits.lean index 09fbf9db1327e..c5cb673d113c9 100644 --- a/Mathlib/Algebra/Category/MonCat/Colimits.lean +++ b/Mathlib/Algebra/Category/MonCat/Colimits.lean @@ -132,11 +132,11 @@ instance : Inhabited (ColimitType F) := by instance monoidColimitType : Monoid (ColimitType F) where one := Quotient.mk _ one - mul := Quotient.map₂ mul <| fun x x' rx y y' ry => + mul := Quotient.map₂ mul fun x x' rx y y' ry => Setoid.trans (Relation.mul_1 _ _ y rx) (Relation.mul_2 x' _ _ ry) - one_mul := Quotient.ind <| fun _ => Quotient.sound <| Relation.one_mul _ - mul_one := Quotient.ind <| fun _ => Quotient.sound <| Relation.mul_one _ - mul_assoc := Quotient.ind <| fun _ => Quotient.ind₂ <| fun _ _ => + one_mul := Quotient.ind fun _ => Quotient.sound <| Relation.one_mul _ + mul_one := Quotient.ind fun _ => Quotient.sound <| Relation.mul_one _ + mul_assoc := Quotient.ind fun _ => Quotient.ind₂ fun _ _ => Quotient.sound <| Relation.mul_assoc _ _ _ set_option linter.uppercaseLean3 false in #align Mon.colimits.monoid_colimit_type MonCat.Colimits.monoidColimitType diff --git a/Mathlib/Algebra/Category/Ring/Colimits.lean b/Mathlib/Algebra/Category/Ring/Colimits.lean index 74ae83013be3f..eacda8088c946 100644 --- a/Mathlib/Algebra/Category/Ring/Colimits.lean +++ b/Mathlib/Algebra/Category/Ring/Colimits.lean @@ -144,12 +144,12 @@ def ColimitType : Type v := instance ColimitType.AddGroup : AddGroup (ColimitType F) where zero := Quotient.mk _ zero neg := Quotient.map neg Relation.neg_1 - add := Quotient.map₂ add <| fun x x' rx y y' ry => + add := Quotient.map₂ add fun x x' rx y y' ry => Setoid.trans (Relation.add_1 _ _ y rx) (Relation.add_2 x' _ _ ry) - zero_add := Quotient.ind <| fun _ => Quotient.sound <| Relation.zero_add _ - add_zero := Quotient.ind <| fun _ => Quotient.sound <| Relation.add_zero _ - add_left_neg := Quotient.ind <| fun _ => Quotient.sound <| Relation.add_left_neg _ - add_assoc := Quotient.ind <| fun _ => Quotient.ind₂ <| fun _ _ => + zero_add := Quotient.ind fun _ => Quotient.sound <| Relation.zero_add _ + add_zero := Quotient.ind fun _ => Quotient.sound <| Relation.add_zero _ + add_left_neg := Quotient.ind fun _ => Quotient.sound <| Relation.add_left_neg _ + add_assoc := Quotient.ind fun _ => Quotient.ind₂ fun _ _ => Quotient.sound <| Relation.add_assoc _ _ _ -- Porting note : failed to derive `Inhabited` instance diff --git a/Mathlib/Algebra/GCDMonoid/Finset.lean b/Mathlib/Algebra/GCDMonoid/Finset.lean index 24033244491d4..80694ccf7de76 100644 --- a/Mathlib/Algebra/GCDMonoid/Finset.lean +++ b/Mathlib/Algebra/GCDMonoid/Finset.lean @@ -274,7 +274,7 @@ theorem extract_gcd (f : β → α) (hs : s.Nonempty) : · choose g' hg using @gcd_dvd _ _ _ _ s f push_neg at h refine' ⟨fun b ↦ if hb : b ∈ s then g' hb else 0, fun b hb ↦ _, - extract_gcd' f _ h <| fun b hb ↦ _⟩ + extract_gcd' f _ h fun b hb ↦ _⟩ simp only [hb, hg, dite_true] rw [dif_pos hb, hg hb] #align finset.extract_gcd Finset.extract_gcd diff --git a/Mathlib/Algebra/GCDMonoid/Multiset.lean b/Mathlib/Algebra/GCDMonoid/Multiset.lean index dd626c139a82c..65a9e663b2ecb 100644 --- a/Mathlib/Algebra/GCDMonoid/Multiset.lean +++ b/Mathlib/Algebra/GCDMonoid/Multiset.lean @@ -79,7 +79,7 @@ this lower priority to avoid linter complaints about simp-normal form -/ `(Multiset.induction_on s)`, when it should be `Multiset.induction_on s <|`. -/ @[simp 1100] theorem normalize_lcm (s : Multiset α) : normalize s.lcm = s.lcm := - Multiset.induction_on s (by simp) <| fun a s _ ↦ by simp + Multiset.induction_on s (by simp) fun a s _ ↦ by simp #align multiset.normalize_lcm Multiset.normalize_lcm @[simp] @@ -93,7 +93,7 @@ variable [DecidableEq α] @[simp] theorem lcm_dedup (s : Multiset α) : (dedup s).lcm = s.lcm := - Multiset.induction_on s (by simp) <| fun a s IH ↦ by + Multiset.induction_on s (by simp) fun a s IH ↦ by by_cases h : a ∈ s <;> simp [IH, h] unfold lcm rw [← cons_erase h, fold_cons_left, ← lcm_assoc, lcm_same] @@ -167,7 +167,7 @@ theorem gcd_mono {s₁ s₂ : Multiset α} (h : s₁ ⊆ s₂) : s₂.gcd ∣ s this lower priority to avoid linter complaints about simp-normal form -/ @[simp 1100] theorem normalize_gcd (s : Multiset α) : normalize s.gcd = s.gcd := - Multiset.induction_on s (by simp) <| fun a s _ ↦ by simp + Multiset.induction_on s (by simp) fun a s _ ↦ by simp #align multiset.normalize_gcd Multiset.normalize_gcd theorem gcd_eq_zero_iff (s : Multiset α) : s.gcd = 0 ↔ ∀ x : α, x ∈ s → x = 0 := by @@ -196,7 +196,7 @@ variable [DecidableEq α] @[simp] theorem gcd_dedup (s : Multiset α) : (dedup s).gcd = s.gcd := - Multiset.induction_on s (by simp) <| fun a s IH ↦ by + Multiset.induction_on s (by simp) fun a s IH ↦ by by_cases h : a ∈ s <;> simp [IH, h] unfold gcd rw [← cons_erase h, fold_cons_left, ← gcd_assoc, gcd_same] diff --git a/Mathlib/Algebra/GradedMonoid.lean b/Mathlib/Algebra/GradedMonoid.lean index 383bab6b9b10a..a7033d50a11f7 100644 --- a/Mathlib/Algebra/GradedMonoid.lean +++ b/Mathlib/Algebra/GradedMonoid.lean @@ -616,7 +616,7 @@ theorem list_prod_map_mem_graded {ι'} (l : List ι') (i : ι' → ι) (r : ι' rw [List.map_cons, List.map_cons, List.prod_cons, List.sum_cons] exact mul_mem_graded (h _ <| List.mem_cons_self _ _) - (list_prod_map_mem_graded tail _ _ <| fun j hj => h _ <| List.mem_cons_of_mem _ hj) + (list_prod_map_mem_graded tail _ _ fun j hj => h _ <| List.mem_cons_of_mem _ hj) #align set_like.list_prod_map_mem_graded SetLike.list_prod_map_mem_graded theorem list_prod_ofFn_mem_graded {n} (i : Fin n → ι) (r : Fin n → R) (h : ∀ j, r j ∈ A (i j)) : diff --git a/Mathlib/Algebra/Group/Equiv/Basic.lean b/Mathlib/Algebra/Group/Equiv/Basic.lean index 0fcc8b12d8277..c273f4b33d342 100644 --- a/Mathlib/Algebra/Group/Equiv/Basic.lean +++ b/Mathlib/Algebra/Group/Equiv/Basic.lean @@ -195,7 +195,7 @@ instance [Mul α] [Mul β] [MulEquivClass F α β] : CoeTC F (α ≃* β) := @[to_additive] theorem MulEquivClass.toMulEquiv_injective [Mul α] [Mul β] [MulEquivClass F α β] : Function.Injective ((↑) : F → α ≃* β) := - fun _ _ e ↦ FunLike.ext _ _ <| fun a ↦ congr_arg (fun e : α ≃* β ↦ e.toFun a) e + fun _ _ e ↦ FunLike.ext _ _ fun a ↦ congr_arg (fun e : α ≃* β ↦ e.toFun a) e namespace MulEquiv diff --git a/Mathlib/Algebra/Group/Pi.lean b/Mathlib/Algebra/Group/Pi.lean index de434e44817b6..685975e3359ff 100644 --- a/Mathlib/Algebra/Group/Pi.lean +++ b/Mathlib/Algebra/Group/Pi.lean @@ -171,11 +171,11 @@ instance commGroup [∀ i, CommGroup <| f i] : CommGroup (∀ i : I, f i) := @[to_additive] instance [∀ i, Mul <| f i] [∀ i, IsLeftCancelMul <| f i] : IsLeftCancelMul (∀ i : I, f i) where - mul_left_cancel _ _ _ h := funext <| fun _ => mul_left_cancel (congr_fun h _) + mul_left_cancel _ _ _ h := funext fun _ => mul_left_cancel (congr_fun h _) @[to_additive] instance [∀ i, Mul <| f i] [∀ i, IsRightCancelMul <| f i] : IsRightCancelMul (∀ i : I, f i) where - mul_right_cancel _ _ _ h := funext <| fun _ => mul_right_cancel (congr_fun h _) + mul_right_cancel _ _ _ h := funext fun _ => mul_right_cancel (congr_fun h _) @[to_additive] instance [∀ i, Mul <| f i] [∀ i, IsCancelMul <| f i] : IsCancelMul (∀ i : I, f i) where diff --git a/Mathlib/Algebra/GroupWithZero/Basic.lean b/Mathlib/Algebra/GroupWithZero/Basic.lean index 895bbf2080ebb..19bcb60e478f4 100644 --- a/Mathlib/Algebra/GroupWithZero/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Basic.lean @@ -159,7 +159,7 @@ variable [CancelMonoidWithZero M₀] {a b c : M₀} -- see Note [lower instance priority] instance (priority := 10) CancelMonoidWithZero.to_noZeroDivisors : NoZeroDivisors M₀ := - ⟨fun ab0 => or_iff_not_imp_left.mpr <| fun ha => mul_left_cancel₀ ha <| + ⟨fun ab0 => or_iff_not_imp_left.mpr fun ha => mul_left_cancel₀ ha <| ab0.trans (mul_zero _).symm⟩ #align cancel_monoid_with_zero.to_no_zero_divisors CancelMonoidWithZero.to_noZeroDivisors diff --git a/Mathlib/Algebra/GroupWithZero/InjSurj.lean b/Mathlib/Algebra/GroupWithZero/InjSurj.lean index b40b18db6e3dd..2329133b30dfb 100644 --- a/Mathlib/Algebra/GroupWithZero/InjSurj.lean +++ b/Mathlib/Algebra/GroupWithZero/InjSurj.lean @@ -234,7 +234,7 @@ protected def Function.Surjective.groupWithZero [Zero G₀'] [Mul G₀'] [One G { hf.monoidWithZero f zero one mul npow, hf.divInvMonoid f one mul inv div npow zpow with inv_zero := by erw [← zero, ← inv, inv_zero], mul_inv_cancel := hf.forall.2 fun x hx => by - erw [← inv, ← mul, mul_inv_cancel (mt (congr_arg f) <| fun h ↦ hx (h.trans zero)), one] + erw [← inv, ← mul, mul_inv_cancel (mt (congr_arg f) fun h ↦ hx (h.trans zero)), one] exists_pair_ne := ⟨0, 1, h01⟩ } #align function.surjective.group_with_zero Function.Surjective.groupWithZero diff --git a/Mathlib/Algebra/Module/Submodule/Pointwise.lean b/Mathlib/Algebra/Module/Submodule/Pointwise.lean index a35af4ec0aaf7..0d3b1f86e8bc9 100644 --- a/Mathlib/Algebra/Module/Submodule/Pointwise.lean +++ b/Mathlib/Algebra/Module/Submodule/Pointwise.lean @@ -508,7 +508,7 @@ protected def pointwiseSetMulAction [SMulCommClass R R M] : fun h => ⟨m, h, (one_smul _ _).symm⟩⟩ mul_smul s t x := le_antisymm (set_smul_le _ _ _ <| by rintro _ _ ⟨_, _, _, _, rfl⟩ _; rw [mul_smul]; aesop) - (set_smul_le _ _ _ <| fun r m hr hm ↦ by + (set_smul_le _ _ _ fun r m hr hm ↦ by have : SMulCommClass R R x := ⟨fun r s m => Subtype.ext <| smul_comm _ _ _⟩ obtain ⟨c, hc1, rfl⟩ := mem_set_smul _ _ _ |>.mp hm simp only [Finsupp.sum, AddSubmonoid.coe_finset_sum, coe_toAddSubmonoid, SetLike.val_smul, diff --git a/Mathlib/Algebra/MonoidAlgebra/Basic.lean b/Mathlib/Algebra/MonoidAlgebra/Basic.lean index 4d7bb6fdf2b7e..8788d413f6369 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Basic.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Basic.lean @@ -979,7 +979,7 @@ def domCongr (e : G ≃* H) : MonoidAlgebra A G ≃ₐ[k] MonoidAlgebra A H := congr_arg₂ _ (equivMapDomain_eq_mapDomain _ _).symm (equivMapDomain_eq_mapDomain _ _).symm) theorem domCongr_toAlgHom (e : G ≃* H) : (domCongr k A e).toAlgHom = mapDomainAlgHom k A e := - AlgHom.ext <| fun _ => equivMapDomain_eq_mapDomain _ _ + AlgHom.ext fun _ => equivMapDomain_eq_mapDomain _ _ @[simp] theorem domCongr_apply (e : G ≃* H) (f : MonoidAlgebra A G) (h : H) : domCongr k A e f h = f (e.symm h) := @@ -2119,7 +2119,7 @@ def domCongr (e : G ≃+ H) : A[G] ≃ₐ[k] A[H] := congr_arg₂ _ (equivMapDomain_eq_mapDomain _ _).symm (equivMapDomain_eq_mapDomain _ _).symm) theorem domCongr_toAlgHom (e : G ≃+ H) : (domCongr k A e).toAlgHom = mapDomainAlgHom k A e := - AlgHom.ext <| fun _ => equivMapDomain_eq_mapDomain _ _ + AlgHom.ext fun _ => equivMapDomain_eq_mapDomain _ _ @[simp] theorem domCongr_apply (e : G ≃+ H) (f : MonoidAlgebra A G) (h : H) : domCongr k A e f h = f (e.symm h) := diff --git a/Mathlib/Algebra/Order/Module/OrderedSMul.lean b/Mathlib/Algebra/Order/Module/OrderedSMul.lean index ee2eace0e4a30..bc47e3a949e5f 100644 --- a/Mathlib/Algebra/Order/Module/OrderedSMul.lean +++ b/Mathlib/Algebra/Order/Module/OrderedSMul.lean @@ -65,7 +65,7 @@ instance OrderedSMul.toPosSMulStrictMono : PosSMulStrictMono R M where elim _a ha _b₁ _b₂ hb := OrderedSMul.smul_lt_smul_of_pos hb ha instance OrderedSMul.toPosSMulReflectLT : PosSMulReflectLT R M := - PosSMulReflectLT.of_pos $ fun _a ha _b₁ _b₂ h ↦ OrderedSMul.lt_of_smul_lt_smul_of_pos h ha + PosSMulReflectLT.of_pos fun _a ha _b₁ _b₂ h ↦ OrderedSMul.lt_of_smul_lt_smul_of_pos h ha instance OrderDual.instOrderedSMul [OrderedSemiring R] [OrderedAddCommMonoid M] [SMulWithZero R M] [OrderedSMul R M] : OrderedSMul R Mᵒᵈ where diff --git a/Mathlib/Algebra/Order/Monovary.lean b/Mathlib/Algebra/Order/Monovary.lean index 73928ce9ff8cf..6c95814ac2db3 100644 --- a/Mathlib/Algebra/Order/Monovary.lean +++ b/Mathlib/Algebra/Order/Monovary.lean @@ -143,19 +143,19 @@ variable [OrderedCommGroup α] [LinearOrderedCommGroup β] {s : Set ι} {f f₁ @[to_additive] lemma Monovary.mul_right (h₁ : Monovary f g₁) (h₂ : Monovary f g₂) : Monovary f (g₁ * g₂) := - fun _i _j hij ↦ (lt_or_lt_of_mul_lt_mul hij).elim (fun h ↦ h₁ h) $ fun h ↦ h₂ h + fun _i _j hij ↦ (lt_or_lt_of_mul_lt_mul hij).elim (fun h ↦ h₁ h) fun h ↦ h₂ h @[to_additive] lemma Antivary.mul_right (h₁ : Antivary f g₁) (h₂ : Antivary f g₂) : Antivary f (g₁ * g₂) := - fun _i _j hij ↦ (lt_or_lt_of_mul_lt_mul hij).elim (fun h ↦ h₁ h) $ fun h ↦ h₂ h + fun _i _j hij ↦ (lt_or_lt_of_mul_lt_mul hij).elim (fun h ↦ h₁ h) fun h ↦ h₂ h @[to_additive] lemma Monovary.div_right (h₁ : Monovary f g₁) (h₂ : Antivary f g₂) : Monovary f (g₁ / g₂) := - fun _i _j hij ↦ (lt_or_lt_of_div_lt_div hij).elim (fun h ↦ h₁ h) $ fun h ↦ h₂ h + fun _i _j hij ↦ (lt_or_lt_of_div_lt_div hij).elim (fun h ↦ h₁ h) fun h ↦ h₂ h @[to_additive] lemma Antivary.div_right (h₁ : Antivary f g₁) (h₂ : Monovary f g₂) : Antivary f (g₁ / g₂) := - fun _i _j hij ↦ (lt_or_lt_of_div_lt_div hij).elim (fun h ↦ h₁ h) $ fun h ↦ h₂ h + fun _i _j hij ↦ (lt_or_lt_of_div_lt_div hij).elim (fun h ↦ h₁ h) fun h ↦ h₂ h @[to_additive] lemma Monovary.pow_right (hfg : Monovary f g) (n : ℕ) : Monovary f (g ^ n) := fun _i _j hij ↦ hfg $ lt_of_pow_lt_pow_left' _ hij @@ -345,7 +345,7 @@ monovary_toDual_right.symm.trans $ by rw [monovary_iff_forall_smul_nonneg]; rfl lemma monovaryOn_iff_smul_rearrangement : MonovaryOn f g s ↔ ∀ ⦃i⦄, i ∈ s → ∀ ⦃j⦄, j ∈ s → f i • g j + f j • g i ≤ f i • g i + f j • g j := - monovaryOn_iff_forall_smul_nonneg.trans $ forall₄_congr $ fun i _ j _ ↦ by + monovaryOn_iff_forall_smul_nonneg.trans $ forall₄_congr fun i _ j _ ↦ by simp [smul_sub, sub_smul, ← add_sub_right_comm, le_sub_iff_add_le, add_comm (f i • g i), add_comm (f i • g j)] diff --git a/Mathlib/Algebra/Order/Ring/WithTop.lean b/Mathlib/Algebra/Order/Ring/WithTop.lean index f6ba7fc0a55ea..0c40b6bedf032 100644 --- a/Mathlib/Algebra/Order/Ring/WithTop.lean +++ b/Mathlib/Algebra/Order/Ring/WithTop.lean @@ -75,7 +75,7 @@ theorem mul_lt_top [LT α] {a b : WithTop α} (ha : a ≠ ⊤) (hb : b ≠ ⊤) #align with_top.mul_lt_top WithTop.mul_lt_top instance noZeroDivisors [NoZeroDivisors α] : NoZeroDivisors (WithTop α) := by - refine ⟨fun h₁ => Decidable.by_contradiction <| fun h₂ => ?_⟩ + refine ⟨fun h₁ => Decidable.by_contradiction fun h₂ => ?_⟩ rw [mul_def, if_neg h₂] at h₁ rcases Option.mem_map₂_iff.1 h₁ with ⟨a, b, (rfl : _ = _), (rfl : _ = _), hab⟩ exact h₂ ((eq_zero_or_eq_zero_of_mul_eq_zero hab).imp (congr_arg some) (congr_arg some)) diff --git a/Mathlib/Algebra/Ring/CentroidHom.lean b/Mathlib/Algebra/Ring/CentroidHom.lean index ac7410b2864d0..6000aaaefccb1 100644 --- a/Mathlib/Algebra/Ring/CentroidHom.lean +++ b/Mathlib/Algebra/Ring/CentroidHom.lean @@ -278,13 +278,13 @@ instance instSMul : SMul M (CentroidHom α) where #noalign centroid_hom.has_nsmul instance [SMul M N] [IsScalarTower M N α] : IsScalarTower M N (CentroidHom α) where - smul_assoc _ _ _ := ext <| fun _ => smul_assoc _ _ _ + smul_assoc _ _ _ := ext fun _ => smul_assoc _ _ _ instance [SMulCommClass M N α] : SMulCommClass M N (CentroidHom α) where - smul_comm _ _ _ := ext <| fun _ => smul_comm _ _ _ + smul_comm _ _ _ := ext fun _ => smul_comm _ _ _ instance [DistribMulAction Mᵐᵒᵖ α] [IsCentralScalar M α] : IsCentralScalar M (CentroidHom α) where - op_smul_eq_smul _ _ := ext <| fun _ => op_smul_eq_smul _ _ + op_smul_eq_smul _ _ := ext fun _ => op_smul_eq_smul _ _ instance isScalarTowerRight : IsScalarTower M (CentroidHom α) (CentroidHom α) where smul_assoc _ _ _ := rfl diff --git a/Mathlib/Algebra/RingQuot.lean b/Mathlib/Algebra/RingQuot.lean index 4fe4add27d29f..7570672750c07 100644 --- a/Mathlib/Algebra/RingQuot.lean +++ b/Mathlib/Algebra/RingQuot.lean @@ -278,11 +278,11 @@ theorem smul_quot [Algebra S R] {n : S} {a : R} : instance instIsScalarTower [CommSemiring T] [SMul S T] [Algebra S R] [Algebra T R] [IsScalarTower S T R] : IsScalarTower S T (RingQuot r) := - ⟨fun s t ⟨a⟩ => Quot.inductionOn a <| fun a' => by simp only [RingQuot.smul_quot, smul_assoc]⟩ + ⟨fun s t ⟨a⟩ => Quot.inductionOn a fun a' => by simp only [RingQuot.smul_quot, smul_assoc]⟩ instance instSMulCommClass [CommSemiring T] [Algebra S R] [Algebra T R] [SMulCommClass S T R] : SMulCommClass S T (RingQuot r) := - ⟨fun s t ⟨a⟩ => Quot.inductionOn a <| fun a' => by simp only [RingQuot.smul_quot, smul_comm]⟩ + ⟨fun s t ⟨a⟩ => Quot.inductionOn a fun a' => by simp only [RingQuot.smul_quot, smul_comm]⟩ instance instAddCommMonoid (r : R → R → Prop) : AddCommMonoid (RingQuot r) where add := (· + ·) diff --git a/Mathlib/Algebra/SMulWithZero.lean b/Mathlib/Algebra/SMulWithZero.lean index 7159b789ce216..651dcc4fd98bb 100644 --- a/Mathlib/Algebra/SMulWithZero.lean +++ b/Mathlib/Algebra/SMulWithZero.lean @@ -77,7 +77,7 @@ lemma smul_eq_zero_of_left (h : a = 0) (b : M) : a • b = 0 := h.symm ▸ zero_ #align smul_eq_zero_of_left smul_eq_zero_of_left lemma smul_eq_zero_of_right (a : R) (h : b = 0) : a • b = 0 := h.symm ▸ smul_zero a #align smul_eq_zero_of_right smul_eq_zero_of_right -lemma left_ne_zero_of_smul : a • b ≠ 0 → a ≠ 0 := mt $ fun h ↦ smul_eq_zero_of_left h b +lemma left_ne_zero_of_smul : a • b ≠ 0 → a ≠ 0 := mt fun h ↦ smul_eq_zero_of_left h b #align left_ne_zero_of_smul left_ne_zero_of_smul lemma right_ne_zero_of_smul : a • b ≠ 0 → b ≠ 0 := mt $ smul_eq_zero_of_right a #align right_ne_zero_of_smul right_ne_zero_of_smul diff --git a/Mathlib/AlgebraicTopology/SimplexCategory.lean b/Mathlib/AlgebraicTopology/SimplexCategory.lean index 563909dab4b5d..a04e56aa8a06e 100644 --- a/Mathlib/AlgebraicTopology/SimplexCategory.lean +++ b/Mathlib/AlgebraicTopology/SimplexCategory.lean @@ -223,7 +223,7 @@ theorem δ_comp_δ {n} {i j : Fin (n + 2)} (H : i ≤ j) : theorem δ_comp_δ' {n} {i : Fin (n + 2)} {j : Fin (n + 3)} (H : Fin.castSucc i < j) : δ i ≫ δ j = - δ (j.pred <| fun (hj : j = 0) => by simp [hj, Fin.not_lt_zero] at H) ≫ + δ (j.pred fun (hj : j = 0) => by simp [hj, Fin.not_lt_zero] at H) ≫ δ (Fin.castSucc i) := by rw [← δ_comp_δ] · rw [Fin.succ_pred] @@ -326,7 +326,7 @@ theorem δ_comp_σ_of_gt {n} {i : Fin (n + 2)} {j : Fin (n + 1)} (H : Fin.castSu @[reassoc] theorem δ_comp_σ_of_gt' {n} {i : Fin (n + 3)} {j : Fin (n + 2)} (H : j.succ < i) : δ i ≫ σ j = σ (j.castLT ((add_lt_add_iff_right 1).mp (lt_of_lt_of_le H i.is_le))) ≫ - δ (i.pred <| fun (hi : i = 0) => by simp only [Fin.not_lt_zero, hi] at H) := by + δ (i.pred fun (hi : i = 0) => by simp only [Fin.not_lt_zero, hi] at H) := by rw [← δ_comp_σ_of_gt] · simp · rw [Fin.castSucc_castLT, ← Fin.succ_lt_succ_iff, Fin.succ_pred] diff --git a/Mathlib/AlgebraicTopology/SimplicialObject.lean b/Mathlib/AlgebraicTopology/SimplicialObject.lean index 1a3d78e84a89c..32e1b97f96a42 100644 --- a/Mathlib/AlgebraicTopology/SimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/SimplicialObject.lean @@ -117,7 +117,7 @@ theorem δ_comp_δ {n} {i j : Fin (n + 2)} (H : i ≤ j) : theorem δ_comp_δ' {n} {i : Fin (n + 2)} {j : Fin (n + 3)} (H : Fin.castSucc i < j) : X.δ j ≫ X.δ i = X.δ (Fin.castSucc i) ≫ - X.δ (j.pred <| fun (hj : j = 0) => by simp [hj, Fin.not_lt_zero] at H) := by + X.δ (j.pred fun (hj : j = 0) => by simp [hj, Fin.not_lt_zero] at H) := by dsimp [δ] simp only [← X.map_comp, ← op_comp, SimplexCategory.δ_comp_δ' H] #align category_theory.simplicial_object.δ_comp_δ' CategoryTheory.SimplicialObject.δ_comp_δ' @@ -191,7 +191,7 @@ theorem δ_comp_σ_of_gt {n} {i : Fin (n + 2)} {j : Fin (n + 1)} (H : Fin.castSu @[reassoc] theorem δ_comp_σ_of_gt' {n} {i : Fin (n + 3)} {j : Fin (n + 2)} (H : j.succ < i) : X.σ j ≫ X.δ i = - X.δ (i.pred <| fun (hi : i = 0) => by simp only [Fin.not_lt_zero, hi] at H) ≫ + X.δ (i.pred fun (hi : i = 0) => by simp only [Fin.not_lt_zero, hi] at H) ≫ X.σ (j.castLT ((add_lt_add_iff_right 1).mp (lt_of_lt_of_le H i.is_le))) := by dsimp [δ, σ] simp only [← X.map_comp, ← op_comp, SimplexCategory.δ_comp_σ_of_gt' H] @@ -488,7 +488,7 @@ theorem δ_comp_δ {n} {i j : Fin (n + 2)} (H : i ≤ j) : @[reassoc] theorem δ_comp_δ' {n} {i : Fin (n + 2)} {j : Fin (n + 3)} (H : Fin.castSucc i < j) : X.δ i ≫ X.δ j = - X.δ (j.pred <| fun (hj : j = 0) => by simp only [hj, Fin.not_lt_zero] at H) ≫ + X.δ (j.pred fun (hj : j = 0) => by simp only [hj, Fin.not_lt_zero] at H) ≫ X.δ (Fin.castSucc i) := by dsimp [δ] simp only [← X.map_comp, ← op_comp, SimplexCategory.δ_comp_δ' H] diff --git a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean index ef8ecb9af98ed..8de8f38c8be6b 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean @@ -1910,7 +1910,7 @@ def restrContDiff (f : PartialHomeomorph E F) (n : ℕ) : PartialHomeomorph E F haveI H : f.IsImage {x | ContDiffAt 𝕜 n f x ∧ ContDiffAt 𝕜 n f.symm (f x)} {y | ContDiffAt 𝕜 n f.symm y ∧ ContDiffAt 𝕜 n f (f.symm y)} := fun x hx ↦ by simp [hx, and_comm] - H.restr <| isOpen_iff_mem_nhds.2 <| fun x ⟨hxs, hxf, hxf'⟩ ↦ + H.restr <| isOpen_iff_mem_nhds.2 fun x ⟨hxs, hxf, hxf'⟩ ↦ inter_mem (f.open_source.mem_nhds hxs) <| hxf.eventually.and <| f.continuousAt hxs hxf'.eventually diff --git a/Mathlib/Analysis/Calculus/MeanValue.lean b/Mathlib/Analysis/Calculus/MeanValue.lean index da20d7d4441d9..9569ce7a5ac7b 100644 --- a/Mathlib/Analysis/Calculus/MeanValue.lean +++ b/Mathlib/Analysis/Calculus/MeanValue.lean @@ -1118,7 +1118,7 @@ Note that we don't require differentiability, since it is guaranteed at all but one point by the strict monotonicity of `f'`. -/ theorem StrictMonoOn.strictConvexOn_of_deriv {D : Set ℝ} (hD : Convex ℝ D) {f : ℝ → ℝ} (hf : ContinuousOn f D) (hf' : StrictMonoOn (deriv f) (interior D)) : StrictConvexOn ℝ D f := - strictConvexOn_of_slope_strict_mono_adjacent hD <| fun {x y z} hx hz hxy hyz => by + strictConvexOn_of_slope_strict_mono_adjacent hD fun {x y z} hx hz hxy hyz => by -- First we prove some trivial inclusions have hxzD : Icc x z ⊆ D := hD.ordConnected.out hx hz have hxyD : Icc x y ⊆ D := (Icc_subset_Icc_right hyz.le).trans hxzD diff --git a/Mathlib/Analysis/Complex/CauchyIntegral.lean b/Mathlib/Analysis/Complex/CauchyIntegral.lean index 8c3df46ac0a3d..1a56cd60a1159 100644 --- a/Mathlib/Analysis/Complex/CauchyIntegral.lean +++ b/Mathlib/Analysis/Complex/CauchyIntegral.lean @@ -620,7 +620,7 @@ protected theorem _root_.Differentiable.analyticAt {f : ℂ → E} (hf : Differe /-- A complex differentiable function `f : ℂ → E` is continuously differentiable at every point. -/ protected theorem _root_.Differentiable.contDiff {f : ℂ → E} (hf : Differentiable ℂ f) {n : ℕ∞} : ContDiff ℂ n f := - contDiff_iff_contDiffAt.mpr $ fun z ↦ (hf.analyticAt z).contDiffAt + contDiff_iff_contDiffAt.mpr fun z ↦ (hf.analyticAt z).contDiffAt /-- When `f : ℂ → E` is differentiable, the `cauchyPowerSeries f z R` represents `f` as a power series centered at `z` in the entirety of `ℂ`, regardless of `R : ℝ≥0`, with `0 < R`. -/ diff --git a/Mathlib/Analysis/Matrix.lean b/Mathlib/Analysis/Matrix.lean index 544207b9ca739..37ad8c40ca2be 100644 --- a/Mathlib/Analysis/Matrix.lean +++ b/Mathlib/Analysis/Matrix.lean @@ -432,7 +432,7 @@ variable [SeminormedAddCommGroup α] [SeminormedAddCommGroup β] theorem frobenius_nnnorm_def (A : Matrix m n α) : ‖A‖₊ = (∑ i, ∑ j, ‖A i j‖₊ ^ (2 : ℝ)) ^ (1 / 2 : ℝ) := by -- porting note: added, along with `WithLp.equiv_symm_pi_apply` below - change ‖(WithLp.equiv 2 _).symm <| fun i => (WithLp.equiv 2 _).symm <| fun j => A i j‖₊ = _ + change ‖(WithLp.equiv 2 _).symm fun i => (WithLp.equiv 2 _).symm fun j => A i j‖₊ = _ simp_rw [PiLp.nnnorm_eq_of_L2, NNReal.sq_sqrt, NNReal.sqrt_eq_rpow, NNReal.rpow_two, WithLp.equiv_symm_pi_apply] #align matrix.frobenius_nnnorm_def Matrix.frobenius_nnnorm_def diff --git a/Mathlib/Analysis/Normed/Field/InfiniteSum.lean b/Mathlib/Analysis/Normed/Field/InfiniteSum.lean index 2e4bb050c8e8a..c7812051f74f9 100644 --- a/Mathlib/Analysis/Normed/Field/InfiniteSum.lean +++ b/Mathlib/Analysis/Normed/Field/InfiniteSum.lean @@ -30,7 +30,7 @@ open Finset theorem Summable.mul_of_nonneg {f : ι → ℝ} {g : ι' → ℝ} (hf : Summable f) (hg : Summable g) (hf' : 0 ≤ f) (hg' : 0 ≤ g) : Summable fun x : ι × ι' => f x.1 * g x.2 := - (summable_prod_of_nonneg <| fun _ ↦ mul_nonneg (hf' _) (hg' _)).2 ⟨fun x ↦ hg.mul_left (f x), + (summable_prod_of_nonneg fun _ ↦ mul_nonneg (hf' _) (hg' _)).2 ⟨fun x ↦ hg.mul_left (f x), by simpa only [hg.tsum_mul_left _] using hf.mul_right (∑' x, g x)⟩ #align summable.mul_of_nonneg Summable.mul_of_nonneg diff --git a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean index 29acf116dd222..06e90e53601ed 100644 --- a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean +++ b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean @@ -287,7 +287,7 @@ theorem bernsteinApproximation_uniform (f : C(I, ℝ)) : -- Again enlarging the sum from `Sᶜ` to all of `Fin (n+1)` _ ≤ 2 * ‖f‖ * ∑ k : Fin (n + 1), δ ^ (-2 : ℤ) * ((x : ℝ) - k/ₙ) ^ 2 * bernstein n k x := by gcongr - refine Finset.sum_le_univ_sum_of_nonneg <| fun k => ?_ + refine Finset.sum_le_univ_sum_of_nonneg fun k => ?_ positivity _ = 2 * ‖f‖ * δ ^ (-2 : ℤ) * ∑ k : Fin (n + 1), ((x : ℝ) - k/ₙ) ^ 2 * bernstein n k x := by conv_rhs => diff --git a/Mathlib/CategoryTheory/Extensive.lean b/Mathlib/CategoryTheory/Extensive.lean index 0ae838fd8cef7..33c247bf42898 100644 --- a/Mathlib/CategoryTheory/Extensive.lean +++ b/Mathlib/CategoryTheory/Extensive.lean @@ -553,7 +553,7 @@ lemma FinitaryPreExtensive.hasPullbacks_of_is_coproduct [FinitaryPreExtensive C] let e : ∐ f ≅ f i ⨿ (∐ fun j : ({i}ᶜ : Set ι) ↦ f j) := { hom := Sigma.desc (fun j ↦ if h : j = i then eqToHom (congr_arg f h) ≫ coprod.inl else Sigma.ι (fun j : ({i}ᶜ : Set ι) ↦ f j) ⟨j, h⟩ ≫ coprod.inr) - inv := coprod.desc (Sigma.ι f i) (Sigma.desc <| fun j ↦ Sigma.ι f j) + inv := coprod.desc (Sigma.ι f i) (Sigma.desc fun j ↦ Sigma.ι f j) hom_inv_id := by aesop_cat inv_hom_id := by ext j @@ -612,7 +612,7 @@ lemma FinitaryPreExtensive.sigma_desc_iso [FinitaryPreExtensive C] {α : Type} [ simp [coproductIsCoproduct] refine (FinitaryPreExtensive.isUniversal_finiteCoproducts this (Cofan.mk _ ((fun _ ↦ pullback.fst) : (a : α) → pullback f (π a) ⟶ _)) - (Discrete.natTrans <| fun i ↦ pullback.snd) f ?_ + (Discrete.natTrans fun i ↦ pullback.snd) f ?_ (NatTrans.equifibered_of_discrete _) ?_).some · ext simp [pullback.condition] diff --git a/Mathlib/CategoryTheory/Limits/VanKampen.lean b/Mathlib/CategoryTheory/Limits/VanKampen.lean index 0905eefa290bc..87dfbdf7ae5a5 100644 --- a/Mathlib/CategoryTheory/Limits/VanKampen.lean +++ b/Mathlib/CategoryTheory/Limits/VanKampen.lean @@ -608,8 +608,8 @@ theorem isUniversalColimit_extendCofan {n : ℕ} (f : Fin (n + 1) → C) · rintro ⟨i⟩ ⟨j⟩ ⟨⟨rfl : i = j⟩⟩ simp have t₁' := @t₁ (Discrete.functor (fun j ↦ F.obj ⟨j.succ⟩)) - (Cofan.mk (pullback c₂.inr i) <| fun j ↦ pullback.lift (α.app _ ≫ c₁.inj _) (c.ι.app _) ?_) - (Discrete.natTrans <| fun i ↦ α.app _) pullback.fst ?_ (NatTrans.equifibered_of_discrete _) ?_ + (Cofan.mk (pullback c₂.inr i) fun j ↦ pullback.lift (α.app _ ≫ c₁.inj _) (c.ι.app _) ?_) + (Discrete.natTrans fun i ↦ α.app _) pullback.fst ?_ (NatTrans.equifibered_of_discrete _) ?_ rotate_left · simpa only [Functor.const_obj_obj, pair_obj_right, Discrete.functor_obj, Category.assoc, extendCofan_pt, Functor.const_obj_obj, NatTrans.comp_app, extendCofan_ι_app, @@ -662,8 +662,8 @@ theorem isVanKampenColimit_extendCofan {n : ℕ} (f : Fin (n + 1) → C) refine ⟨?_, isUniversalColimit_extendCofan f t₁.isUniversal t₂.isUniversal c α i e hα⟩ intro ⟨Hc⟩ ⟨j⟩ have t₂' := (@t₂ (pair (F.obj ⟨0⟩) (∐ fun (j : Fin n) ↦ F.obj ⟨j.succ⟩)) - (BinaryCofan.mk (P := c.pt) (c.ι.app _) (Sigma.desc <| fun b ↦ c.ι.app _)) - (mapPair (α.app _) (Sigma.desc <| fun b ↦ α.app _ ≫ c₁.inj _)) i ?_ + (BinaryCofan.mk (P := c.pt) (c.ι.app _) (Sigma.desc fun b ↦ c.ι.app _)) + (mapPair (α.app _) (Sigma.desc fun b ↦ α.app _ ≫ c₁.inj _)) i ?_ (mapPair_equifibered _)).mp ⟨?_⟩ rotate_left · ext ⟨⟨⟩⟩ @@ -709,7 +709,7 @@ theorem isVanKampenColimit_extendCofan {n : ℕ} (f : Fin (n + 1) → C) induction' j using Fin.inductionOn with j _ · exact t₂' ⟨WalkingPair.left⟩ · have t₁' := (@t₁ (Discrete.functor (fun j ↦ F.obj ⟨j.succ⟩)) (Cofan.mk _ _) (Discrete.natTrans - <| fun i ↦ α.app _) (Sigma.desc (fun j ↦ α.app _ ≫ c₁.inj _)) ?_ + fun i ↦ α.app _) (Sigma.desc (fun j ↦ α.app _ ≫ c₁.inj _)) ?_ (NatTrans.equifibered_of_discrete _)).mp ⟨coproductIsCoproduct _⟩ ⟨j⟩ rotate_left · ext ⟨j⟩ diff --git a/Mathlib/CategoryTheory/PathCategory.lean b/Mathlib/CategoryTheory/PathCategory.lean index 3ca83bb4f8267..e1ffc58bdbff3 100644 --- a/Mathlib/CategoryTheory/PathCategory.lean +++ b/Mathlib/CategoryTheory/PathCategory.lean @@ -235,7 +235,7 @@ def quotientPathsEquiv : Quotient (pathsHomRel C) ≌ C where unitIso := NatIso.ofComponents (fun X => by cases X; rfl) - (Quot.ind $ fun f => by + (Quot.ind fun f => by apply Quot.sound apply Quotient.CompClosure.of simp [Category.comp_id, Category.id_comp, pathsHomRel]) diff --git a/Mathlib/Combinatorics/Partition.lean b/Mathlib/Combinatorics/Partition.lean index 20cdc0af42a8e..753157350257f 100644 --- a/Mathlib/Combinatorics/Partition.lean +++ b/Mathlib/Combinatorics/Partition.lean @@ -112,7 +112,7 @@ instance {n : ℕ} : Inhabited (Partition n) := ⟨indiscrete n⟩ simp [indiscrete, filter_eq_self, hn] @[simp] lemma partition_zero_parts (p : Partition 0) : p.parts = 0 := - eq_zero_of_forall_not_mem <| fun _ h => (p.parts_pos h).ne' <| sum_eq_zero_iff.1 p.parts_sum _ h + eq_zero_of_forall_not_mem fun _ h => (p.parts_pos h).ne' <| sum_eq_zero_iff.1 p.parts_sum _ h instance UniquePartitionZero : Unique (Partition 0) where uniq _ := Partition.ext _ _ <| by simp diff --git a/Mathlib/Combinatorics/Pigeonhole.lean b/Mathlib/Combinatorics/Pigeonhole.lean index a48948e0b3a6a..9f1f1a0be1de1 100644 --- a/Mathlib/Combinatorics/Pigeonhole.lean +++ b/Mathlib/Combinatorics/Pigeonhole.lean @@ -461,7 +461,7 @@ open Set that are equal mod `k`. -/ theorem exists_lt_modEq_of_infinite {s : Set ℕ} (hs : s.Infinite) {k : ℕ} (hk : 0 < k) : ∃ m ∈ s, ∃ n ∈ s, m < n ∧ m ≡ n [MOD k] := - (hs.exists_lt_map_eq_of_mapsTo $ fun n _ => show n % k ∈ Iio k from Nat.mod_lt n hk) <| + (hs.exists_lt_map_eq_of_mapsTo fun n _ => show n % k ∈ Iio k from Nat.mod_lt n hk) <| finite_lt_nat k #align nat.exists_lt_modeq_of_infinite Nat.exists_lt_modEq_of_infinite diff --git a/Mathlib/Combinatorics/SetFamily/FourFunctions.lean b/Mathlib/Combinatorics/SetFamily/FourFunctions.lean index a75d667611083..ede2be843716e 100644 --- a/Mathlib/Combinatorics/SetFamily/FourFunctions.lean +++ b/Mathlib/Combinatorics/SetFamily/FourFunctions.lean @@ -125,7 +125,7 @@ lemma le_collapse_of_insert_mem (ha : a ∉ s) (hf : 0 ≤ f) (hts : t = insert · exact le_add_of_nonneg_left $ hf _ · rw [zero_add] -lemma collapse_nonneg (hf : 0 ≤ f) : 0 ≤ collapse 𝒜 a f := fun _s ↦ sum_nonneg $ fun _t _ ↦ hf _ +lemma collapse_nonneg (hf : 0 ≤ f) : 0 ≤ collapse 𝒜 a f := fun _s ↦ sum_nonneg fun _t _ ↦ hf _ lemma collapse_modular (hu : a ∉ u) (h₁ : 0 ≤ f₁) (h₂ : 0 ≤ f₂) (h₃ : 0 ≤ f₃) (h₄ : 0 ≤ f₄) (h : ∀ ⦃s⦄, s ⊆ insert a u → ∀ ⦃t⦄, t ⊆ insert a u → f₁ s * f₂ t ≤ f₃ (s ∩ t) * f₄ (s ∪ t)) diff --git a/Mathlib/Combinatorics/SetFamily/Shatter.lean b/Mathlib/Combinatorics/SetFamily/Shatter.lean index 5c53b3c021c01..50e97a018bb22 100644 --- a/Mathlib/Combinatorics/SetFamily/Shatter.lean +++ b/Mathlib/Combinatorics/SetFamily/Shatter.lean @@ -66,7 +66,7 @@ lemma shatters_iff : 𝒜.Shatters s ↔ 𝒜.image (fun t ↦ s ∩ t) = s.powe fun h t ht ↦ by rwa [← mem_powerset, ← h, mem_image] at ht⟩ lemma univ_shatters [Fintype α] : univ.Shatters s := - shatters_of_forall_subset <| fun _ _ ↦ mem_univ _ + shatters_of_forall_subset fun _ _ ↦ mem_univ _ @[simp] lemma shatters_univ [Fintype α] : 𝒜.Shatters univ ↔ 𝒜 = univ := by rw [shatters_iff, powerset_univ]; simp_rw [univ_inter, image_id'] @@ -75,7 +75,7 @@ lemma univ_shatters [Fintype α] : univ.Shatters s := def shatterer (𝒜 : Finset (Finset α)) : Finset (Finset α) := (𝒜.biUnion powerset).filter 𝒜.Shatters @[simp] lemma mem_shatterer : s ∈ 𝒜.shatterer ↔ 𝒜.Shatters s := by - refine mem_filter.trans <| and_iff_right_of_imp <| fun h ↦ ?_ + refine mem_filter.trans <| and_iff_right_of_imp fun h ↦ ?_ simp_rw [mem_biUnion, mem_powerset] exact h.exists_superset @@ -83,7 +83,7 @@ lemma shatterer_mono (h : 𝒜 ⊆ ℬ) : 𝒜.shatterer ⊆ ℬ.shatterer := fun _ ↦ by simpa using Shatters.mono_left h lemma subset_shatterer (h : IsLowerSet (𝒜 : Set (Finset α))) : 𝒜 ⊆ 𝒜.shatterer := - fun _s hs ↦ mem_shatterer.2 <| fun t ht ↦ ⟨t, h ht hs, inter_eq_right.2 ht⟩ + fun _s hs ↦ mem_shatterer.2 fun t ht ↦ ⟨t, h ht hs, inter_eq_right.2 ht⟩ @[simp] lemma isLowerSet_shatterer (𝒜 : Finset (Finset α)) : IsLowerSet (𝒜.shatterer : Set (Finset α)) := fun s t ↦ by simpa using Shatters.mono_right @@ -191,7 +191,7 @@ lemma vcDim_compress_le (a : α) (𝒜 : Finset (Finset α)) : (𝓓 a 𝒜).vcD lemma card_shatterer_le_sum_vcDim [Fintype α] : 𝒜.shatterer.card ≤ ∑ k in Iic 𝒜.vcDim, (Fintype.card α).choose k := by simp_rw [← card_univ, ← card_powersetCard] - refine (card_le_card <| fun s hs ↦ mem_biUnion.2 ⟨card s, ?_⟩).trans card_biUnion_le + refine (card_le_card fun s hs ↦ mem_biUnion.2 ⟨card s, ?_⟩).trans card_biUnion_le exact ⟨mem_Iic.2 (mem_shatterer.1 hs).card_le_vcDim, mem_powersetCard_univ.2 rfl⟩ end Finset diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 500b7d23fdea4..5ca69b7108848 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -317,7 +317,7 @@ theorem sdiff_adj (x y : SimpleGraph V) (v w : V) : (x \ y).Adj v w ↔ x.Adj v instance supSet : SupSet (SimpleGraph V) where sSup s := { Adj := fun a b => ∃ G ∈ s, Adj G a b - symm := fun a b => Exists.imp $ fun _ => And.imp_right Adj.symm + symm := fun a b => Exists.imp fun _ => And.imp_right Adj.symm loopless := by rintro a ⟨G, _, ha⟩ exact ha.ne rfl } diff --git a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean index 1c4adb124c365..9c3fe167173bb 100644 --- a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean +++ b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean @@ -498,7 +498,7 @@ namely `n^p (1 + ∑_{u < n} g(u) / u^(p+1))`. -/ @[continuity] lemma continuous_sumCoeffsExp : Continuous (fun (p : ℝ) => ∑ i, a i * (b i) ^ p) := by - refine continuous_finset_sum Finset.univ <| fun i _ => Continuous.mul (by continuity) ?_ + refine continuous_finset_sum Finset.univ fun i _ => Continuous.mul (by continuity) ?_ exact Continuous.rpow continuous_const continuous_id (fun x => Or.inl (ne_of_gt (R.b_pos i))) lemma strictAnti_sumCoeffsExp : StrictAnti (fun (p : ℝ) => ∑ i, a i * (b i) ^ p) := by diff --git a/Mathlib/Computability/Primrec.lean b/Mathlib/Computability/Primrec.lean index 2cffe2ec1024d..976814050f27c 100644 --- a/Mathlib/Computability/Primrec.lean +++ b/Mathlib/Computability/Primrec.lean @@ -112,7 +112,7 @@ theorem casesOn1 {f} (m : ℕ) (hf : Nat.Primrec f) : Nat.Primrec (Nat.casesOn -- Porting note: `Nat.Primrec.casesOn` is already declared as a recursor. theorem casesOn' {f g} (hf : Nat.Primrec f) (hg : Nat.Primrec g) : Nat.Primrec (unpaired fun z n => n.casesOn (f z) fun y => g <| Nat.pair z y) := - (prec hf (hg.comp (pair left (left.comp right)))).of_eq <| fun n => by simp + (prec hf (hg.comp (pair left (left.comp right)))).of_eq fun n => by simp #align nat.primrec.cases Nat.Primrec.casesOn' protected theorem swap : Nat.Primrec (unpaired (swap Nat.pair)) := diff --git a/Mathlib/Control/EquivFunctor.lean b/Mathlib/Control/EquivFunctor.lean index 087b607c4b0cd..4c345d4342bfb 100644 --- a/Mathlib/Control/EquivFunctor.lean +++ b/Mathlib/Control/EquivFunctor.lean @@ -83,7 +83,7 @@ or `map_comp_map` when not applied. @[simp] theorem mapEquiv_trans {γ : Type u₀} (ab : α ≃ β) (bc : β ≃ γ) : (mapEquiv f ab).trans (mapEquiv f bc) = mapEquiv f (ab.trans bc) := - Equiv.ext $ fun x => by simp [mapEquiv, map_trans'] + Equiv.ext fun x => by simp [mapEquiv, map_trans'] #align equiv_functor.map_equiv_trans EquivFunctor.mapEquiv_trans end @@ -104,7 +104,7 @@ theorem mapEquiv.injective (f : Type u₀ → Type u₁) (h : ∀ γ, Function.Injective (pure : γ → f γ)) : Function.Injective (@EquivFunctor.mapEquiv f _ α β) := fun e₁ e₂ H => - Equiv.ext $ fun x => h β (by simpa [EquivFunctor.map] using Equiv.congr_fun H (pure x)) + Equiv.ext fun x => h β (by simpa [EquivFunctor.map] using Equiv.congr_fun H (pure x)) #align equiv_functor.map_equiv.injective EquivFunctor.mapEquiv.injective end EquivFunctor diff --git a/Mathlib/Control/Functor.lean b/Mathlib/Control/Functor.lean index 38ac018219546..df9c171e3c2a7 100644 --- a/Mathlib/Control/Functor.lean +++ b/Mathlib/Control/Functor.lean @@ -43,7 +43,7 @@ theorem Functor.map_id : (id <$> ·) = (id : F α → F α) := funext id_map theorem Functor.map_comp_map (f : α → β) (g : β → γ) : ((g <$> ·) ∘ (f <$> ·) : F α → F γ) = ((g ∘ f) <$> ·) := - funext <| fun _ => (comp_map _ _ _).symm + funext fun _ => (comp_map _ _ _).symm -- porting note: was `apply funext <;> intro <;> rw [comp_map]` but `rw` failed? #align functor.map_comp_map Functor.map_comp_map diff --git a/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean b/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean index d788eea08b447..8fb904bcd0f3b 100644 --- a/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean +++ b/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean @@ -33,7 +33,7 @@ the sequence of elements `x : Fin k → ℕ` such that `n = ∑ i, x i`. ## Implementation notes -While we could implement this by filtering `(Fintype.PiFinset $ fun _ ↦ range (n + 1))` or similar, +While we could implement this by filtering `(Fintype.PiFinset fun _ ↦ range (n + 1))` or similar, this implementation would be much slower. In the future, we could consider generalizing `Finset.Nat.antidiagonalTuple` further to diff --git a/Mathlib/Data/Finmap.lean b/Mathlib/Data/Finmap.lean index 9463b4f841ed1..28240db32928b 100644 --- a/Mathlib/Data/Finmap.lean +++ b/Mathlib/Data/Finmap.lean @@ -332,7 +332,7 @@ that `(lookup a).isSome ↔ a ∈ keys`. -/ def keysLookupEquiv : Finmap β ≃ { f : Finset α × (∀ a, Option (β a)) // ∀ i, (f.2 i).isSome ↔ i ∈ f.1 } where toFun s := ⟨(s.keys, fun i => s.lookup i), fun _ => lookup_isSome⟩ - invFun f := mk (f.1.1.sigma <| fun i => (f.1.2 i).toFinset).val <| by + invFun f := mk (f.1.1.sigma fun i => (f.1.2 i).toFinset).val <| by refine Multiset.nodup_keys.1 ((Finset.nodup _).map_on ?_) simp only [Finset.mem_val, Finset.mem_sigma, Option.mem_toFinset, Option.mem_def] rintro ⟨i, x⟩ ⟨_, hx⟩ ⟨j, y⟩ ⟨_, hy⟩ (rfl : i = j) @@ -347,13 +347,13 @@ def keysLookupEquiv : @[simp] lemma keysLookupEquiv_symm_apply_keys : ∀ f : {f : Finset α × (∀ a, Option (β a)) // ∀ i, (f.2 i).isSome ↔ i ∈ f.1}, (keysLookupEquiv.symm f).keys = f.1.1 := - keysLookupEquiv.surjective.forall.2 $ fun _ => by + keysLookupEquiv.surjective.forall.2 fun _ => by simp only [Equiv.symm_apply_apply, keysLookupEquiv_apply_coe_fst] @[simp] lemma keysLookupEquiv_symm_apply_lookup : ∀ (f : {f : Finset α × (∀ a, Option (β a)) // ∀ i, (f.2 i).isSome ↔ i ∈ f.1}) a, (keysLookupEquiv.symm f).lookup a = f.1.2 a := - keysLookupEquiv.surjective.forall.2 $ fun _ _ => by + keysLookupEquiv.surjective.forall.2 fun _ _ => by simp only [Equiv.symm_apply_apply, keysLookupEquiv_apply_coe_snd] /-! ### replace -/ diff --git a/Mathlib/Data/Finset/Basic.lean b/Mathlib/Data/Finset/Basic.lean index c5dbd2cdd92c5..f1de472f9c74d 100644 --- a/Mathlib/Data/Finset/Basic.lean +++ b/Mathlib/Data/Finset/Basic.lean @@ -2979,7 +2979,7 @@ theorem filter_and (s : Finset α) : (s.filter fun a => p a ∧ q a) = s.filter #align finset.filter_and Finset.filter_and theorem filter_not (s : Finset α) : (s.filter fun a => ¬p a) = s \ s.filter p := - ext <| fun a => by + ext fun a => by simp only [Bool.decide_coe, Bool.not_eq_true', mem_filter, and_comm, mem_sdiff, not_and_or, Bool.not_eq_true, and_or_left, and_not_self, or_false] #align finset.filter_not Finset.filter_not diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean index c8d04c7b61c08..e3e890c9f61bf 100644 --- a/Mathlib/Data/Finset/Powerset.lean +++ b/Mathlib/Data/Finset/Powerset.lean @@ -334,7 +334,7 @@ theorem powersetCard_card_add (s : Finset α) {i : ℕ} (hi : 0 < i) : theorem powersetCard_map {β : Type*} (f : α ↪ β) (n : ℕ) (s : Finset α) : powersetCard n (s.map f) = (powersetCard n s).map (mapEmbedding f).toEmbedding := - ext <| fun t => by + ext fun t => by simp only [card_map, mem_powersetCard, le_eq_subset, gt_iff_lt, mem_map, mapEmbedding_apply] constructor · classical diff --git a/Mathlib/Data/Finsupp/Multiset.lean b/Mathlib/Data/Finsupp/Multiset.lean index a5d05ee98d4b2..2ec476e7efcaa 100644 --- a/Mathlib/Data/Finsupp/Multiset.lean +++ b/Mathlib/Data/Finsupp/Multiset.lean @@ -143,7 +143,7 @@ the multiplicities of the elements of `s`. -/ def toFinsupp : Multiset α ≃+ (α →₀ ℕ) where toFun s := ⟨s.toFinset, fun a => s.count a, fun a => by simp⟩ invFun f := Finsupp.toMultiset f - map_add' s t := Finsupp.ext <| fun _ => count_add _ _ _ + map_add' s t := Finsupp.ext fun _ => count_add _ _ _ right_inv f := Finsupp.ext fun a => by simp only [Finsupp.toMultiset_apply, Finsupp.sum, Multiset.count_sum', diff --git a/Mathlib/Data/Fintype/Basic.lean b/Mathlib/Data/Fintype/Basic.lean index f70dd3c8f5aaa..1ed5dfa4db982 100644 --- a/Mathlib/Data/Fintype/Basic.lean +++ b/Mathlib/Data/Fintype/Basic.lean @@ -1134,7 +1134,7 @@ instance pfunFintype (p : Prop) [Decidable p] (α : p → Type*) [∀ hp, Fintyp Fintype (∀ hp : p, α hp) := if hp : p then Fintype.ofEquiv (α hp) ⟨fun a _ => a, fun f => f hp, fun _ => rfl, fun _ => rfl⟩ else ⟨singleton fun h => (hp h).elim, fun h => mem_singleton.2 - (funext $ fun x => by contradiction)⟩ + (funext fun x => by contradiction)⟩ #align pfun_fintype pfunFintype theorem mem_image_univ_iff_mem_range {α β : Type*} [Fintype α] [DecidableEq β] {f : α → β} diff --git a/Mathlib/Data/Fintype/Pi.lean b/Mathlib/Data/Fintype/Pi.lean index ddb38b10f78a6..2d43eaaf8030d 100644 --- a/Mathlib/Data/Fintype/Pi.lean +++ b/Mathlib/Data/Fintype/Pi.lean @@ -93,7 +93,7 @@ lemma eval_image_piFinset_subset (t : ∀ a, Finset (δ a)) (a : α) [DecidableE lemma eval_image_piFinset (t : ∀ a, Finset (δ a)) (a : α) [DecidableEq (δ a)] (ht : ∀ b, a ≠ b → (t b).Nonempty) : ((piFinset t).image fun f ↦ f a) = t a := by - refine (eval_image_piFinset_subset _ _).antisymm $ fun x h ↦ mem_image.2 ?_ + refine (eval_image_piFinset_subset _ _).antisymm fun x h ↦ mem_image.2 ?_ choose f hf using ht exact ⟨fun b ↦ if h : a = b then h ▸ x else f _ h, by aesop, by simp⟩ diff --git a/Mathlib/Data/FunLike/Equiv.lean b/Mathlib/Data/FunLike/Equiv.lean index 9706d86143413..cb8e16fc8c21f 100644 --- a/Mathlib/Data/FunLike/Equiv.lean +++ b/Mathlib/Data/FunLike/Equiv.lean @@ -228,7 +228,7 @@ theorem comp_bijective (f : α → β) (e : F) : Function.Bijective (e ∘ f) /-- This is not an instance to avoid slowing down every single `Subsingleton` typeclass search.-/ lemma subsingleton_dom [Subsingleton β] : Subsingleton F := - ⟨fun f g ↦ FunLike.ext f g $ fun _ ↦ (right_inv f).injective $ Subsingleton.elim _ _⟩ + ⟨fun f g ↦ FunLike.ext f g fun _ ↦ (right_inv f).injective $ Subsingleton.elim _ _⟩ #align equiv_like.subsingleton_dom EquivLike.subsingleton_dom end EquivLike diff --git a/Mathlib/Data/List/Defs.lean b/Mathlib/Data/List/Defs.lean index b318571705e5b..590cfc212c838 100644 --- a/Mathlib/Data/List/Defs.lean +++ b/Mathlib/Data/List/Defs.lean @@ -79,7 +79,7 @@ def takeI [Inhabited α] (n : Nat) (l : List α) : List α := /-- `findM tac l` returns the first element of `l` on which `tac` succeeds, and fails otherwise. -/ def findM {α} {m : Type u → Type v} [Alternative m] (tac : α → m PUnit) : List α → m α := - List.firstM <| fun a => (tac a) $> a + List.firstM fun a => (tac a) $> a #align list.mfind List.findM /-- `findM? p l` returns the first element `a` of `l` for which `p a` returns diff --git a/Mathlib/Data/List/Forall2.lean b/Mathlib/Data/List/Forall2.lean index a69cd1833cd61..3041b64adb4f1 100644 --- a/Mathlib/Data/List/Forall2.lean +++ b/Mathlib/Data/List/Forall2.lean @@ -202,7 +202,7 @@ theorem forall₂_iff_zip {l₁ l₂} : · simp at h₁ · simp only [length_cons, succ.injEq] at h₁ exact Forall₂.cons (h₂ <| by simp [zip]) - (IH h₁ <| fun h => h₂ <| by + (IH h₁ fun h => h₂ <| by simp only [zip, zipWith, find?, mem_cons, Prod.mk.injEq]; right simpa [zip] using h)⟩ #align list.forall₂_iff_zip List.forall₂_iff_zip diff --git a/Mathlib/Data/List/Prime.lean b/Mathlib/Data/List/Prime.lean index 26308984878a3..de1cb9643a5cd 100644 --- a/Mathlib/Data/List/Prime.lean +++ b/Mathlib/Data/List/Prime.lean @@ -40,7 +40,7 @@ theorem Prime.dvd_prod_iff {p : M} {L : List M} (pp : Prime p) : p ∣ L.prod theorem Prime.not_dvd_prod {p : M} {L : List M} (pp : Prime p) (hL : ∀ a ∈ L, ¬p ∣ a) : ¬p ∣ L.prod := - mt (Prime.dvd_prod_iff pp).1 <| not_exists.2 <| fun a => not_and.2 (hL a) + mt (Prime.dvd_prod_iff pp).1 <| not_exists.2 fun a => not_and.2 (hL a) #align prime.not_dvd_prod Prime.not_dvd_prod end CommMonoidWithZero diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index 5021bd92f5060..c85e3afad4e5c 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -66,7 +66,7 @@ theorem sublists'_eq_sublists'Aux (l : List α) : theorem sublists'Aux_eq_map (a : α) (r₁ : List (List α)) : ∀ (r₂ : List (List α)), sublists'Aux a r₁ r₂ = r₂ ++ map (cons a) r₁ := - List.reverseRecOn r₁ (fun _ => by simp [sublists'Aux]) <| fun r₁ l ih r₂ => by + List.reverseRecOn r₁ (fun _ => by simp [sublists'Aux]) fun r₁ l ih r₂ => by rw [map_append, map_singleton, ← append_assoc, ← ih, sublists'Aux, foldl_append, foldl] simp [sublists'Aux] @@ -128,7 +128,7 @@ theorem sublistsAux_eq_array_foldl : theorem sublistsAux_eq_bind : sublistsAux = fun (a : α) (r : List (List α)) => r.bind fun l => [l, a :: l] := - funext <| fun a => funext <| fun r => + funext fun a => funext fun r => List.reverseRecOn r (by simp [sublistsAux]) (fun r l ih => by diff --git a/Mathlib/Data/Matrix/Basic.lean b/Mathlib/Data/Matrix/Basic.lean index 766d39ef76c21..d863e5ec54e0d 100644 --- a/Mathlib/Data/Matrix/Basic.lean +++ b/Mathlib/Data/Matrix/Basic.lean @@ -94,7 +94,7 @@ theorem ext : (∀ i j, M i j = N i j) → M = N := -- and restore the `@[ext]` attribute on `Matrix.ext` above. @[ext] theorem ext' : (∀ i, M i = N i) → M = N := - fun h => Matrix.ext <| fun i => by simp[h] + fun h => Matrix.ext fun i => by simp[h] end Ext diff --git a/Mathlib/Data/Matroid/Basic.lean b/Mathlib/Data/Matroid/Basic.lean index bf33d7e0425b8..e6219c7b71259 100644 --- a/Mathlib/Data/Matroid/Basic.lean +++ b/Mathlib/Data/Matroid/Basic.lean @@ -561,7 +561,7 @@ theorem Base.dep_of_insert (hB : M.Base B) (heB : e ∉ B) (he : e ∈ M.E := by M.Dep (insert e B) := hB.dep_of_ssubset (ssubset_insert heB) (insert_subset he hB.subset_ground) theorem Base.mem_of_insert_indep (hB : M.Base B) (heB : M.Indep (insert e B)) : e ∈ B := - by_contra <| fun he ↦ (hB.dep_of_insert he (heB.subset_ground (mem_insert _ _))).not_indep heB + by_contra fun he ↦ (hB.dep_of_insert he (heB.subset_ground (mem_insert _ _))).not_indep heB /-- If the difference of two Bases is a singleton, then they differ by an insertion/removal -/ theorem Base.eq_exchange_of_diff_eq_singleton (hB : M.Base B) (hB' : M.Base B') (h : B \ B' = {e}) : diff --git a/Mathlib/Data/Matroid/IndepAxioms.lean b/Mathlib/Data/Matroid/IndepAxioms.lean index 798b1f380f3fd..242f2b0e96b44 100644 --- a/Mathlib/Data/Matroid/IndepAxioms.lean +++ b/Mathlib/Data/Matroid/IndepAxioms.lean @@ -202,7 +202,7 @@ attribute [pp_dot] Indep E have := (hB₀fin.diff I).to_subtype refine ⟨iUnion f ∪ (B₀ ∩ I), union_subset (iUnion_subset (fun i ↦ (hf i).1)) (inter_subset_right _ _), - (finite_iUnion <| fun i ↦ (hf i).2.1).union (hB₀fin.subset (inter_subset_left _ _)), + (finite_iUnion fun i ↦ (hf i).2.1).union (hB₀fin.subset (inter_subset_left _ _)), fun x ⟨hxB₀, hxn⟩ hi ↦ ?_⟩ have hxI : x ∉ I := fun hxI ↦ hxn <| Or.inr ⟨hxB₀, hxI⟩ refine (hf ⟨x, ⟨hxB₀, hxI⟩⟩).2.2 (indep_subset hi <| insert_subset_insert ?_) diff --git a/Mathlib/Data/Multiset/Antidiagonal.lean b/Mathlib/Data/Multiset/Antidiagonal.lean index 5af2a2ae42d42..8f5e5aa349eab 100644 --- a/Mathlib/Data/Multiset/Antidiagonal.lean +++ b/Mathlib/Data/Multiset/Antidiagonal.lean @@ -45,7 +45,7 @@ in what used to be `simp [antidiagonal_coe]`. -/ @[simp] theorem mem_antidiagonal {s : Multiset α} {x : Multiset α × Multiset α} : x ∈ antidiagonal s ↔ x.1 + x.2 = s := - Quotient.inductionOn s <| fun l ↦ by + Quotient.inductionOn s fun l ↦ by dsimp only [quot_mk_to_coe, antidiagonal_coe] refine' ⟨fun h => revzip_powersetAux h, fun h ↦ _⟩ haveI := Classical.decEq α @@ -57,12 +57,12 @@ theorem mem_antidiagonal {s : Multiset α} {x : Multiset α × Multiset α} : @[simp] theorem antidiagonal_map_fst (s : Multiset α) : (antidiagonal s).map Prod.fst = powerset s := - Quotient.inductionOn s <| fun l ↦ by simp [powersetAux']; + Quotient.inductionOn s fun l ↦ by simp [powersetAux']; #align multiset.antidiagonal_map_fst Multiset.antidiagonal_map_fst @[simp] theorem antidiagonal_map_snd (s : Multiset α) : (antidiagonal s).map Prod.snd = powerset s := - Quotient.inductionOn s <| fun l ↦ by simp [powersetAux'] + Quotient.inductionOn s fun l ↦ by simp [powersetAux'] #align multiset.antidiagonal_map_snd Multiset.antidiagonal_map_snd @[simp] @@ -74,7 +74,7 @@ theorem antidiagonal_zero : @antidiagonal α 0 = {(0, 0)} := theorem antidiagonal_cons (a : α) (s) : antidiagonal (a ::ₘ s) = map (Prod.map id (cons a)) (antidiagonal s) + map (Prod.map (cons a) id) (antidiagonal s) := - Quotient.inductionOn s <| fun l ↦ by + Quotient.inductionOn s fun l ↦ by simp only [revzip, reverse_append, quot_mk_to_coe, coe_eq_coe, powersetAux'_cons, cons_coe, coe_map, antidiagonal_coe', coe_add] rw [← zip_map, ← zip_map, zip_append, (_ : _ ++ _ = _)] diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index fdb2cb1b51825..e0b3640e52acf 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -232,7 +232,7 @@ theorem mem_coe {a : α} {l : List α} : a ∈ (l : Multiset α) ↔ a ∈ l := #align multiset.mem_coe Multiset.mem_coe instance decidableMem [DecidableEq α] (a : α) (s : Multiset α) : Decidable (a ∈ s) := - Quot.recOnSubsingleton' s <| fun l ↦ inferInstanceAs (Decidable (a ∈ l)) + Quot.recOnSubsingleton' s fun l ↦ inferInstanceAs (Decidable (a ∈ l)) #align multiset.decidable_mem Multiset.decidableMem @[simp] @@ -433,7 +433,7 @@ theorem cons_subset_cons {a : α} {s t : Multiset α} : s ⊆ t → a ::ₘ s #align multiset.cons_subset_cons Multiset.cons_subset_cons theorem eq_zero_of_subset_zero {s : Multiset α} (h : s ⊆ 0) : s = 0 := - eq_zero_of_forall_not_mem $ fun _ hx ↦ not_mem_zero _ (h hx) + eq_zero_of_forall_not_mem fun _ hx ↦ not_mem_zero _ (h hx) #align multiset.eq_zero_of_subset_zero Multiset.eq_zero_of_subset_zero @[simp] lemma subset_zero : s ⊆ 0 ↔ s = 0 := @@ -1006,7 +1006,7 @@ theorem replicate_le_replicate (a : α) {k n : ℕ} : replicate k a ≤ replicat theorem le_replicate_iff {m : Multiset α} {a : α} {n : ℕ} : m ≤ replicate n a ↔ ∃ k ≤ n, m = replicate k a := ⟨fun h => ⟨card m, (card_mono h).trans_eq (card_replicate _ _), - eq_replicate_card.2 <| fun _ hb => eq_of_mem_replicate <| subset_of_le h hb⟩, + eq_replicate_card.2 fun _ hb => eq_of_mem_replicate <| subset_of_le h hb⟩, fun ⟨_, hkn, hm⟩ => hm.symm ▸ (replicate_le_replicate _).2 hkn⟩ #align multiset.le_replicate_iff Multiset.le_replicate_iff @@ -2539,14 +2539,14 @@ theorem count_replicate (a b : α) (n : ℕ) : count a (replicate n b) = if a = @[simp] theorem count_erase_self (a : α) (s : Multiset α) : count a (erase s a) = count a s - 1 := - Quotient.inductionOn s <| fun l => by + Quotient.inductionOn s fun l => by convert List.count_erase_self a l <;> rw [← coe_count] <;> simp #align multiset.count_erase_self Multiset.count_erase_self @[simp] theorem count_erase_of_ne {a b : α} (ab : a ≠ b) (s : Multiset α) : count a (erase s b) = count a s := - Quotient.inductionOn s <| fun l => by + Quotient.inductionOn s fun l => by convert List.count_erase_of_ne ab l <;> rw [← coe_count] <;> simp #align multiset.count_erase_of_ne Multiset.count_erase_of_ne @@ -2658,7 +2658,7 @@ theorem count_map_eq_count' [DecidableEq β] (f : α → β) (s : Multiset α) ( #align multiset.count_map_eq_count' Multiset.count_map_eq_count' theorem filter_eq' (s : Multiset α) (b : α) : s.filter (· = b) = replicate (count b s) b := - Quotient.inductionOn s <| fun l => by + Quotient.inductionOn s fun l => by simp only [quot_mk_to_coe, coe_filter, mem_coe, coe_count] rw [List.filter_eq l b, coe_replicate] #align multiset.filter_eq' Multiset.filter_eq' diff --git a/Mathlib/Data/Multiset/Nodup.lean b/Mathlib/Data/Multiset/Nodup.lean index 1a27d4e730c1e..0eb95e696fbce 100644 --- a/Mathlib/Data/Multiset/Nodup.lean +++ b/Mathlib/Data/Multiset/Nodup.lean @@ -272,7 +272,7 @@ theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset have : t = s.attach.map fun x => i x.1 x.2 · rw [ht.ext] · aesop - · exact hs.attach.map $ fun x y hxy ↦ Subtype.ext $ i_inj _ x.2 _ y.2 hxy + · exact hs.attach.map fun x y hxy ↦ Subtype.ext $ i_inj _ x.2 _ y.2 hxy calc s.map f = s.pmap (fun x _ => f x) fun _ => id := by rw [pmap_eq_map] _ = s.attach.map fun x => f x.1 := by rw [pmap_eq_map_attach] diff --git a/Mathlib/Data/Nat/Digits.lean b/Mathlib/Data/Nat/Digits.lean index 9152ca7f2aaa1..af18ab0eb595e 100644 --- a/Mathlib/Data/Nat/Digits.lean +++ b/Mathlib/Data/Nat/Digits.lean @@ -526,7 +526,7 @@ lemma ofDigits_div_pow_eq_ofDigits_drop induction' i with i hi · simp · rw [Nat.pow_succ, ← Nat.div_div_eq_div_mul, hi, ofDigits_div_eq_ofDigits_tail hpos - (List.drop i digits) <| fun x hx ↦ w₁ x <| List.mem_of_mem_drop hx, ← List.drop_one, + (List.drop i digits) fun x hx ↦ w₁ x <| List.mem_of_mem_drop hx, ← List.drop_one, List.drop_drop, add_comm] /-- Dividing `n` by `p^i` is like truncating the first `i` digits of `n` in base `p`. diff --git a/Mathlib/Data/PFun.lean b/Mathlib/Data/PFun.lean index da0cca946ca7e..04e1ff2901bd9 100644 --- a/Mathlib/Data/PFun.lean +++ b/Mathlib/Data/PFun.lean @@ -248,10 +248,10 @@ case `f.fix a` returns `f a`), or it is undefined (in which case `f.fix a` is un it is in the `α` part of `β ⊕ α` (in which case we repeat the procedure, so `f.fix a` will return `f.fix (f a)`). -/ def fix (f : α →. Sum β α) : α →. β := fun a => - Part.assert (Acc (fun x y => Sum.inr x ∈ f y) a) $ fun h => + Part.assert (Acc (fun x y => Sum.inr x ∈ f y) a) fun h => WellFounded.fixF (fun a IH => - Part.assert (f a).Dom $ fun hf => + Part.assert (f a).Dom fun hf => match e : (f a).get hf with | Sum.inl b => Part.some b | Sum.inr a' => IH a' ⟨hf, e⟩) diff --git a/Mathlib/Data/Real/CauSeq.lean b/Mathlib/Data/Real/CauSeq.lean index 397b449613c0d..6af31e21f5021 100644 --- a/Mathlib/Data/Real/CauSeq.lean +++ b/Mathlib/Data/Real/CauSeq.lean @@ -407,7 +407,7 @@ instance ring : Ring (CauSeq β abv) := instance {β : Type*} [CommRing β] {abv : β → α} [IsAbsoluteValue abv] : CommRing (CauSeq β abv) := { CauSeq.ring with - mul_comm := fun a b => ext $ fun n => by simp [mul_left_comm, mul_comm] } + mul_comm := fun a b => ext fun n => by simp [mul_left_comm, mul_comm] } /-- `LimZero f` holds when `f` approaches 0. -/ def LimZero {abv : β → α} (f : CauSeq β abv) : Prop := diff --git a/Mathlib/Data/Real/EReal.lean b/Mathlib/Data/Real/EReal.lean index c5cd416945687..64763dcbec277 100644 --- a/Mathlib/Data/Real/EReal.lean +++ b/Mathlib/Data/Real/EReal.lean @@ -715,7 +715,7 @@ theorem add_lt_add_of_lt_of_le' {x y z t : EReal} (h : x < y) (h' : z ≤ t) (hb assumptions. -/ theorem add_lt_add_of_lt_of_le {x y z t : EReal} (h : x < y) (h' : z ≤ t) (hz : z ≠ ⊥) (ht : t ≠ ⊤) : x + z < y + t := - add_lt_add_of_lt_of_le' h h' (ne_bot_of_le_ne_bot hz h') <| fun ht' => (ht ht').elim + add_lt_add_of_lt_of_le' h h' (ne_bot_of_le_ne_bot hz h') fun ht' => (ht ht').elim #align ereal.add_lt_add_of_lt_of_le EReal.add_lt_add_of_lt_of_le theorem add_lt_top {x y : EReal} (hx : x ≠ ⊤) (hy : y ≠ ⊤) : x + y < ⊤ := by diff --git a/Mathlib/Data/Real/Hyperreal.lean b/Mathlib/Data/Real/Hyperreal.lean index b7508f9a63eec..ac42712ab5828 100644 --- a/Mathlib/Data/Real/Hyperreal.lean +++ b/Mathlib/Data/Real/Hyperreal.lean @@ -294,7 +294,7 @@ theorem not_infinite_of_exists_st {x : ℝ*} : (∃ r : ℝ, IsSt x r) → ¬Inf #align hyperreal.not_infinite_of_exists_st Hyperreal.not_infinite_of_exists_st theorem Infinite.st_eq {x : ℝ*} (hi : Infinite x) : st x = 0 := - dif_neg <| fun ⟨_r, hr⟩ ↦ hr.not_infinite hi + dif_neg fun ⟨_r, hr⟩ ↦ hr.not_infinite hi #align hyperreal.st_infinite Hyperreal.Infinite.st_eq theorem isSt_sSup {x : ℝ*} (hni : ¬Infinite x) : IsSt x (sSup { y : ℝ | (y : ℝ*) < x }) := @@ -413,7 +413,7 @@ theorem IsSt.sub {x y : ℝ*} {r s : ℝ} (hxr : IsSt x r) (hys : IsSt y s) : Is #align hyperreal.is_st_sub Hyperreal.IsSt.sub theorem IsSt.le {x y : ℝ*} {r s : ℝ} (hrx : IsSt x r) (hsy : IsSt y s) (hxy : x ≤ y) : r ≤ s := - not_lt.1 <| fun h ↦ hxy.not_lt <| hsy.lt hrx h + not_lt.1 fun h ↦ hxy.not_lt <| hsy.lt hrx h #align hyperreal.is_st_le_of_le Hyperreal.IsSt.le theorem st_le_of_le {x y : ℝ*} (hix : ¬Infinite x) (hiy : ¬Infinite y) : x ≤ y → st x ≤ st y := diff --git a/Mathlib/Data/Semiquot.lean b/Mathlib/Data/Semiquot.lean index 807762648d638..20d8cd2bcdaee 100644 --- a/Mathlib/Data/Semiquot.lean +++ b/Mathlib/Data/Semiquot.lean @@ -263,7 +263,7 @@ theorem mem_univ [Inhabited α] : ∀ a, a ∈ @univ α _ := @[congr] theorem univ_unique (I J : Inhabited α) : @univ _ I = @univ _ J := - ext.2 <| fun a => refl (a ∈ univ) + ext.2 fun a => refl (a ∈ univ) #align semiquot.univ_unique Semiquot.univ_unique @[simp] diff --git a/Mathlib/Data/Set/Basic.lean b/Mathlib/Data/Set/Basic.lean index 678c9abb7a4f3..50a80707f9e09 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -1177,7 +1177,7 @@ theorem insert_subset_insert (h : s ⊆ t) : insert a s ⊆ insert a t := fun _ #align set.insert_subset_insert_iff Set.insert_subset_insert_iff theorem subset_insert_iff_of_not_mem (ha : a ∉ s) : s ⊆ insert a t ↔ s ⊆ t := - forall₂_congr <| fun _ hb => or_iff_right <| ne_of_mem_of_not_mem hb ha + forall₂_congr fun _ hb => or_iff_right <| ne_of_mem_of_not_mem hb ha #align set.subset_insert_iff_of_not_mem Set.subset_insert_iff_of_not_mem theorem ssubset_iff_insert {s t : Set α} : s ⊂ t ↔ ∃ a ∉ s, insert a s ⊆ t := by @@ -1255,7 +1255,7 @@ theorem ball_insert_iff {P : α → Prop} {a : α} {s : Set α} : /- porting note: instance was in core in Lean3 -/ instance : IsLawfulSingleton α (Set α) := - ⟨fun x => Set.ext <| fun a => by + ⟨fun x => Set.ext fun a => by simp only [mem_empty_iff_false, mem_insert_iff, or_false] exact Iff.rfl⟩ @@ -2674,7 +2674,7 @@ lemma Nonempty.exists_eq_singleton_or_nontrivial : s.Nonempty → (∃ a, s = {a #align set.nonempty.exists_eq_singleton_or_nontrivial Set.Nonempty.exists_eq_singleton_or_nontrivial theorem univ_eq_true_false : univ = ({True, False} : Set Prop) := - Eq.symm <| eq_univ_of_forall <| fun x => by + Eq.symm <| eq_univ_of_forall fun x => by rw [mem_insert_iff, mem_singleton_iff] exact Classical.propComplete x #align set.univ_eq_true_false Set.univ_eq_true_false diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index e061cc66ef6fc..a56f7b928f687 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -192,7 +192,7 @@ theorem coeSort_toFinset : ↥hs.toFinset = ↥s := by /-- The identity map, bundled as an equivalence between the subtypes of `s : Set α` and of `h.toFinset : Finset α`, where `h` is a proof of finiteness of `s`. -/ @[simps!] def subtypeEquivToFinset : {x // x ∈ s} ≃ {x // x ∈ hs.toFinset} := - (Equiv.refl α).subtypeEquiv <| fun _ ↦ hs.mem_toFinset.symm + (Equiv.refl α).subtypeEquiv fun _ ↦ hs.mem_toFinset.symm variable {hs} diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean index e97c5aa518e65..399ba0a3a5445 100644 --- a/Mathlib/Data/Set/Function.lean +++ b/Mathlib/Data/Set/Function.lean @@ -411,7 +411,7 @@ theorem mapsTo' : MapsTo f s t ↔ f '' s ⊆ t := #align set.maps_to' Set.mapsTo' theorem mapsTo_prod_map_diagonal : MapsTo (Prod.map f f) (diagonal α) (diagonal β) := - diagonal_subset_iff.2 <| fun _ => rfl + diagonal_subset_iff.2 fun _ => rfl #align set.maps_to_prod_map_diagonal Set.mapsTo_prod_map_diagonal theorem MapsTo.subset_preimage {f : α → β} {s : Set α} {t : Set β} (hf : MapsTo f s t) : @@ -1856,7 +1856,7 @@ lemma bijOn' (h₁ : MapsTo e s t) (h₂ : MapsTo e.symm t s) : BijOn e s t := #align equiv.bij_on' Equiv.bijOn' protected lemma bijOn (h : ∀ a, e a ∈ t ↔ a ∈ s) : BijOn e s t := - e.bijOn' (fun a ↦ (h _).2) $ fun b hb ↦ (h _).1 $ by rwa [apply_symm_apply] + e.bijOn' (fun a ↦ (h _).2) fun b hb ↦ (h _).1 $ by rwa [apply_symm_apply] #align equiv.bij_on Equiv.bijOn lemma invOn : InvOn e e.symm t s := @@ -1880,7 +1880,7 @@ alias ⟨_root_.Set.BijOn.of_equiv_symm, _root_.Set.BijOn.equiv_symm⟩ := bijOn variable [DecidableEq α] {a b : α} lemma bijOn_swap (ha : a ∈ s) (hb : b ∈ s) : BijOn (swap a b) s s := - (swap a b).bijOn $ fun x ↦ by + (swap a b).bijOn fun x ↦ by obtain rfl | hxa := eq_or_ne x a <;> obtain rfl | hxb := eq_or_ne x b <;> simp [*, swap_apply_of_ne_of_ne] diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index f034e42438bae..81b6dc6dab274 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -130,7 +130,7 @@ def iUnion_delab : Delab := whenPPOption Lean.getPPNotation do let ppTypes ← getPPOption getPPFunBinderTypes let stx ← SubExpr.withAppArg do let dom ← SubExpr.withBindingDomain delab - withBindingBodyUnusedName $ fun x => do + withBindingBodyUnusedName fun x => do let x : TSyntax `ident := .mk x let body ← delab if prop && !dep then @@ -158,7 +158,7 @@ def sInter_delab : Delab := whenPPOption Lean.getPPNotation do let ppTypes ← getPPOption getPPFunBinderTypes let stx ← SubExpr.withAppArg do let dom ← SubExpr.withBindingDomain delab - withBindingBodyUnusedName $ fun x => do + withBindingBodyUnusedName fun x => do let x : TSyntax `ident := .mk x let body ← delab if prop && !dep then diff --git a/Mathlib/Data/Set/List.lean b/Mathlib/Data/Set/List.lean index 4ded9393dd294..8d4e8a8e52161 100644 --- a/Mathlib/Data/Set/List.lean +++ b/Mathlib/Data/Set/List.lean @@ -47,7 +47,7 @@ theorem range_list_get? : range l.get? = insert none (some '' { x | x ∈ l }) : rw [← range_list_nthLe, ← range_comp] refine' (range_subset_iff.2 fun n => _).antisymm (insert_subset_iff.2 ⟨_, _⟩) exacts [(le_or_lt l.length n).imp get?_eq_none.2 (fun hlt => ⟨⟨_, hlt⟩, (get?_eq_get hlt).symm⟩), - ⟨_, get?_eq_none.2 le_rfl⟩, range_subset_iff.2 <| fun k => ⟨_, get?_eq_get _⟩] + ⟨_, get?_eq_none.2 le_rfl⟩, range_subset_iff.2 fun k => ⟨_, get?_eq_get _⟩] #align set.range_list_nth Set.range_list_get? @[simp] diff --git a/Mathlib/Data/Set/Prod.lean b/Mathlib/Data/Set/Prod.lean index 36f4eef0986a8..60d433696efe4 100644 --- a/Mathlib/Data/Set/Prod.lean +++ b/Mathlib/Data/Set/Prod.lean @@ -508,7 +508,7 @@ theorem mem_diagonal_iff {x : α × α} : x ∈ diagonal α ↔ x.1 = x.2 := #align set.mem_diagonal_iff Set.mem_diagonal_iff lemma diagonal_nonempty [Nonempty α] : (diagonal α).Nonempty := - Nonempty.elim ‹_› <| fun x => ⟨_, mem_diagonal x⟩ + Nonempty.elim ‹_› fun x => ⟨_, mem_diagonal x⟩ #align set.diagonal_nonempty Set.diagonal_nonempty instance decidableMemDiagonal [h : DecidableEq α] (x : α × α) : Decidable (x ∈ diagonal α) := diff --git a/Mathlib/Data/Sigma/Lex.lean b/Mathlib/Data/Sigma/Lex.lean index 2df844d8f8548..92bf4ac304216 100644 --- a/Mathlib/Data/Sigma/Lex.lean +++ b/Mathlib/Data/Sigma/Lex.lean @@ -70,7 +70,7 @@ theorem Lex.mono (hr : ∀ a b, r₁ a b → r₂ a b) (hs : ∀ i a b, s₁ i a theorem Lex.mono_left (hr : ∀ a b, r₁ a b → r₂ a b) {a b : Σ i, α i} (h : Lex r₁ s a b) : Lex r₂ s a b := - h.mono hr $ fun _ _ _ => id + h.mono hr fun _ _ _ => id #align sigma.lex.mono_left Sigma.Lex.mono_left theorem Lex.mono_right (hs : ∀ i a b, s₁ i a b → s₂ i a b) {a b : Σ i, α i} (h : Lex r s₁ a b) : @@ -178,7 +178,7 @@ theorem Lex.mono {r₁ r₂ : ι → ι → Prop} {s₁ s₂ : ∀ i, α i → theorem Lex.mono_left {r₁ r₂ : ι → ι → Prop} {s : ∀ i, α i → α i → Prop} (hr : ∀ a b, r₁ a b → r₂ a b) {a b : Σ' i, α i} (h : Lex r₁ s a b) : Lex r₂ s a b := - h.mono hr $ fun _ _ _ => id + h.mono hr fun _ _ _ => id #align psigma.lex.mono_left PSigma.Lex.mono_left theorem Lex.mono_right {r : ι → ι → Prop} {s₁ s₂ : ∀ i, α i → α i → Prop} diff --git a/Mathlib/Data/TypeVec.lean b/Mathlib/Data/TypeVec.lean index e5a84d7624755..2b46d72b0c826 100644 --- a/Mathlib/Data/TypeVec.lean +++ b/Mathlib/Data/TypeVec.lean @@ -116,7 +116,7 @@ theorem drop_append1 {α : TypeVec n} {β : Type*} {i : Fin2 n} : drop (append1 #align typevec.drop_append1 TypeVec.drop_append1 theorem drop_append1' {α : TypeVec n} {β : Type*} : drop (append1 α β) = α := - funext <| fun _ => drop_append1 + funext fun _ => drop_append1 #align typevec.drop_append1' TypeVec.drop_append1' theorem last_append1 {α : TypeVec n} {β : Type*} : last (append1 α β) = β := diff --git a/Mathlib/FieldTheory/Fixed.lean b/Mathlib/FieldTheory/Fixed.lean index cb2d229512be5..5507a68d14dfd 100644 --- a/Mathlib/FieldTheory/Fixed.lean +++ b/Mathlib/FieldTheory/Fixed.lean @@ -314,7 +314,7 @@ theorem linearIndependent_toLinearMap (R : Type u) (A : Type v) (B : Type w) [Co LinearIndependent B (AlgHom.toLinearMap : (A →ₐ[R] B) → A →ₗ[R] B) := have : LinearIndependent B (LinearMap.ltoFun R A B ∘ AlgHom.toLinearMap) := ((linearIndependent_monoidHom A B).comp ((↑) : (A →ₐ[R] B) → A →* B) fun _ _ hfg => - AlgHom.ext <| fun _ => FunLike.ext_iff.1 hfg _ : + AlgHom.ext fun _ => FunLike.ext_iff.1 hfg _ : _) this.of_comp _ #align linear_independent_to_linear_map linearIndependent_toLinearMap diff --git a/Mathlib/FieldTheory/IsSepClosed.lean b/Mathlib/FieldTheory/IsSepClosed.lean index 9faecc88e75f6..d455deb141c88 100644 --- a/Mathlib/FieldTheory/IsSepClosed.lean +++ b/Mathlib/FieldTheory/IsSepClosed.lean @@ -93,7 +93,7 @@ theorem exists_root [IsSepClosed k] (p : k[X]) (hp : p.degree ≠ 0) (hsep : p.S theorem exists_pow_nat_eq [IsSepClosed k] (x : k) (n : ℕ) [hn : NeZero (n : k)] : ∃ z, z ^ n = x := by - have hn' : 0 < n := Nat.pos_of_ne_zero <| fun h => by + have hn' : 0 < n := Nat.pos_of_ne_zero fun h => by rw [h, Nat.cast_zero] at hn exact hn.out rfl have : degree (X ^ n - C x) ≠ 0 := by diff --git a/Mathlib/FieldTheory/Perfect.lean b/Mathlib/FieldTheory/Perfect.lean index 806175a7b9808..926294a0eaaf9 100644 --- a/Mathlib/FieldTheory/Perfect.lean +++ b/Mathlib/FieldTheory/Perfect.lean @@ -168,7 +168,7 @@ class PerfectField (K : Type*) [Field K] : Prop where lemma PerfectRing.toPerfectField (K : Type*) (p : ℕ) [Field K] [hp : Fact p.Prime] [CharP K p] [PerfectRing K p] : PerfectField K := by - refine' PerfectField.mk $ fun hf ↦ _ + refine' PerfectField.mk fun hf ↦ _ rcases separable_or p hf with h | ⟨-, g, -, rfl⟩ · assumption · exfalso; revert hf; simp @@ -188,7 +188,7 @@ variable [PerfectField K] /-- A perfect field of characteristic `p` (prime) is a perfect ring. -/ instance toPerfectRing (p : ℕ) [hp : Fact p.Prime] [CharP K p] : PerfectRing K p := by - refine' PerfectRing.ofSurjective _ _ $ fun y ↦ _ + refine' PerfectRing.ofSurjective _ _ fun y ↦ _ let f : K[X] := X ^ p - C y let L := f.SplittingField let ι := algebraMap K L diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean index a401c7593796e..fe70c9b5b9745 100644 --- a/Mathlib/FieldTheory/SeparableDegree.lean +++ b/Mathlib/FieldTheory/SeparableDegree.lean @@ -207,7 +207,7 @@ def embEquivOfAdjoinSplits {S : Set E} (hS : adjoin F S = ⊤) (hK : ∀ s ∈ S, IsIntegral F s ∧ Splits (algebraMap F K) (minpoly F s)) : Emb F E ≃ (E →ₐ[F] K) := have halg := (topEquiv (F := F) (E := E)).isAlgebraic - (hS ▸ isAlgebraic_adjoin (S := S) <| fun x hx ↦ (hK x hx).1) + (hS ▸ isAlgebraic_adjoin (S := S) fun x hx ↦ (hK x hx).1) Classical.choice <| Function.Embedding.antisymm (halg.algHomEmbeddingOfSplits (fun _ ↦ splits_of_mem_adjoin F (S := S) hK (hS ▸ mem_top)) _) (halg.algHomEmbeddingOfSplits (fun _ ↦ IsAlgClosed.splits_codomain _) _) @@ -223,7 +223,7 @@ theorem finSepDegree_eq_of_adjoin_splits {S : Set E} (hS : adjoin F S = ⊤) and `K / F` is algebraically closed. -/ def embEquivOfIsAlgClosed (halg : Algebra.IsAlgebraic F E) [IsAlgClosed K] : Emb F E ≃ (E →ₐ[F] K) := - embEquivOfAdjoinSplits F E K (adjoin_univ F E) <| fun s _ ↦ + embEquivOfAdjoinSplits F E K (adjoin_univ F E) fun s _ ↦ ⟨(halg s).isIntegral, IsAlgClosed.splits_codomain _⟩ /-- The `Field.finSepDegree F E` is equal to the cardinality of `E →ₐ[F] K` as a natural number, @@ -528,7 +528,7 @@ private theorem finSepDegree_adjoin_simple_dvd_finrank (α : E) : by_cases halg : IsAlgebraic F α · rw [finSepDegree_adjoin_simple_eq_natSepDegree F E halg, adjoin.finrank halg.isIntegral] exact (minpoly.irreducible halg.isIntegral).natSepDegree_dvd_natDegree - have : finrank F F⟮α⟯ = 0 := finrank_of_infinite_dimensional <| fun _ ↦ + have : finrank F F⟮α⟯ = 0 := finrank_of_infinite_dimensional fun _ ↦ halg ((AdjoinSimple.isIntegral_gen F α).1 (IsIntegral.of_finite F _)).isAlgebraic rw [this] exact dvd_zero _ diff --git a/Mathlib/Geometry/Euclidean/Inversion/ImageHyperplane.lean b/Mathlib/Geometry/Euclidean/Inversion/ImageHyperplane.lean index e5ad0afcff3e1..1a046fcb561bb 100644 --- a/Mathlib/Geometry/Euclidean/Inversion/ImageHyperplane.lean +++ b/Mathlib/Geometry/Euclidean/Inversion/ImageHyperplane.lean @@ -82,5 +82,5 @@ theorem mapsTo_inversion_affineSubspace_of_mem {p : AffineSubspace ℝ P} (hp : /-- Inversion sends an affine subspace passing through the center to itself. -/ theorem image_inversion_affineSubspace_of_mem {p : AffineSubspace ℝ P} (hR : R ≠ 0) (hp : c ∈ p) : inversion c R '' p = p := - (mapsTo_inversion_affineSubspace_of_mem hp).image_subset.antisymm <| fun x hx ↦ + (mapsTo_inversion_affineSubspace_of_mem hp).image_subset.antisymm fun x hx ↦ ⟨inversion c R x, mapsTo_inversion_affineSubspace_of_mem hp hx, inversion_inversion _ hR _⟩ diff --git a/Mathlib/Geometry/Euclidean/PerpBisector.lean b/Mathlib/Geometry/Euclidean/PerpBisector.lean index 323bae597a520..55e73920e4349 100644 --- a/Mathlib/Geometry/Euclidean/PerpBisector.lean +++ b/Mathlib/Geometry/Euclidean/PerpBisector.lean @@ -108,7 +108,7 @@ theorem perpBisector_comm (p₁ p₂ : P) : perpBisector p₁ p₂ = perpBisecto rw [perpBisector_comm, right_mem_perpBisector, eq_comm] @[simp] theorem perpBisector_self (p : P) : perpBisector p p = ⊤ := - top_unique <| fun _ ↦ by simp [mem_perpBisector_iff_inner_eq_inner] + top_unique fun _ ↦ by simp [mem_perpBisector_iff_inner_eq_inner] @[simp] theorem perpBisector_eq_top : perpBisector p₁ p₂ = ⊤ ↔ p₁ = p₂ := by refine ⟨fun h ↦ ?_, fun h ↦ h ▸ perpBisector_self _⟩ diff --git a/Mathlib/GroupTheory/Congruence.lean b/Mathlib/GroupTheory/Congruence.lean index 447b5edf370ed..19074e28d5b3d 100644 --- a/Mathlib/GroupTheory/Congruence.lean +++ b/Mathlib/GroupTheory/Congruence.lean @@ -793,7 +793,7 @@ theorem mem_coe {c : Con M} {x y} : (x, y) ∈ (↑c : Submonoid (M × M)) ↔ ( @[to_additive] theorem to_submonoid_inj (c d : Con M) (H : (c : Submonoid (M × M)) = d) : c = d := - ext <| fun x y => show (x, y) ∈ c.submonoid ↔ (x, y) ∈ d from H ▸ Iff.rfl + ext fun x y => show (x, y) ∈ c.submonoid ↔ (x, y) ∈ d from H ▸ Iff.rfl #align con.to_submonoid_inj Con.to_submonoid_inj #align add_con.to_add_submonoid_inj AddCon.to_addSubmonoid_inj diff --git a/Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean b/Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean index a90ef20c46ace..f469c600938f6 100644 --- a/Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean +++ b/Mathlib/GroupTheory/GroupAction/DomAct/Basic.lean @@ -172,7 +172,7 @@ instance [SMul M α] [SMul N α] [SMulCommClass M N α] : SMulCommClass Mᵈᵐ @[to_additive] instance [SMul M α] [FaithfulSMul M α] [Nontrivial β] : FaithfulSMul Mᵈᵐᵃ (α → β) where - eq_of_smul_eq_smul {c₁ c₂} h := mk.symm.injective <| eq_of_smul_eq_smul <| fun a : α ↦ by + eq_of_smul_eq_smul {c₁ c₂} h := mk.symm.injective <| eq_of_smul_eq_smul fun a : α ↦ by rcases exists_pair_ne β with ⟨x, y, hne⟩ contrapose! hne haveI := Classical.decEq α diff --git a/Mathlib/GroupTheory/OrderOfElement.lean b/Mathlib/GroupTheory/OrderOfElement.lean index 65a0591141215..c816151e078da 100644 --- a/Mathlib/GroupTheory/OrderOfElement.lean +++ b/Mathlib/GroupTheory/OrderOfElement.lean @@ -288,7 +288,7 @@ protected lemma IsOfFinOrder.mem_powers_iff_mem_range_orderOf [DecidableEq G] @[to_additive IsOfFinAddOrder.powers_eq_image_range_orderOf] protected lemma IsOfFinOrder.powers_eq_image_range_orderOf [DecidableEq G] (hx : IsOfFinOrder x) : (Submonoid.powers x : Set G) = (Finset.range (orderOf x)).image (x ^ ·) := - Set.ext $ fun _ ↦ hx.mem_powers_iff_mem_range_orderOf + Set.ext fun _ ↦ hx.mem_powers_iff_mem_range_orderOf @[to_additive] theorem pow_eq_one_iff_modEq : x ^ n = 1 ↔ n ≡ 0 [MOD orderOf x] := by diff --git a/Mathlib/GroupTheory/Perm/Basic.lean b/Mathlib/GroupTheory/Perm/Basic.lean index 0278b9e22a9cc..ef4b9df6aeab6 100644 --- a/Mathlib/GroupTheory/Perm/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Basic.lean @@ -607,7 +607,7 @@ variable [AddGroup α] (a b : α) #align equiv.add_left_add Equiv.addLeft_add @[simp] lemma addRight_add : Equiv.addRight (a + b) = Equiv.addRight b * Equiv.addRight a := - ext $ fun _ ↦ (add_assoc _ _ _).symm + ext fun _ ↦ (add_assoc _ _ _).symm #align equiv.add_right_add Equiv.addRight_add @[simp] lemma inv_addLeft : (Equiv.addLeft a)⁻¹ = Equiv.addLeft (-a) := Equiv.coe_inj.1 rfl @@ -654,7 +654,7 @@ lemma mulLeft_mul : Equiv.mulLeft (a * b) = Equiv.mulLeft a * Equiv.mulLeft b := @[to_additive existing (attr := simp)] lemma mulRight_mul : Equiv.mulRight (a * b) = Equiv.mulRight b * Equiv.mulRight a := - ext $ fun _ ↦ (mul_assoc _ _ _).symm + ext fun _ ↦ (mul_assoc _ _ _).symm #align equiv.mul_right_mul Equiv.mulRight_mul @[to_additive existing (attr := simp) inv_addLeft] diff --git a/Mathlib/GroupTheory/PushoutI.lean b/Mathlib/GroupTheory/PushoutI.lean index 9d4feaead5dcf..70f378df31c31 100644 --- a/Mathlib/GroupTheory/PushoutI.lean +++ b/Mathlib/GroupTheory/PushoutI.lean @@ -102,7 +102,7 @@ def lift (f : ∀ i, G i →* K) (k : H →* K) (hf : ∀ i, (f i).comp (φ i) = k) : PushoutI φ →* K := Con.lift _ (Coprod.lift (CoprodI.lift f) k) <| by - apply Con.conGen_le <| fun x y => ?_ + apply Con.conGen_le fun x y => ?_ rintro ⟨i, x', rfl, rfl⟩ simp only [FunLike.ext_iff, MonoidHom.coe_comp, comp_apply] at hf simp [hf] diff --git a/Mathlib/GroupTheory/Transfer.lean b/Mathlib/GroupTheory/Transfer.lean index 40e81534d69a2..881ab8c8dd39d 100644 --- a/Mathlib/GroupTheory/Transfer.lean +++ b/Mathlib/GroupTheory/Transfer.lean @@ -79,7 +79,7 @@ theorem diff_inv : (diff ϕ S T)⁻¹ = diff ϕ T S := @[to_additive] theorem smul_diff_smul (g : G) : diff ϕ (g • S) (g • T) = diff ϕ S T := let _ := H.fintypeQuotientOfFiniteIndex - Fintype.prod_equiv (MulAction.toPerm g).symm _ _ $ fun _ ↦ by + Fintype.prod_equiv (MulAction.toPerm g).symm _ _ fun _ ↦ by simp only [smul_apply_eq_smul_apply_inv_smul, smul_eq_mul, mul_inv_rev, mul_assoc, inv_mul_cancel_left, toPerm_symm_apply] #align subgroup.left_transversals.smul_diff_smul Subgroup.leftTransversals.smul_diff_smul diff --git a/Mathlib/Init/Data/List/Instances.lean b/Mathlib/Init/Data/List/Instances.lean index aee160504f5c6..17815db2c5dee 100644 --- a/Mathlib/Init/Data/List/Instances.lean +++ b/Mathlib/Init/Data/List/Instances.lean @@ -78,7 +78,7 @@ instance decidableBex : ∀ (l : List α), Decidable (∃ x ∈ l, p x) instance decidableBall (l : List α) : Decidable (∀ x ∈ l, p x) := match (inferInstance : Decidable <| ∃ x ∈ l, ¬ p x) with - | isFalse h => isTrue $ fun x hx => match ‹DecidablePred p› x with + | isFalse h => isTrue fun x hx => match ‹DecidablePred p› x with | isTrue h' => h' | isFalse h' => False.elim $ h ⟨x, hx, h'⟩ | isTrue h => isFalse <| let ⟨x, h, np⟩ := h; fun al => np (al x h) diff --git a/Mathlib/Lean/Expr/Traverse.lean b/Mathlib/Lean/Expr/Traverse.lean index 883f521e20b3e..0a01a77851920 100644 --- a/Mathlib/Lean/Expr/Traverse.lean +++ b/Mathlib/Lean/Expr/Traverse.lean @@ -28,7 +28,7 @@ def traverseChildren [Applicative M] (f : Expr → M Expr) : Expr → M Expr /-- `e.foldlM f a` folds the monadic function `f` over the subterms of the expression `e`, with initial value `a`. -/ def foldlM {α : Type} {m} [Monad m] (f : α → Expr → m α) (x : α) (e : Expr) : m α := - Prod.snd <$> (StateT.run (e.traverseChildren $ fun e' => + Prod.snd <$> (StateT.run (e.traverseChildren fun e' => Functor.mapConst e' (get >>= monadLift ∘ flip f e' >>= set)) x : m _) end Lean.Expr diff --git a/Mathlib/LinearAlgebra/BilinearForm/Basic.lean b/Mathlib/LinearAlgebra/BilinearForm/Basic.lean index e5452c4decaa7..d7313f3286aa3 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Basic.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Basic.lean @@ -236,17 +236,17 @@ theorem smul_apply {α} [Monoid α] [DistribMulAction α R] [SMulCommClass α R instance {α β} [Monoid α] [Monoid β] [DistribMulAction α R] [DistribMulAction β R] [SMulCommClass α R R] [SMulCommClass β R R] [SMulCommClass α β R] : SMulCommClass α β (BilinForm R M) := - ⟨fun a b B => ext $ fun x y => smul_comm a b (B x y)⟩ + ⟨fun a b B => ext fun x y => smul_comm a b (B x y)⟩ instance {α β} [Monoid α] [Monoid β] [SMul α β] [DistribMulAction α R] [DistribMulAction β R] [SMulCommClass α R R] [SMulCommClass β R R] [IsScalarTower α β R] : IsScalarTower α β (BilinForm R M) := - ⟨fun a b B => ext $ fun x y => smul_assoc a b (B x y)⟩ + ⟨fun a b B => ext fun x y => smul_assoc a b (B x y)⟩ instance {α} [Monoid α] [DistribMulAction α R] [DistribMulAction αᵐᵒᵖ R] [SMulCommClass α R R] [IsCentralScalar α R] : IsCentralScalar α (BilinForm R M) := - ⟨fun a B => ext $ fun x y => op_smul_eq_smul a (B x y)⟩ + ⟨fun a B => ext fun x y => op_smul_eq_smul a (B x y)⟩ instance : AddCommMonoid (BilinForm R M) := Function.Injective.addCommMonoid _ coe_injective coe_zero coe_add fun _ _ => coe_smul _ _ diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean index 5f83f8a7c9375..baf99539b5db7 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Conjugation.lean @@ -92,8 +92,8 @@ theorem reverseOp_ι (m : M) : reverseOp (ι Q m) = op (ι Q m) := lift_ι_apply @[simps! apply] def reverseOpEquiv : CliffordAlgebra Q ≃ₐ[R] (CliffordAlgebra Q)ᵐᵒᵖ := AlgEquiv.ofAlgHom reverseOp (AlgHom.opComm reverseOp) - (AlgHom.unop.injective <| hom_ext <| LinearMap.ext <| fun _ => by simp) - (hom_ext <| LinearMap.ext <| fun _ => by simp) + (AlgHom.unop.injective <| hom_ext <| LinearMap.ext fun _ => by simp) + (hom_ext <| LinearMap.ext fun _ => by simp) @[simp] theorem reverseOpEquiv_opComm : diff --git a/Mathlib/LinearAlgebra/DFinsupp.lean b/Mathlib/LinearAlgebra/DFinsupp.lean index f410c50cea64c..53432a58a766b 100644 --- a/Mathlib/LinearAlgebra/DFinsupp.lean +++ b/Mathlib/LinearAlgebra/DFinsupp.lean @@ -362,7 +362,7 @@ lemma mem_iSup_iff_exists_finsupp (p : ι → Submodule R N) (x : N) : rw [mem_iSup_iff_exists_dfinsupp'] refine ⟨fun ⟨f, hf⟩ ↦ ⟨⟨f.support, fun i ↦ (f i : N), by simp⟩, by simp, hf⟩, ?_⟩ rintro ⟨f, hf, rfl⟩ - refine ⟨DFinsupp.mk f.support <| fun i ↦ ⟨f i, hf i⟩, Finset.sum_congr ?_ fun i hi ↦ ?_⟩ + refine ⟨DFinsupp.mk f.support fun i ↦ ⟨f i, hf i⟩, Finset.sum_congr ?_ fun i hi ↦ ?_⟩ · ext; simp · simp [Finsupp.mem_support_iff.mp hi] diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean index b0c4ba710772c..dc41f54cd5260 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean @@ -397,7 +397,7 @@ theorem independent_generalizedEigenspace [NoZeroSMulDivisors R M] (f : End R M) any eigenspace has trivial intersection with the span of all the other eigenspaces. -/ theorem eigenspaces_independent [NoZeroSMulDivisors R M] (f : End R M) : CompleteLattice.Independent f.eigenspace := - f.independent_generalizedEigenspace.mono <| fun μ ↦ le_iSup (generalizedEigenspace f μ) 1 + f.independent_generalizedEigenspace.mono fun μ ↦ le_iSup (generalizedEigenspace f μ) 1 /-- Eigenvectors corresponding to distinct eigenvalues of a linear operator are linearly independent. (Lemma 5.10 of [axler2015]) diff --git a/Mathlib/LinearAlgebra/InvariantBasisNumber.lean b/Mathlib/LinearAlgebra/InvariantBasisNumber.lean index 1ad622db73b09..1b05b8673a89f 100644 --- a/Mathlib/LinearAlgebra/InvariantBasisNumber.lean +++ b/Mathlib/LinearAlgebra/InvariantBasisNumber.lean @@ -199,7 +199,7 @@ theorem nontrivial_of_invariantBasisNumber : Nontrivial R := by refine' zero_ne_one (eq_of_fin_equiv R _) haveI := not_nontrivial_iff_subsingleton.1 h haveI : Subsingleton (Fin 1 → R) := - Subsingleton.intro <| fun a b => funext fun x => Subsingleton.elim _ _ + Subsingleton.intro fun a b => funext fun x => Subsingleton.elim _ _ exact { toFun := 0 invFun := 0 diff --git a/Mathlib/LinearAlgebra/Matrix/PosDef.lean b/Mathlib/LinearAlgebra/Matrix/PosDef.lean index a71114b77a639..087e3c9586d13 100644 --- a/Mathlib/LinearAlgebra/Matrix/PosDef.lean +++ b/Mathlib/LinearAlgebra/Matrix/PosDef.lean @@ -52,7 +52,7 @@ def PosSemidef (M : Matrix n n R) := lemma posSemidef_diagonal_iff [DecidableEq n] {d : n → R} : PosSemidef (diagonal d) ↔ (∀ i : n, 0 ≤ d i) := by refine ⟨fun ⟨_, hP⟩ i ↦ by simpa using hP (Pi.single i 1), ?_⟩ - refine fun hd ↦ ⟨isHermitian_diagonal_iff.2 <| fun i ↦ IsSelfAdjoint.of_nonneg (hd i), ?_⟩ + refine fun hd ↦ ⟨isHermitian_diagonal_iff.2 fun i ↦ IsSelfAdjoint.of_nonneg (hd i), ?_⟩ refine fun x ↦ Finset.sum_nonneg fun i _ ↦ ?_ simpa only [mulVec_diagonal, mul_assoc] using conjugate_nonneg (hd i) _ diff --git a/Mathlib/LinearAlgebra/Matrix/Spectrum.lean b/Mathlib/LinearAlgebra/Matrix/Spectrum.lean index 8f03821568c01..4d38c25ccaa4c 100644 --- a/Mathlib/LinearAlgebra/Matrix/Spectrum.lean +++ b/Mathlib/LinearAlgebra/Matrix/Spectrum.lean @@ -81,7 +81,7 @@ theorem eigenvectorMatrix_apply (i j : n) : hA.eigenvectorMatrix i j = hA.eigenv /-- The columns of `Matrix.IsHermitian.eigenVectorMatrix` form the basis-/ theorem transpose_eigenvectorMatrix_apply (i : n) : hA.eigenvectorMatrixᵀ i = hA.eigenvectorBasis i := - funext <| fun j => eigenvectorMatrix_apply hA j i + funext fun j => eigenvectorMatrix_apply hA j i theorem eigenvectorMatrixInv_apply (i j : n) : hA.eigenvectorMatrixInv i j = star (hA.eigenvectorBasis i j) := by diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean index 2a21b5fa08c4e..309f280cad304 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean @@ -401,10 +401,10 @@ theorem smul_apply (a : S) (Q : QuadraticForm R M) (x : M) : (a • Q) x = a • #align quadratic_form.smul_apply QuadraticForm.smul_apply instance [SMulCommClass S T R] : SMulCommClass S T (QuadraticForm R M) where - smul_comm _s _t _q := ext <| fun _ => smul_comm _ _ _ + smul_comm _s _t _q := ext fun _ => smul_comm _ _ _ instance [SMul S T] [IsScalarTower S T R] : IsScalarTower S T (QuadraticForm R M) where - smul_assoc _s _t _q := ext <| fun _ => smul_assoc _ _ _ + smul_assoc _s _t _q := ext fun _ => smul_assoc _ _ _ end SMul @@ -765,7 +765,7 @@ theorem polarBilin_toQuadraticForm : polarBilin (toQuadraticForm B) = B + flip' @[simp] theorem _root_.QuadraticForm.toQuadraticForm_polarBilin (Q : QuadraticForm R M) : toQuadraticForm (polarBilin Q) = 2 • Q := - QuadraticForm.ext <| fun x => (polar_self _ x).trans <| by simp + QuadraticForm.ext fun x => (polar_self _ x).trans <| by simp theorem _root_.QuadraticForm.polarBilin_injective (h : IsUnit (2 : R)) : Function.Injective (polarBilin : QuadraticForm R M → _) := @@ -778,7 +778,7 @@ variable [AddCommGroup N] [Module R N] theorem _root_.QuadraticForm.polarBilin_comp (Q : QuadraticForm R N) (f : M →ₗ[R] N) : polarBilin (Q.comp f) = BilinForm.comp (polarBilin Q) f f := - BilinForm.ext <| fun x y => by simp [polar] + BilinForm.ext fun x y => by simp [polar] theorem _root_.LinearMap.compQuadraticForm_polar (f : R →ₗ[S] S) (Q : QuadraticForm R M) (x y : M) : polar (f.compQuadraticForm Q) x y = f (polar Q x y) := by diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean b/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean index 474aaceb3d6ec..68b41401710ac 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean @@ -313,7 +313,7 @@ variable [Fintype ι] @[simp] theorem polarBilin_pi (Q : ∀ i, QuadraticForm R (Mᵢ i)) : (pi Q).polarBilin = ∑ i, (Q i).polarBilin.comp (.proj i) (.proj i) := - BilinForm.ext <| fun x y => (polar_pi _ _ _).trans <| by simp + BilinForm.ext fun x y => (polar_pi _ _ _).trans <| by simp @[simp] theorem associated_pi [Invertible (2 : R)] (Q : ∀ i, QuadraticForm R (Mᵢ i)) : associated (pi Q) = ∑ i, (Q i).associated.comp (.proj i) (.proj i) := by diff --git a/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean b/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean index 141bddf90affa..988419527c93c 100644 --- a/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean +++ b/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean @@ -43,7 +43,7 @@ noncomputable def equivFreeAlgebra (b : Basis κ R M) : (TensorAlgebra.lift _ (Finsupp.total _ _ _ (FreeAlgebra.ι _) ∘ₗ b.repr.toLinearMap)) (FreeAlgebra.lift _ (ι R ∘ b)) (by ext; simp) - (hom_ext <| b.ext <| fun i => by simp) + (hom_ext <| b.ext fun i => by simp) @[simp] lemma equivFreeAlgebra_ι_apply (b : Basis κ R M) (i : κ) : diff --git a/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean b/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean index 9397932378d0f..5348d74a90b84 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean @@ -166,13 +166,13 @@ noncomputable def lTensor.inverse_of_rightInverse {h : P → N} (hgh : Function. Q ⊗[R] P →ₗ[R] Q ⊗[R] N ⧸ LinearMap.range (lTensor Q f) := TensorProduct.lift <| LinearMap.flip <| { toFun := fun p ↦ Submodule.mkQ _ ∘ₗ ((TensorProduct.mk R _ _).flip (h p)) - map_add' := fun p p' => LinearMap.ext <| fun q => (Submodule.Quotient.eq _).mpr <| by + map_add' := fun p p' => LinearMap.ext fun q => (Submodule.Quotient.eq _).mpr <| by change q ⊗ₜ[R] (h (p + p')) - (q ⊗ₜ[R] (h p) + q ⊗ₜ[R] (h p')) ∈ range (lTensor Q f) rw [← TensorProduct.tmul_add, ← TensorProduct.tmul_sub] apply le_comap_range_lTensor f rw [exact_iff] at hfg simp only [← hfg, mem_ker, map_sub, map_add, hgh _, sub_self] - map_smul' := fun r p => LinearMap.ext <| fun q => (Submodule.Quotient.eq _).mpr <| by + map_smul' := fun r p => LinearMap.ext fun q => (Submodule.Quotient.eq _).mpr <| by change q ⊗ₜ[R] (h (r • p)) - r • q ⊗ₜ[R] (h p) ∈ range (lTensor Q f) rw [← TensorProduct.tmul_smul, ← TensorProduct.tmul_sub] apply le_comap_range_lTensor f @@ -271,13 +271,13 @@ noncomputable def rTensor.inverse_of_rightInverse {h : P → N} (hgh : Function. P ⊗[R] Q →ₗ[R] N ⊗[R] Q ⧸ LinearMap.range (rTensor Q f) := TensorProduct.lift { toFun := fun p ↦ Submodule.mkQ _ ∘ₗ TensorProduct.mk R _ _ (h p) - map_add' := fun p p' => LinearMap.ext <| fun q => (Submodule.Quotient.eq _).mpr <| by + map_add' := fun p p' => LinearMap.ext fun q => (Submodule.Quotient.eq _).mpr <| by change h (p + p') ⊗ₜ[R] q - (h p ⊗ₜ[R] q + h p' ⊗ₜ[R] q) ∈ range (rTensor Q f) rw [← TensorProduct.add_tmul, ← TensorProduct.sub_tmul] apply le_comap_range_rTensor f rw [exact_iff] at hfg simp only [← hfg, mem_ker, map_sub, map_add, hgh _, sub_self] - map_smul' := fun r p => LinearMap.ext <| fun q => (Submodule.Quotient.eq _).mpr <| by + map_smul' := fun r p => LinearMap.ext fun q => (Submodule.Quotient.eq _).mpr <| by change h (r • p) ⊗ₜ[R] q - r • h p ⊗ₜ[R] q ∈ range (rTensor Q f) rw [TensorProduct.smul_tmul', ← TensorProduct.sub_tmul] apply le_comap_range_rTensor f diff --git a/Mathlib/LinearAlgebra/TensorProduct/Tower.lean b/Mathlib/LinearAlgebra/TensorProduct/Tower.lean index eadb31e280940..9f58349440d74 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Tower.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Tower.lean @@ -303,7 +303,7 @@ protected def rid : M ⊗[R] R ≃ₗ[A] M := (lift <| Algebra.lsmul _ _ _ |>.toLinearMap |>.flip) (mk R A M R |>.flip 1) (LinearMap.ext <| one_smul _) - (ext <| fun _ _ => smul_tmul _ _ _ |>.trans <| congr_arg _ <| mul_one _) + (ext fun _ _ => smul_tmul _ _ _ |>.trans <| congr_arg _ <| mul_one _) theorem rid_eq_rid : AlgebraTensorModule.rid R R M = TensorProduct.rid R M := LinearEquiv.toLinearMap_injective <| TensorProduct.ext' fun _ _ => rfl @@ -403,9 +403,9 @@ def rightComm : (M ⊗[A] P) ⊗[R] Q ≃ₗ[A] (M ⊗[R] Q) ⊗[A] P := ∘ₗ (mk R A (M ⊗[A] P) Q).flip) -- explicit `Eq.refl`s here help with performance, but also make it clear that the `ext` are -- letting us prove the result as an equality of pure tensors. - (TensorProduct.ext <| ext <| fun m q => LinearMap.ext <| fun p => Eq.refl <| + (TensorProduct.ext <| ext fun m q => LinearMap.ext fun p => Eq.refl <| (m ⊗ₜ[R] q) ⊗ₜ[A] p) - (curry_injective <| TensorProduct.ext' <| fun m p => LinearMap.ext <| fun q => Eq.refl <| + (curry_injective <| TensorProduct.ext' fun m p => LinearMap.ext fun q => Eq.refl <| (m ⊗ₜ[A] p) ⊗ₜ[R] q) variable {M N P Q} diff --git a/Mathlib/Logic/Function/Basic.lean b/Mathlib/Logic/Function/Basic.lean index 1263c5b165cda..80056acaad0f0 100644 --- a/Mathlib/Logic/Function/Basic.lean +++ b/Mathlib/Logic/Function/Basic.lean @@ -295,7 +295,7 @@ theorem cantor_surjective {α} (f : α → Set α) : ¬Surjective f to `α`. -/ theorem cantor_injective {α : Type*} (f : Set α → α) : ¬Injective f | i => cantor_surjective (fun a ↦ {b | ∀ U, a = f U → U b}) <| - RightInverse.surjective (λ U => Set.ext <| fun _ ↦ ⟨fun h ↦ h U rfl, fun h _ e ↦ i e ▸ h⟩) + RightInverse.surjective (λ U => Set.ext fun _ ↦ ⟨fun h ↦ h U rfl, fun h _ e ↦ i e ▸ h⟩) #align function.cantor_injective Function.cantor_injective /-- There is no surjection from `α : Type u` into `Type (max u v)`. This theorem @@ -781,7 +781,7 @@ theorem extend_injective (hf : Injective f) (e' : β → γ) : Injective fun g lemma FactorsThrough.extend_comp {g : α → γ} (e' : β → γ) (hf : FactorsThrough g f) : extend f g e' ∘ f = g := - funext $ fun a => hf.extend_apply e' a + funext fun a => hf.extend_apply e' a #align function.factors_through.extend_comp Function.FactorsThrough.extend_comp @[simp] diff --git a/Mathlib/Logic/Relator.lean b/Mathlib/Logic/Relator.lean index d1ecfd52ecb8d..1bb3e1be03234 100644 --- a/Mathlib/Logic/Relator.lean +++ b/Mathlib/Logic/Relator.lean @@ -80,7 +80,7 @@ lemma RightTotal.rel_forall (h : RightTotal R) : lemma LeftTotal.rel_exists (h : LeftTotal R) : ((R ⇒ (· → ·)) ⇒ (· → ·)) (fun p => ∃i, p i) (fun q => ∃i, q i) := - fun _ _ Hrel ⟨a, pa⟩ => (h a).imp $ fun _ Rab => Hrel Rab pa + fun _ _ Hrel ⟨a, pa⟩ => (h a).imp fun _ Rab => Hrel Rab pa #align relator.left_total.rel_exists Relator.LeftTotal.rel_exists lemma BiTotal.rel_forall (h : BiTotal R) : @@ -93,8 +93,8 @@ lemma BiTotal.rel_forall (h : BiTotal R) : lemma BiTotal.rel_exists (h : BiTotal R) : ((R ⇒ Iff) ⇒ Iff) (fun p => ∃i, p i) (fun q => ∃i, q i) := fun _ _ Hrel => - ⟨fun ⟨a, pa⟩ => (h.left a).imp $ fun _ Rab => (Hrel Rab).1 pa, - fun ⟨b, qb⟩ => (h.right b).imp $ fun _ Rab => (Hrel Rab).2 qb⟩ + ⟨fun ⟨a, pa⟩ => (h.left a).imp fun _ Rab => (Hrel Rab).1 pa, + fun ⟨b, qb⟩ => (h.right b).imp fun _ Rab => (Hrel Rab).2 qb⟩ #align relator.bi_total.rel_exists Relator.BiTotal.rel_exists lemma left_unique_of_rel_eq {eq' : β → β → Prop} (he : (R ⇒ (R ⇒ Iff)) Eq eq') : LeftUnique R := diff --git a/Mathlib/Mathport/Notation.lean b/Mathlib/Mathport/Notation.lean index 1fd3d0aef797a..9afa98330f8b6 100644 --- a/Mathlib/Mathport/Notation.lean +++ b/Mathlib/Mathport/Notation.lean @@ -316,7 +316,7 @@ partial def matchScoped (lit scopeId : Name) (smatcher : Matcher) : Matcher := g let isDep := (← getExpr).bindingBody!.hasLooseBVar 0 let ppTypes ← getPPOption getPPPiBinderTypes -- the same option controlling ∀ let dom ← withBindingDomain delab - withBindingBodyUnusedName <| fun x => do + withBindingBodyUnusedName fun x => do let x : Ident := ⟨x⟩ let binder ← if prop && !isDep then diff --git a/Mathlib/MeasureTheory/Function/AEEqFun.lean b/Mathlib/MeasureTheory/Function/AEEqFun.lean index 4427b14672a66..400c0d6e60bef 100644 --- a/Mathlib/MeasureTheory/Function/AEEqFun.lean +++ b/Mathlib/MeasureTheory/Function/AEEqFun.lean @@ -220,7 +220,7 @@ open MeasureTheory.Measure (QuasiMeasurePreserving) See also `AEEqFun.compMeasurePreserving`. -/ def compQuasiMeasurePreserving (g : β →ₘ[ν] γ) (f : α → β) (hf : QuasiMeasurePreserving f μ ν) : α →ₘ[μ] γ := - Quotient.liftOn' g (fun g ↦ mk (g ∘ f) <| g.2.comp_quasiMeasurePreserving hf) <| fun _ _ h ↦ + Quotient.liftOn' g (fun g ↦ mk (g ∘ f) <| g.2.comp_quasiMeasurePreserving hf) fun _ _ h ↦ mk_eq_mk.2 <| h.comp_tendsto hf.tendsto_ae @[simp] diff --git a/Mathlib/MeasureTheory/Function/LpSpace.lean b/Mathlib/MeasureTheory/Function/LpSpace.lean index d8872ba41e5e7..420cbb4b0bc1b 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace.lean @@ -897,7 +897,7 @@ theorem Lp.norm_const_le : ‖Lp.const p μ c‖ ≤ ‖c‖ * (μ Set.univ).toR @[simps! apply] protected def Lp.constL (𝕜 : Type*) [NormedField 𝕜] [NormedSpace 𝕜 E] [Fact (1 ≤ p)] : E →L[𝕜] Lp E p μ := - (Lp.constₗ p μ 𝕜).mkContinuous ((μ Set.univ).toReal ^ (1 / p.toReal)) <| fun _ ↦ + (Lp.constₗ p μ 𝕜).mkContinuous ((μ Set.univ).toReal ^ (1 / p.toReal)) fun _ ↦ (Lp.norm_const_le _ _ _).trans_eq (mul_comm _ _) theorem Lp.norm_constL_le (𝕜 : Type*) [NontriviallyNormedField 𝕜] [NormedSpace 𝕜 E] diff --git a/Mathlib/MeasureTheory/Group/Measure.lean b/Mathlib/MeasureTheory/Group/Measure.lean index d12de64415911..7186af3381e1f 100644 --- a/Mathlib/MeasureTheory/Group/Measure.lean +++ b/Mathlib/MeasureTheory/Group/Measure.lean @@ -256,7 +256,7 @@ theorem isMulLeftInvariant_map_smul {α} [SMul α G] [SMulCommClass α G G] [MeasurableSpace α] [MeasurableSMul α G] [IsMulLeftInvariant μ] (a : α) : IsMulLeftInvariant (map (a • · : G → G) μ) := - (forall_measure_preimage_mul_iff _).1 <| fun x _ hs => + (forall_measure_preimage_mul_iff _).1 fun x _ hs => (smulInvariantMeasure_map_smul μ a).measure_preimage_smul x hs /-- The image of a right invariant measure under a left action is right invariant, assuming that @@ -267,7 +267,7 @@ theorem isMulRightInvariant_map_smul {α} [SMul α G] [SMulCommClass α Gᵐᵒᵖ G] [MeasurableSpace α] [MeasurableSMul α G] [IsMulRightInvariant μ] (a : α) : IsMulRightInvariant (map (a • · : G → G) μ) := - (forall_measure_preimage_mul_right_iff _).1 <| fun x _ hs => + (forall_measure_preimage_mul_right_iff _).1 fun x _ hs => (smulInvariantMeasure_map_smul μ a).measure_preimage_smul (MulOpposite.op x) hs /-- The image of a left invariant measure under right multiplication is left invariant. -/ diff --git a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean index 9d483849f878b..e306c3ecb9730 100644 --- a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean +++ b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean @@ -341,7 +341,7 @@ theorem AECover.biUnion_Iic_aecover [Preorder ι] {φ : ι → Set α} (hφ : AE -- porting note: generalized from `[SemilatticeSup ι] [Nonempty ι]` to `[Preorder ι]` theorem AECover.biInter_Ici_aecover [Preorder ι] {φ : ι → Set α} (hφ : AECover μ atTop φ) : AECover μ atTop fun n : ι => ⋂ (k) (_h : k ∈ Ici n), φ k where - ae_eventually_mem := hφ.ae_eventually_mem.mono <| fun x h ↦ by + ae_eventually_mem := hφ.ae_eventually_mem.mono fun x h ↦ by simpa only [mem_iInter, mem_Ici, eventually_forall_ge_atTop] measurableSet i := .biInter (to_countable _) fun n _ => hφ.measurableSet n #align measure_theory.ae_cover.bInter_Ici_ae_cover MeasureTheory.AECover.biInter_Ici_aecover diff --git a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean index ed66ca6f091de..7003c07f5d4a6 100644 --- a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean +++ b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean @@ -239,7 +239,7 @@ theorem lintegral_prod_norm_pow_le {α ι : Type*} [MeasurableSpace α] {μ : Me _ ≤ (∫⁻ a, f i₀ a ∂μ) ^ p i₀ * (∫⁻ a, ∏ i in s, f i a ^ q i ∂μ) ^ (1 - p i₀) := by apply ENNReal.lintegral_mul_norm_pow_le · exact hf i₀ <| mem_insert_self .. - · exact s.aemeasurable_prod <| fun i hi ↦ (hf i <| mem_insert_of_mem hi).pow_const _ + · exact s.aemeasurable_prod fun i hi ↦ (hf i <| mem_insert_of_mem hi).pow_const _ · exact h2p i₀ <| mem_insert_self .. · exact hpi₀ · apply add_sub_cancel'_right diff --git a/Mathlib/NumberTheory/BernoulliPolynomials.lean b/Mathlib/NumberTheory/BernoulliPolynomials.lean index c5ca391aa36a6..c969bccc9290d 100644 --- a/Mathlib/NumberTheory/BernoulliPolynomials.lean +++ b/Mathlib/NumberTheory/BernoulliPolynomials.lean @@ -77,7 +77,7 @@ theorem bernoulli_zero : bernoulli 0 = 1 := by simp [bernoulli] theorem bernoulli_eval_zero (n : ℕ) : (bernoulli n).eval 0 = _root_.bernoulli n := by rw [bernoulli, eval_finset_sum, sum_range_succ] have : (∑ x : ℕ in range n, _root_.bernoulli x * n.choose x * 0 ^ (n - x)) = 0 := by - apply sum_eq_zero <| fun x hx => _ + apply sum_eq_zero fun x hx => _ intros x hx have h : x < n := (mem_range.1 hx) simp [h] diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index 31a85ba3acf4b..ea4fd3e1f0b21 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -652,7 +652,7 @@ noncomputable def orbitRelEquiv [IsGalois k K] : Quotient (MulAction.orbitRel (K ≃ₐ[k] K) (InfinitePlace K)) ≃ InfinitePlace k := by refine Equiv.ofBijective (Quotient.lift (comap · (algebraMap k K)) - <| fun _ _ e ↦ (mem_orbit_iff.mp e).symm) ⟨?_, ?_⟩ + fun _ _ e ↦ (mem_orbit_iff.mp e).symm) ⟨?_, ?_⟩ · rintro ⟨w⟩ ⟨w'⟩ e exact Quotient.sound (mem_orbit_iff.mpr e.symm) · intro w diff --git a/Mathlib/NumberTheory/Padics/PadicNumbers.lean b/Mathlib/NumberTheory/Padics/PadicNumbers.lean index 52e36ef6cfa17..6b46d58b99840 100644 --- a/Mathlib/NumberTheory/Padics/PadicNumbers.lean +++ b/Mathlib/NumberTheory/Padics/PadicNumbers.lean @@ -577,7 +577,7 @@ def padicNormE {p : ℕ} [hp : Fact p.Prime] : AbsoluteValue ℚ_[p] ℚ where toFun := Quotient.lift PadicSeq.norm <| @PadicSeq.norm_equiv _ _ map_mul' q r := Quotient.inductionOn₂ q r <| PadicSeq.norm_mul nonneg' q := Quotient.inductionOn q <| PadicSeq.norm_nonneg - eq_zero' q := Quotient.inductionOn q <| fun r ↦ by + eq_zero' q := Quotient.inductionOn q fun r ↦ by rw [Padic.zero_def, Quotient.eq] exact PadicSeq.norm_zero_iff r add_le' q r := by diff --git a/Mathlib/NumberTheory/SmoothNumbers.lean b/Mathlib/NumberTheory/SmoothNumbers.lean index a99c3f0a8c027..2c75938e14aa0 100644 --- a/Mathlib/NumberTheory/SmoothNumbers.lean +++ b/Mathlib/NumberTheory/SmoothNumbers.lean @@ -174,15 +174,15 @@ def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) : · nth_rw 2 [← prod_factors hm₀] refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_ rw [filter_append, hp.factors_pow, - filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2], - nil_append, filter_eq_self.mpr <| fun q hq ↦ by simp [hm q hq]] + filter_eq_nil.mpr fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2], + nil_append, filter_eq_self.mpr fun q hq ↦ by simp [hm q hq]] right_inv := by rintro ⟨m, hm₀, hm⟩ simp only [Set.coe_setOf, Set.mem_setOf_eq, Subtype.mk.injEq] rw [← factors_count_eq, ← prod_replicate, ← prod_append] nth_rw 3 [← prod_factors hm₀] have : m.factors.filter (· = p) = m.factors.filter (¬ · < p) - · refine (filter_congr' <| fun q hq ↦ ?_).symm + · refine (filter_congr' fun q hq ↦ ?_).symm have H : ¬ p < q := fun hf ↦ Nat.lt_le_asymm hf <| lt_succ_iff.mp (hm q hq) simp only [not_lt, le_iff_eq_or_lt, H, or_false, eq_comm, true_eq_decide_iff] refine prod_eq <| (filter_eq m.factors p).symm ▸ this ▸ perm_append_comm.trans ?_ diff --git a/Mathlib/NumberTheory/SumPrimeReciprocals.lean b/Mathlib/NumberTheory/SumPrimeReciprocals.lean index 5f2005bdbe782..4e2b04d147c96 100644 --- a/Mathlib/NumberTheory/SumPrimeReciprocals.lean +++ b/Mathlib/NumberTheory/SumPrimeReciprocals.lean @@ -65,7 +65,7 @@ theorem not_summable_one_div_on_primes : intro h obtain ⟨k, hk⟩ := h.nat_tsum_vanishing (Iio_mem_nhds one_half_pos : Iio (1 / 2 : ℝ) ∈ nhds 0) specialize hk ({p | Nat.Prime p} ∩ {p | k ≤ p}) <| inter_subset_right .. - rw [tsum_subtype, indicator_indicator, inter_eq_left.mpr <| fun n hn ↦ hn.1, mem_Iio] at hk + rw [tsum_subtype, indicator_indicator, inter_eq_left.mpr fun n hn ↦ hn.1, mem_Iio] at hk have h' : Summable (indicator ({p | Nat.Prime p} ∩ {p | k ≤ p}) fun n ↦ (1 : ℝ) / n) · convert h.indicator {n : ℕ | k ≤ n} using 1 simp only [indicator_indicator, inter_comm] diff --git a/Mathlib/Order/Closure.lean b/Mathlib/Order/Closure.lean index af6f24417d78e..0b4ee02693ff7 100644 --- a/Mathlib/Order/Closure.lean +++ b/Mathlib/Order/Closure.lean @@ -257,7 +257,7 @@ variable [CompleteLattice α] (c : ClosureOperator α) {p : α → Prop} def ofCompletePred (p : α → Prop) (hsinf : ∀ s, (∀ a ∈ s, p a) → p (sInf s)) : ClosureOperator α := ofPred (fun a ↦ ⨅ b : {b // a ≤ b ∧ p b}, b) p (fun a ↦ by simp [forall_swap]) - (fun a ↦ hsinf _ $ forall_range_iff.2 $ fun b ↦ b.2.2) + (fun a ↦ hsinf _ $ forall_range_iff.2 fun b ↦ b.2.2) (fun a b hab hb ↦ iInf_le_of_le ⟨b, hab, hb⟩ le_rfl) @[simp] diff --git a/Mathlib/Order/CompleteLattice.lean b/Mathlib/Order/CompleteLattice.lean index 3296f8d29636c..76dd3366232d2 100644 --- a/Mathlib/Order/CompleteLattice.lean +++ b/Mathlib/Order/CompleteLattice.lean @@ -123,7 +123,7 @@ def iSup_delab : Delab := whenPPOption Lean.getPPNotation do let ppTypes ← getPPOption getPPFunBinderTypes let stx ← SubExpr.withAppArg do let dom ← SubExpr.withBindingDomain delab - withBindingBodyUnusedName $ fun x => do + withBindingBodyUnusedName fun x => do let x : TSyntax `ident := .mk x let body ← delab if prop && !dep then @@ -151,7 +151,7 @@ def iInf_delab : Delab := whenPPOption Lean.getPPNotation do let ppTypes ← getPPOption getPPFunBinderTypes let stx ← SubExpr.withAppArg do let dom ← SubExpr.withBindingDomain delab - withBindingBodyUnusedName $ fun x => do + withBindingBodyUnusedName fun x => do let x : TSyntax `ident := .mk x let body ← delab if prop && !dep then @@ -699,7 +699,7 @@ theorem iSup_congr (h : ∀ i, f i = g i) : ⨆ i, f i = ⨆ i, g i := theorem biSup_congr {p : ι → Prop} (h : ∀ i, p i → f i = g i) : ⨆ (i) (_ : p i), f i = ⨆ (i) (_ : p i), g i := - iSup_congr <| fun i ↦ iSup_congr (h i) + iSup_congr fun i ↦ iSup_congr (h i) theorem Function.Surjective.iSup_comp {f : ι → ι'} (hf : Surjective f) (g : ι' → α) : ⨆ x, g (f x) = ⨆ y, g y := by diff --git a/Mathlib/Order/Filter/Bases.lean b/Mathlib/Order/Filter/Bases.lean index 8f4c2975057fc..1d665eeb3c7d3 100644 --- a/Mathlib/Order/Filter/Bases.lean +++ b/Mathlib/Order/Filter/Bases.lean @@ -165,7 +165,7 @@ namespace FilterBasis /-- The filter associated to a filter basis. -/ protected def filter (B : FilterBasis α) : Filter α where sets := { s | ∃ t ∈ B, t ⊆ s } - univ_sets := B.nonempty.imp <| fun s s_in => ⟨s_in, s.subset_univ⟩ + univ_sets := B.nonempty.imp fun s s_in => ⟨s_in, s.subset_univ⟩ sets_of_superset := fun ⟨s, s_in, h⟩ hxy => ⟨s, s_in, Set.Subset.trans h hxy⟩ inter_sets := fun ⟨_s, s_in, hs⟩ ⟨_t, t_in, ht⟩ => let ⟨u, u_in, u_sub⟩ := B.inter_sets s_in t_in @@ -274,7 +274,7 @@ theorem hasBasis_iff : l.HasBasis p s ↔ ∀ t, t ∈ l ↔ ∃ i, p i ∧ s i #align filter.has_basis_iff Filter.hasBasis_iffₓ theorem HasBasis.ex_mem (h : l.HasBasis p s) : ∃ i, p i := - (h.mem_iff.mp univ_mem).imp <| fun _ => And.left + (h.mem_iff.mp univ_mem).imp fun _ => And.left #align filter.has_basis.ex_mem Filter.HasBasis.ex_mem protected theorem HasBasis.nonempty (h : l.HasBasis p s) : Nonempty ι := @@ -755,7 +755,7 @@ theorem inf_neBot_iff_frequently_right {f g : Filter α} : #align filter.inf_ne_bot_iff_frequently_right Filter.inf_neBot_iff_frequently_right theorem HasBasis.eq_biInf (h : l.HasBasis p s) : l = ⨅ (i) (_ : p i), 𝓟 (s i) := - eq_biInf_of_mem_iff_exists_mem <| fun {_} => by simp only [h.mem_iff, mem_principal, exists_prop] + eq_biInf_of_mem_iff_exists_mem fun {_} => by simp only [h.mem_iff, mem_principal, exists_prop] #align filter.has_basis.eq_binfi Filter.HasBasis.eq_biInf theorem HasBasis.eq_iInf (h : l.HasBasis (fun _ => True) s) : l = ⨅ i, 𝓟 (s i) := by diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index dcd3fe24bb720..b9381a98c8117 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -558,7 +558,7 @@ theorem generate_empty : Filter.generate ∅ = (⊤ : Filter α) := #align filter.generate_empty Filter.generate_empty theorem generate_univ : Filter.generate univ = (⊥ : Filter α) := - bot_unique <| fun _ _ => GenerateSets.basic (mem_univ _) + bot_unique fun _ _ => GenerateSets.basic (mem_univ _) #align filter.generate_univ Filter.generate_univ theorem generate_union {s t : Set (Set α)} : @@ -817,7 +817,7 @@ theorem eq_iInf_of_mem_iff_exists_mem {f : ι → Filter α} {l : Filter α} theorem eq_biInf_of_mem_iff_exists_mem {f : ι → Filter α} {p : ι → Prop} {l : Filter α} (h : ∀ {s}, s ∈ l ↔ ∃ i, p i ∧ s ∈ f i) : l = ⨅ (i) (_ : p i), f i := by rw [iInf_subtype'] - exact eq_iInf_of_mem_iff_exists_mem <| fun {_} => by simp only [Subtype.exists, h, exists_prop] + exact eq_iInf_of_mem_iff_exists_mem fun {_} => by simp only [Subtype.exists, h, exists_prop] #align filter.eq_binfi_of_mem_iff_exists_mem Filter.eq_biInf_of_mem_iff_exists_memₓ theorem iInf_sets_eq {f : ι → Filter α} (h : Directed (· ≥ ·) f) [ne : Nonempty ι] : @@ -1156,7 +1156,7 @@ theorem Eventually.mono {p q : α → Prop} {f : Filter α} (hp : ∀ᶠ x in f, theorem forall_eventually_of_eventually_forall {f : Filter α} {p : α → β → Prop} (h : ∀ᶠ x in f, ∀ y, p x y) : ∀ y, ∀ᶠ x in f, p x y := - fun y => h.mono <| fun _ h => h y + fun y => h.mono fun _ h => h y #align filter.forall_eventually_of_eventually_forall Filter.forall_eventually_of_eventually_forall @[simp] diff --git a/Mathlib/Order/Filter/Germ.lean b/Mathlib/Order/Filter/Germ.lean index e938d86ec275c..4472fa212dc97 100644 --- a/Mathlib/Order/Filter/Germ.lean +++ b/Mathlib/Order/Filter/Germ.lean @@ -532,11 +532,11 @@ instance divInvMonoid [DivInvMonoid G] : DivInvMonoid (Germ l G) := { monoid, inv, div with zpow := fun z f => f ^ z zpow_zero' := Quotient.ind' fun _ => congrArg ofFun <| - funext <| fun _ => DivInvMonoid.zpow_zero' _ + funext fun _ => DivInvMonoid.zpow_zero' _ zpow_succ' := fun _ => Quotient.ind' fun _ => congrArg ofFun <| - funext <| fun _ => DivInvMonoid.zpow_succ' .. + funext fun _ => DivInvMonoid.zpow_succ' .. zpow_neg' := fun _ => Quotient.ind' fun _ => congrArg ofFun <| - funext <| fun _ => DivInvMonoid.zpow_neg' .. + funext fun _ => DivInvMonoid.zpow_neg' .. div_eq_mul_inv := Quotient.ind₂' fun _ _ => congrArg ofFun <| div_eq_mul_inv .. } @@ -855,7 +855,7 @@ instance existsMulOfLE [Mul β] [LE β] [ExistsMulOfLE β] : ExistsMulOfLE (Germ exists_mul_of_le {x y} := inductionOn₂ x y fun f g (h : f ≤ᶠ[l] g) ↦ by classical choose c hc using fun x (hx : f x ≤ g x) ↦ exists_mul_of_le hx - refine ⟨ofFun <| fun x ↦ if hx : f x ≤ g x then c x hx else f x, coe_eq.2 ?_⟩ + refine ⟨ofFun fun x ↦ if hx : f x ≤ g x then c x hx else f x, coe_eq.2 ?_⟩ filter_upwards [h] with x hx rw [dif_pos hx, hc] diff --git a/Mathlib/Order/Iterate.lean b/Mathlib/Order/Iterate.lean index 014a1bdf33d25..3aa4f48939f1f 100644 --- a/Mathlib/Order/Iterate.lean +++ b/Mathlib/Order/Iterate.lean @@ -143,7 +143,7 @@ theorem iterate_le_id_of_le_id (h : f ≤ id) (n : ℕ) : f^[n] ≤ id := #align function.iterate_le_id_of_le_id Function.iterate_le_id_of_le_id theorem monotone_iterate_of_id_le (h : id ≤ f) : Monotone fun m => f^[m] := - monotone_nat_of_le_succ $ fun n x => by + monotone_nat_of_le_succ fun n x => by rw [iterate_succ_apply'] exact h _ #align function.monotone_iterate_of_id_le Function.monotone_iterate_of_id_le @@ -234,7 +234,7 @@ variable [Preorder α] {f : α → α} {x : α} /-- If `f` is a monotone map and `x ≤ f x` at some point `x`, then the iterates `f^[n] x` form a monotone sequence. -/ theorem monotone_iterate_of_le_map (hf : Monotone f) (hx : x ≤ f x) : Monotone fun n => f^[n] x := - monotone_nat_of_le_succ $ fun n => by + monotone_nat_of_le_succ fun n => by rw [iterate_succ_apply] exact hf.iterate n hx #align monotone.monotone_iterate_of_le_map Monotone.monotone_iterate_of_le_map @@ -255,7 +255,7 @@ variable [Preorder α] {f : α → α} {x : α} form a strictly monotone sequence. -/ theorem strictMono_iterate_of_lt_map (hf : StrictMono f) (hx : x < f x) : StrictMono fun n => f^[n] x := - strictMono_nat_of_lt_succ $ fun n => by + strictMono_nat_of_lt_succ fun n => by rw [iterate_succ_apply] exact hf.iterate n hx #align strict_mono.strict_mono_iterate_of_lt_map StrictMono.strictMono_iterate_of_lt_map diff --git a/Mathlib/Order/Lattice.lean b/Mathlib/Order/Lattice.lean index f550108409de8..2445a1d667d50 100644 --- a/Mathlib/Order/Lattice.lean +++ b/Mathlib/Order/Lattice.lean @@ -241,7 +241,7 @@ instance : IsCommutative α (· ⊔ ·) := ⟨@sup_comm _ _⟩ theorem sup_assoc : a ⊔ b ⊔ c = a ⊔ (b ⊔ c) := - eq_of_forall_ge_iff $ fun x => by simp only [sup_le_iff]; rw [and_assoc] + eq_of_forall_ge_iff fun x => by simp only [sup_le_iff]; rw [and_assoc] #align sup_assoc sup_assoc instance : IsAssociative α (· ⊔ ·) := @@ -312,7 +312,7 @@ theorem SemilatticeSup.ext_sup {α} {A B : SemilatticeSup α} (H : ∀ x y : α, (haveI := A; x ≤ y) ↔ x ≤ y) (x y : α) : (haveI := A; x ⊔ y) = x ⊔ y := - eq_of_forall_ge_iff $ fun c => by simp only [sup_le_iff]; rw [← H, @sup_le_iff α A, H, H] + eq_of_forall_ge_iff fun c => by simp only [sup_le_iff]; rw [← H, @sup_le_iff α A, H, H] #align semilattice_sup.ext_sup SemilatticeSup.ext_sup theorem SemilatticeSup.ext {α} {A B : SemilatticeSup α} @@ -364,7 +364,7 @@ instance OrderDual.semilatticeInf (α) [SemilatticeSup α] : SemilatticeInf α theorem SemilatticeSup.dual_dual (α : Type*) [H : SemilatticeSup α] : OrderDual.semilatticeSup αᵒᵈ = H := - SemilatticeSup.ext $ fun _ _ => Iff.rfl + SemilatticeSup.ext fun _ _ => Iff.rfl #align semilattice_sup.dual_dual SemilatticeSup.dual_dual section SemilatticeInf @@ -556,7 +556,7 @@ theorem SemilatticeInf.ext_inf {α} {A B : SemilatticeInf α} (H : ∀ x y : α, (haveI := A; x ≤ y) ↔ x ≤ y) (x y : α) : (haveI := A; x ⊓ y) = x ⊓ y := - eq_of_forall_le_iff $ fun c => by simp only [le_inf_iff]; rw [← H, @le_inf_iff α A, H, H] + eq_of_forall_le_iff fun c => by simp only [le_inf_iff]; rw [← H, @le_inf_iff α A, H, H] #align semilattice_inf.ext_inf SemilatticeInf.ext_inf theorem SemilatticeInf.ext {α} {A B : SemilatticeInf α} @@ -571,7 +571,7 @@ theorem SemilatticeInf.ext {α} {A B : SemilatticeInf α} theorem SemilatticeInf.dual_dual (α : Type*) [H : SemilatticeInf α] : OrderDual.semilatticeInf αᵒᵈ = H := - SemilatticeInf.ext $ fun _ _ => Iff.rfl + SemilatticeInf.ext fun _ _ => Iff.rfl #align semilattice_inf.dual_dual SemilatticeInf.dual_dual theorem inf_le_ite (s s' : α) (P : Prop) [Decidable P] : s ⊓ s' ≤ ite P s s' := @@ -617,7 +617,7 @@ theorem semilatticeSup_mk'_partialOrder_eq_semilatticeInf_mk'_partialOrder (sup_inf_self : ∀ a b : α, a ⊔ a ⊓ b = a) (inf_sup_self : ∀ a b : α, a ⊓ (a ⊔ b) = a) : @SemilatticeSup.toPartialOrder _ (SemilatticeSup.mk' sup_comm sup_assoc sup_idem) = @SemilatticeInf.toPartialOrder _ (SemilatticeInf.mk' inf_comm inf_assoc inf_idem) := - PartialOrder.ext $ fun a b => + PartialOrder.ext fun a b => show a ⊔ b = b ↔ b ⊓ a = a from ⟨fun h => by rw [← h, inf_comm, inf_sup_self], fun h => by rw [← h, sup_comm, sup_inf_self]⟩ #align semilattice_sup_mk'_partial_order_eq_semilattice_inf_mk'_partial_order semilatticeSup_mk'_partialOrder_eq_semilatticeInf_mk'_partialOrder diff --git a/Mathlib/Order/Minimal.lean b/Mathlib/Order/Minimal.lean index c91147d4d5677..0c674004f0591 100644 --- a/Mathlib/Order/Minimal.lean +++ b/Mathlib/Order/Minimal.lean @@ -162,11 +162,11 @@ theorem mem_maximals_iff_forall_lt_not_mem [PartialOrder α] {s : Set α} : -- porting note: new theorem theorem maximals_of_symm [IsSymm α r] : maximals r s = s := - sep_eq_self_iff_mem_true.2 <| fun _ _ _ _ => symm + sep_eq_self_iff_mem_true.2 fun _ _ _ _ => symm -- porting note: new theorem theorem minimals_of_symm [IsSymm α r] : minimals r s = s := - sep_eq_self_iff_mem_true.2 <| fun _ _ _ _ => symm + sep_eq_self_iff_mem_true.2 fun _ _ _ _ => symm theorem maximals_eq_minimals [IsSymm α r] : maximals r s = minimals r s := by rw [minimals_of_symm, maximals_of_symm] diff --git a/Mathlib/Order/OmegaCompletePartialOrder.lean b/Mathlib/Order/OmegaCompletePartialOrder.lean index 7724fb567a46a..bfadb8a4c1e07 100644 --- a/Mathlib/Order/OmegaCompletePartialOrder.lean +++ b/Mathlib/Order/OmegaCompletePartialOrder.lean @@ -822,7 +822,7 @@ theorem forall_forall_merge' (c₀ : Chain (α →𝒄 β)) (c₁ : Chain α) (z of the functions in the `ω`-chain. -/ @[simps!] protected def ωSup (c : Chain (α →𝒄 β)) : α →𝒄 β := - .mk (ωSup <| c.map toMono) <| fun c' ↦ by + .mk (ωSup <| c.map toMono) fun c' ↦ by apply eq_of_forall_ge_iff; intro z simp only [ωSup_le_iff, (c _).continuous, Chain.map_coe, OrderHom.apply_coe, toMono_coe, OrderHom.omegaCompletePartialOrder_ωSup_coe, forall_forall_merge, OrderHomClass.coe_coe, diff --git a/Mathlib/Order/RelSeries.lean b/Mathlib/Order/RelSeries.lean index 2643882f0d9f4..5a404fae3be89 100644 --- a/Mathlib/Order/RelSeries.lean +++ b/Mathlib/Order/RelSeries.lean @@ -110,7 +110,7 @@ protected def Equiv : RelSeries r ≃ {x : List α | x ≠ [] ∧ x.Chain' r} wh invFun x := fromListChain' _ x.2.1 x.2.2 left_inv x := ext (by simp) <| by ext; apply List.get_ofFn right_inv x := by - refine Subtype.ext (List.ext_get ?_ <| fun n hn1 _ => List.get_ofFn _ _) + refine Subtype.ext (List.ext_get ?_ fun n hn1 _ => List.get_ofFn _ _) simp [Nat.succ_pred_eq_of_pos <| List.length_pos.mpr x.2.1] -- TODO : build a similar bijection between `RelSeries α` and `Quiver.Path` diff --git a/Mathlib/Order/Sublattice.lean b/Mathlib/Order/Sublattice.lean index e0b20890d652d..0e7e522889ee5 100644 --- a/Mathlib/Order/Sublattice.lean +++ b/Mathlib/Order/Sublattice.lean @@ -144,9 +144,9 @@ instance instInf : Inf (Sublattice α) where /-- The inf of sublattices is their intersection. -/ instance instInfSet : InfSet (Sublattice α) where sInf S := { carrier := ⨅ L ∈ S, L - supClosed' := supClosed_sInter $ forall_range_iff.2 $ fun L ↦ supClosed_sInter $ + supClosed' := supClosed_sInter $ forall_range_iff.2 fun L ↦ supClosed_sInter $ forall_range_iff.2 fun _ ↦ L.supClosed - infClosed' := infClosed_sInter $ forall_range_iff.2 $ fun L ↦ infClosed_sInter $ + infClosed' := infClosed_sInter $ forall_range_iff.2 fun L ↦ infClosed_sInter $ forall_range_iff.2 fun _ ↦ L.infClosed } instance instInhabited : Inhabited (Sublattice α) := ⟨⊥⟩ diff --git a/Mathlib/Order/SupClosed.lean b/Mathlib/Order/SupClosed.lean index 18169ee234f31..99968407468a6 100644 --- a/Mathlib/Order/SupClosed.lean +++ b/Mathlib/Order/SupClosed.lean @@ -294,7 +294,7 @@ lemma sup_mem_supClosure (ha : a ∈ s) (hb : b ∈ s) : a ⊔ b ∈ supClosure lemma finsetSup'_mem_supClosure {ι : Type*} {t : Finset ι} (ht : t.Nonempty) {f : ι → α} (hf : ∀ i ∈ t, f i ∈ s) : t.sup' ht f ∈ supClosure s := - supClosed_supClosure.finsetSup'_mem _ $ fun _i hi ↦ subset_supClosure $ hf _ hi + supClosed_supClosure.finsetSup'_mem _ fun _i hi ↦ subset_supClosure $ hf _ hi lemma supClosure_min : s ⊆ t → SupClosed t → supClosure s ⊆ t := supClosure.closure_min @@ -358,7 +358,7 @@ lemma inf_mem_infClosure (ha : a ∈ s) (hb : b ∈ s) : a ⊓ b ∈ infClosure lemma finsetInf'_mem_infClosure {ι : Type*} {t : Finset ι} (ht : t.Nonempty) {f : ι → α} (hf : ∀ i ∈ t, f i ∈ s) : t.inf' ht f ∈ infClosure s := - infClosed_infClosure.finsetInf'_mem _ $ fun _i hi ↦ subset_infClosure $ hf _ hi + infClosed_infClosure.finsetInf'_mem _ fun _i hi ↦ subset_infClosure $ hf _ hi lemma infClosure_min : s ⊆ t → InfClosed t → infClosure s ⊆ t := infClosure.closure_min @@ -381,7 +381,7 @@ variable [Lattice α] {s t : Set α} /-- Every set in a join-semilattice generates a set closed under join. -/ @[simps! isClosed] def latticeClosure : ClosureOperator (Set α) := - .ofCompletePred IsSublattice $ fun _ ↦ isSublattice_sInter + .ofCompletePred IsSublattice fun _ ↦ isSublattice_sInter @[simp] lemma subset_latticeClosure : s ⊆ latticeClosure s := latticeClosure.le_closure _ diff --git a/Mathlib/Order/WellFoundedSet.lean b/Mathlib/Order/WellFoundedSet.lean index a9d586c15bee9..f386c03253504 100644 --- a/Mathlib/Order/WellFoundedSet.lean +++ b/Mathlib/Order/WellFoundedSet.lean @@ -793,7 +793,7 @@ theorem partiallyWellOrderedOn_sublistForall₂ (r : α → α → Prop) [IsRefl exact Nat.pred_lt fun con => hnil _ (List.length_eq_zero.1 con) rw [IsBadSeq] at hf' push_neg at hf' - obtain ⟨m, n, mn, hmn⟩ := hf' <| fun n x hx => by + obtain ⟨m, n, mn, hmn⟩ := hf' fun n x hx => by split_ifs at hx with hn exacts [hf1.1 _ _ hx, hf1.1 _ _ (List.tail_subset _ hx)] by_cases hn : n < g 0 diff --git a/Mathlib/Probability/Kernel/Basic.lean b/Mathlib/Probability/Kernel/Basic.lean index 2232030ad593a..b34bba212cc20 100644 --- a/Mathlib/Probability/Kernel/Basic.lean +++ b/Mathlib/Probability/Kernel/Basic.lean @@ -215,7 +215,7 @@ lemma IsFiniteKernel.integrable (μ : Measure α) [IsFiniteMeasure μ] Integrable (fun x => (κ x s).toReal) μ := by refine' Integrable.mono' (integrable_const (IsFiniteKernel.bound κ).toReal) ((kernel.measurable_coe κ hs).ennreal_toReal.aestronglyMeasurable) - (ae_of_all μ <| fun x => _) + (ae_of_all μ fun x => _) rw [Real.norm_eq_abs, abs_of_nonneg ENNReal.toReal_nonneg, ENNReal.toReal_le_toReal (measure_ne_top _ _) (IsFiniteKernel.bound_ne_top _)] exact kernel.measure_le_bound _ _ _ diff --git a/Mathlib/Probability/Kernel/Disintegration.lean b/Mathlib/Probability/Kernel/Disintegration.lean index 58f9609b68d08..a5bd21c7640d4 100644 --- a/Mathlib/Probability/Kernel/Disintegration.lean +++ b/Mathlib/Probability/Kernel/Disintegration.lean @@ -493,7 +493,7 @@ lemma eq_condKernel_of_measure_eq_compProd_real (ρ : Measure (α × ℝ)) [IsFi Real.isPiSystem_Iic_rat · simp only [OuterMeasure.empty', Filter.eventually_true] · simp only [iUnion_singleton_eq_range, mem_range, forall_exists_index, forall_apply_eq_imp_iff] - exact ae_all_iff.2 <| fun q => eq_condKernel_of_measure_eq_compProd' ρ κ hκ measurableSet_Iic + exact ae_all_iff.2 fun q => eq_condKernel_of_measure_eq_compProd' ρ κ hκ measurableSet_Iic · filter_upwards [huniv] with x hxuniv t ht heq rw [measure_compl ht <| measure_ne_top _ _, heq, hxuniv, measure_compl ht <| measure_ne_top _ _] · refine' ae_of_all _ (fun x f hdisj hf heq => _) diff --git a/Mathlib/RepresentationTheory/GroupCohomology/Hilbert90.lean b/Mathlib/RepresentationTheory/GroupCohomology/Hilbert90.lean index 31882fc1b2317..33d5a299aebdb 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Hilbert90.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Hilbert90.lean @@ -76,7 +76,7 @@ theorem hilbert90 (f : (L ≃ₐ[K] L) → Lˣ) ∃ β : Lˣ, ∀ g : (L ≃ₐ[K] L), f g * Units.map g β = β := by /- Let `z : L` be such that `∑ f(h) * h(z) ≠ 0`, for `h ∈ Aut_K(L)` -/ obtain ⟨z, hz⟩ : ∃ z, aux K L f z ≠ 0 := - not_forall.1 (fun H => aux_ne_zero K L f $ funext $ fun x => H x) + not_forall.1 (fun H => aux_ne_zero K L f $ funext fun x => H x) have : aux K L f z = ∑ h, f h * h z := by simp [aux, Finsupp.total, Finsupp.sum_fintype] /- Let `β = ∑ f(h) * h(z).` -/ use Units.mk0 (aux K L f z) hz diff --git a/Mathlib/RingTheory/DedekindDomain/Different.lean b/Mathlib/RingTheory/DedekindDomain/Different.lean index 8f9ceb422b74b..a2dd93cb161f9 100644 --- a/Mathlib/RingTheory/DedekindDomain/Different.lean +++ b/Mathlib/RingTheory/DedekindDomain/Different.lean @@ -175,7 +175,7 @@ lemma map_equiv_traceDual [NoZeroSMulDivisors A B] (I : Submodule B (FractionRin apply (FractionRing.algEquiv B L).forall_congr simp only [restrictScalars_mem, traceForm_apply, AlgEquiv.toEquiv_eq_coe, EquivLike.coe_coe, mem_comap, AlgEquiv.toLinearMap_apply, AlgEquiv.symm_apply_apply] - refine fun {y} ↦ (forall_congr' $ fun hy ↦ ?_) + refine fun {y} ↦ (forall_congr' fun hy ↦ ?_) rw [Algebra.trace_eq_of_equiv_equiv (FractionRing.algEquiv A K).toRingEquiv (FractionRing.algEquiv B L).toRingEquiv] swap diff --git a/Mathlib/RingTheory/TensorProduct.lean b/Mathlib/RingTheory/TensorProduct.lean index fa8df04e49e0c..513bae32c5797 100644 --- a/Mathlib/RingTheory/TensorProduct.lean +++ b/Mathlib/RingTheory/TensorProduct.lean @@ -451,7 +451,7 @@ theorem ext ⦃f g : (A ⊗[R] B) →ₐ[S] C⦄ rwa [← f.map_mul, ← g.map_mul, tmul_mul_tmul, _root_.one_mul, _root_.mul_one] at this theorem ext' {g h : A ⊗[R] B →ₐ[S] C} (H : ∀ a b, g (a ⊗ₜ b) = h (a ⊗ₜ b)) : g = h := - ext (AlgHom.ext <| fun _ => H _ _) (AlgHom.ext <| fun _ => H _ _) + ext (AlgHom.ext fun _ => H _ _) (AlgHom.ext fun _ => H _ _) #align algebra.tensor_product.ext Algebra.TensorProduct.ext end ext diff --git a/Mathlib/SetTheory/Game/PGame.lean b/Mathlib/SetTheory/Game/PGame.lean index 948f843f6261d..3695f3b348232 100644 --- a/Mathlib/SetTheory/Game/PGame.lean +++ b/Mathlib/SetTheory/Game/PGame.lean @@ -218,7 +218,7 @@ Both this and `PGame.recOn` describe Conway induction on games. -/ @[elab_as_elim] def moveRecOn {C : PGame → Sort*} (x : PGame) (IH : ∀ y : PGame, (∀ i, C (y.moveLeft i)) → (∀ j, C (y.moveRight j)) → C y) : C x := - x.recOn <| fun yl yr yL yR => IH (mk yl yr yL yR) + x.recOn fun yl yr yL yR => IH (mk yl yr yL yR) #align pgame.move_rec_on SetTheory.PGame.moveRecOn /-- `IsOption x y` means that `x` is either a left or right option for `y`. -/ diff --git a/Mathlib/Tactic/ApplyCongr.lean b/Mathlib/Tactic/ApplyCongr.lean index 6ff31e0eaa175..7b37c1cbee508 100644 --- a/Mathlib/Tactic/ApplyCongr.lean +++ b/Mathlib/Tactic/ApplyCongr.lean @@ -78,7 +78,7 @@ def Lean.Elab.Tactic.applyCongr (q : Option Expr) : TacticM Unit := do if congrTheoremExprs == [] then throwError "No matching congr lemmas found" -- For every lemma: - liftMetaTactic <| fun mainGoal => congrTheoremExprs.firstM (fun congrTheoremExpr => do + liftMetaTactic fun mainGoal => congrTheoremExprs.firstM (fun congrTheoremExpr => do let newGoals ← mainGoal.apply congrTheoremExpr { newGoals := .nonDependentOnly } newGoals.mapM fun newGoal => Prod.snd <$> newGoal.intros) diff --git a/Mathlib/Tactic/Linarith/Datatypes.lean b/Mathlib/Tactic/Linarith/Datatypes.lean index ef58dd239bd52..9700b7c255bd8 100644 --- a/Mathlib/Tactic/Linarith/Datatypes.lean +++ b/Mathlib/Tactic/Linarith/Datatypes.lean @@ -63,7 +63,7 @@ partial def add : Linexp → Linexp → Linexp def scale (c : Int) (l : Linexp) : Linexp := if c = 0 then [] else if c = 1 then l - else l.map $ fun ⟨n, z⟩ => (n, z*c) + else l.map fun ⟨n, z⟩ => (n, z*c) /-- `l.get n` returns the value in `l` associated with key `n`, if it exists, and `none` otherwise. diff --git a/Mathlib/Tactic/Linarith/Elimination.lean b/Mathlib/Tactic/Linarith/Elimination.lean index 5f0657c04aa44..52b6b1b9a0da6 100644 --- a/Mathlib/Tactic/Linarith/Elimination.lean +++ b/Mathlib/Tactic/Linarith/Elimination.lean @@ -321,7 +321,7 @@ def elimAllVarsM : LinarithM Unit := do those hypotheses. It produces an initial state for the elimination monad. -/ def mkLinarithData (hyps : List Comp) (maxVar : ℕ) : LinarithData := - ⟨maxVar, .ofList (hyps.enum.map $ fun ⟨n, cmp⟩ => PComp.assump cmp n) _⟩ + ⟨maxVar, .ofList (hyps.enum.map fun ⟨n, cmp⟩ => PComp.assump cmp n) _⟩ /-- `produceCertificate hyps vars` tries to derive a contradiction from the comparisons in `hyps` diff --git a/Mathlib/Tactic/Linarith/Parsing.lean b/Mathlib/Tactic/Linarith/Parsing.lean index 52eda5028b5ee..51334e375da7f 100644 --- a/Mathlib/Tactic/Linarith/Parsing.lean +++ b/Mathlib/Tactic/Linarith/Parsing.lean @@ -42,7 +42,7 @@ and returns the value associated with this key if it exists. Otherwise, it fails. -/ def List.findDefeq (red : TransparencyMode) (m : List (Expr × v)) (e : Expr) : MetaM v := do - if let some (_, n) ← m.findM? $ fun ⟨e', _⟩ => withTransparency red (isDefEq e e') then + if let some (_, n) ← m.findM? fun ⟨e', _⟩ => withTransparency red (isDefEq e e') then return n else failure diff --git a/Mathlib/Tactic/Linarith/Preprocessing.lean b/Mathlib/Tactic/Linarith/Preprocessing.lean index 0f1be1888fdad..a4e9dae56b87a 100644 --- a/Mathlib/Tactic/Linarith/Preprocessing.lean +++ b/Mathlib/Tactic/Linarith/Preprocessing.lean @@ -166,7 +166,7 @@ To avoid adding the same nonnegativity facts many times, it is a global preproce def natToInt : GlobalBranchingPreprocessor where name := "move nats to ints" transform g l := do - let l ← l.mapM $ fun h => do + let l ← l.mapM fun h => do let t ← whnfR (← instantiateMVars (← inferType h)) if isNatProp t then let (some (h', t'), _) ← Term.TermElabM.run' (run_for g (zifyProof none h t)) @@ -352,7 +352,7 @@ def nlinarithExtras : GlobalPreprocessor where let ⟨ine, _⟩ ← parseCompAndExpr tp pure (ine, e) catch _ => pure (Ineq.lt, e)) - let products ← with_comps.mapDiagM $ fun (⟨posa, a⟩ : Ineq × Expr) ⟨posb, b⟩ => + let products ← with_comps.mapDiagM fun (⟨posa, a⟩ : Ineq × Expr) ⟨posb, b⟩ => try (some <$> match posa, posb with | Ineq.eq, _ => mkAppM ``zero_mul_eq #[a, b] diff --git a/Mathlib/Tactic/ReduceModChar.lean b/Mathlib/Tactic/ReduceModChar.lean index 1e6953414c3be..dbcd5702272f7 100644 --- a/Mathlib/Tactic/ReduceModChar.lean +++ b/Mathlib/Tactic/ReduceModChar.lean @@ -201,7 +201,7 @@ partial def derive (e : Expr) : MetaM Simp.Result := do let r := {expr := e} let pre e := do - Simp.andThen (← Simp.preDefault e discharge) <| fun e => + Simp.andThen (← Simp.preDefault e discharge) fun e => try return (Simp.Step.done (← matchAndNorm e)) catch _ => pure (Simp.Step.visit {expr := e}) let post e := do diff --git a/Mathlib/Tactic/ToAdditive.lean b/Mathlib/Tactic/ToAdditive.lean index 1e3e07a5bd8e0..6320f881ccf17 100644 --- a/Mathlib/Tactic/ToAdditive.lean +++ b/Mathlib/Tactic/ToAdditive.lean @@ -441,7 +441,7 @@ def etaExpandN (n : Nat) (e : Expr) : MetaM Expr := do def expand (e : Expr) : MetaM Expr := do let env ← getEnv let reorderFn : Name → List (List ℕ) := fun nm ↦ (reorderAttr.find? env nm |>.getD []) - let e₂ ← Lean.Meta.transform (input := e) (post := fun e => return .done e) <| fun e ↦ do + let e₂ ← Lean.Meta.transform (input := e) (post := fun e => return .done e) fun e ↦ do let e0 := e.getAppFn let es := e.getAppArgs let some e0n := e0.constName? | return .continue diff --git a/Mathlib/Tactic/WLOG.lean b/Mathlib/Tactic/WLOG.lean index d2fee8b545204..395b0d729f8ad 100644 --- a/Mathlib/Tactic/WLOG.lean +++ b/Mathlib/Tactic/WLOG.lean @@ -74,7 +74,7 @@ def _root_.Lean.MVarId.wlog (goal : MVarId) (h : Option Name) (P : Expr) let fvars ← getFVarIdsAt goal xs let fvars := fvars.map Expr.fvar let lctx := (← goal.getDecl).lctx - let (revertedFVars, HType) ← liftMkBindingM <| fun ctx => (do + let (revertedFVars, HType) ← liftMkBindingM fun ctx => (do let f ← collectForwardDeps lctx fvars let revertedFVars := filterOutImplementationDetails lctx (f.map Expr.fvarId!) let HType ← withFreshCache do mkAuxMVarType lctx (revertedFVars.map Expr.fvar) .natural HSuffix diff --git a/Mathlib/Testing/SlimCheck/Functions.lean b/Mathlib/Testing/SlimCheck/Functions.lean index 0c7104b1c3bc5..a51f56135c603 100644 --- a/Mathlib/Testing/SlimCheck/Functions.lean +++ b/Mathlib/Testing/SlimCheck/Functions.lean @@ -82,7 +82,7 @@ namespace TotalFunction /-- Compose a total function with a regular function on the left -/ def comp {γ : Type w} (f : β → γ) : TotalFunction α β → TotalFunction α γ | TotalFunction.withDefault m y => TotalFunction.withDefault - (m.map <| Sigma.map id <| fun _ => f) (f y) + (m.map <| Sigma.map id fun _ => f) (f y) /-- Apply a total function to an argument. -/ def apply [DecidableEq α] : TotalFunction α β → α → β diff --git a/Mathlib/Testing/SlimCheck/Testable.lean b/Mathlib/Testing/SlimCheck/Testable.lean index 6741a8c2074b9..a4b45386c1182 100644 --- a/Mathlib/Testing/SlimCheck/Testable.lean +++ b/Mathlib/Testing/SlimCheck/Testable.lean @@ -508,7 +508,7 @@ open Lean /-- Traverse the syntax of a proposition to find universal quantifiers quantifiers and add `NamedBinder` annotations next to them. -/ partial def addDecorations (e : Expr) : MetaM Expr := - Meta.transform e $ fun expr => do + Meta.transform e fun expr => do if not (← Meta.inferType e).isProp then return .continue else if let Expr.forallE name type body data := expr then diff --git a/Mathlib/Topology/AlexandrovDiscrete.lean b/Mathlib/Topology/AlexandrovDiscrete.lean index f708cf210a1c1..ea22c32a414a5 100644 --- a/Mathlib/Topology/AlexandrovDiscrete.lean +++ b/Mathlib/Topology/AlexandrovDiscrete.lean @@ -133,7 +133,7 @@ lemma mem_exterior : a ∈ exterior s ↔ ∀ U, IsOpen U → s ⊆ U → a ∈ lemma subset_exterior_iff : s ⊆ exterior t ↔ ∀ U, IsOpen U → t ⊆ U → s ⊆ U := by simp [exterior_def] -lemma subset_exterior : s ⊆ exterior s := subset_exterior_iff.2 $ fun _ _ ↦ id +lemma subset_exterior : s ⊆ exterior s := subset_exterior_iff.2 fun _ _ ↦ id lemma exterior_minimal (h₁ : s ⊆ t) (h₂ : IsOpen t) : exterior s ⊆ t := by rw [exterior_def]; exact sInter_subset_of_mem ⟨h₂, h₁⟩ @@ -156,7 +156,7 @@ lemma IsOpen.exterior_subset_iff (ht : IsOpen t) : exterior s ⊆ t ↔ s ⊆ t variable [AlexandrovDiscrete α] [AlexandrovDiscrete β] @[simp] lemma isOpen_exterior : IsOpen (exterior s) := by - rw [exterior_def]; exact isOpen_sInter $ fun _ ↦ And.left + rw [exterior_def]; exact isOpen_sInter fun _ ↦ And.left lemma exterior_mem_nhdsSet : exterior s ∈ 𝓝ˢ s := isOpen_exterior.mem_nhdsSet.2 subset_exterior diff --git a/Mathlib/Topology/Algebra/GroupWithZero.lean b/Mathlib/Topology/Algebra/GroupWithZero.lean index 2dbbc9c3a27fb..188e860e87d83 100644 --- a/Mathlib/Topology/Algebra/GroupWithZero.lean +++ b/Mathlib/Topology/Algebra/GroupWithZero.lean @@ -143,7 +143,7 @@ end Inv₀ points. Then the coercion `G₀ˣ → G₀` is a topological embedding. -/ theorem Units.embedding_val₀ [GroupWithZero G₀] [TopologicalSpace G₀] [HasContinuousInv₀ G₀] : Embedding (val : G₀ˣ → G₀) := - embedding_val_mk <| (continuousOn_inv₀ (G₀ := G₀)).mono <| fun _ ↦ IsUnit.ne_zero + embedding_val_mk <| (continuousOn_inv₀ (G₀ := G₀)).mono fun _ ↦ IsUnit.ne_zero #align units.embedding_coe₀ Units.embedding_val₀ section NhdsInv diff --git a/Mathlib/Topology/Algebra/Order/Compact.lean b/Mathlib/Topology/Algebra/Order/Compact.lean index b1f67c71e7223..1eb7f6d3e01e0 100644 --- a/Mathlib/Topology/Algebra/Order/Compact.lean +++ b/Mathlib/Topology/Algebra/Order/Compact.lean @@ -58,7 +58,7 @@ export CompactIccSpace (isCompact_Icc) -- porting note: new lemma; TODO: make it the definition lemma CompactIccSpace.mk' [TopologicalSpace α] [Preorder α] (h : ∀ {a b : α}, a ≤ b → IsCompact (Icc a b)) : CompactIccSpace α where - isCompact_Icc {a b} := by_cases h $ fun hab => by rw [Icc_eq_empty hab]; exact isCompact_empty + isCompact_Icc {a b} := by_cases h fun hab => by rw [Icc_eq_empty hab]; exact isCompact_empty -- porting note: new lemma; TODO: drop one `'` lemma CompactIccSpace.mk'' [TopologicalSpace α] [PartialOrder α] @@ -452,13 +452,13 @@ theorem IsCompact.exists_isMinOn_mem_subset [ClosedIicTopology α] {f : β → {z : β} (ht : IsCompact t) (hf : ContinuousOn f t) (hz : z ∈ t) (hfz : ∀ z' ∈ t \ s, f z < f z') : ∃ x ∈ s, IsMinOn f t x := let ⟨x, hxt, hfx⟩ := ht.exists_isMinOn ⟨z, hz⟩ hf - ⟨x, by_contra <| fun hxs => (hfz x ⟨hxt, hxs⟩).not_le (hfx hz), hfx⟩ + ⟨x, by_contra fun hxs => (hfz x ⟨hxt, hxs⟩).not_le (hfx hz), hfx⟩ theorem IsCompact.exists_isMaxOn_mem_subset [ClosedIciTopology α] {f : β → α} {s t : Set β} {z : β} (ht : IsCompact t) (hf : ContinuousOn f t) (hz : z ∈ t) (hfz : ∀ z' ∈ t \ s, f z' < f z) : ∃ x ∈ s, IsMaxOn f t x := let ⟨x, hxt, hfx⟩ := ht.exists_isMaxOn ⟨z, hz⟩ hf - ⟨x, by_contra <| fun hxs => (hfz x ⟨hxt, hxs⟩).not_le (hfx hz), hfx⟩ + ⟨x, by_contra fun hxs => (hfz x ⟨hxt, hxs⟩).not_le (hfx hz), hfx⟩ @[deprecated IsCompact.exists_isMinOn_mem_subset] theorem IsCompact.exists_isLocalMinOn_mem_subset [ClosedIicTopology α] {f : β → α} {s t : Set β} diff --git a/Mathlib/Topology/Algebra/Order/Floor.lean b/Mathlib/Topology/Algebra/Order/Floor.lean index f860d0fa03c4d..f8ec86ff7190c 100644 --- a/Mathlib/Topology/Algebra/Order/Floor.lean +++ b/Mathlib/Topology/Algebra/Order/Floor.lean @@ -66,7 +66,7 @@ variable [OrderClosedTopology α] -- porting note: new theorem theorem tendsto_floor_right_pure_floor (x : α) : Tendsto (floor : α → ℤ) (𝓝[≥] x) (pure ⌊x⌋) := - tendsto_pure.2 <| mem_of_superset (Ico_mem_nhdsWithin_Ici' <| lt_floor_add_one x) <| fun _y hy => + tendsto_pure.2 <| mem_of_superset (Ico_mem_nhdsWithin_Ici' <| lt_floor_add_one x) fun _y hy => floor_eq_on_Ico _ _ ⟨(floor_le x).trans hy.1, hy.2⟩ -- porting note: new theorem @@ -76,7 +76,7 @@ theorem tendsto_floor_right_pure (n : ℤ) : Tendsto (floor : α → ℤ) (𝓝[ -- porting note: new theorem theorem tendsto_ceil_left_pure_ceil (x : α) : Tendsto (ceil : α → ℤ) (𝓝[≤] x) (pure ⌈x⌉) := tendsto_pure.2 <| mem_of_superset - (Ioc_mem_nhdsWithin_Iic' <| sub_lt_iff_lt_add.2 <| ceil_lt_add_one _) <| fun _y hy => + (Ioc_mem_nhdsWithin_Iic' <| sub_lt_iff_lt_add.2 <| ceil_lt_add_one _) fun _y hy => ceil_eq_on_Ioc _ _ ⟨hy.1, hy.2.trans (le_ceil _)⟩ -- porting note: new theorem @@ -88,7 +88,7 @@ theorem tendsto_floor_left_pure_ceil_sub_one (x : α) : Tendsto (floor : α → ℤ) (𝓝[<] x) (pure (⌈x⌉ - 1)) := have h₁ : ↑(⌈x⌉ - 1) < x := by rw [cast_sub, cast_one, sub_lt_iff_lt_add]; exact ceil_lt_add_one _ have h₂ : x ≤ ↑(⌈x⌉ - 1) + 1 := by rw [cast_sub, cast_one, sub_add_cancel]; exact le_ceil _ - tendsto_pure.2 <| mem_of_superset (Ico_mem_nhdsWithin_Iio' h₁) <| fun _y hy => + tendsto_pure.2 <| mem_of_superset (Ico_mem_nhdsWithin_Iio' h₁) fun _y hy => floor_eq_on_Ico _ _ ⟨hy.1, hy.2.trans_le h₂⟩ -- porting note: new theorem @@ -100,7 +100,7 @@ theorem tendsto_floor_left_pure_sub_one (n : ℤ) : theorem tendsto_ceil_right_pure_floor_add_one (x : α) : Tendsto (ceil : α → ℤ) (𝓝[>] x) (pure (⌊x⌋ + 1)) := have : ↑(⌊x⌋ + 1) - 1 ≤ x := by rw [cast_add, cast_one, add_sub_cancel]; exact floor_le _ - tendsto_pure.2 <| mem_of_superset (Ioc_mem_nhdsWithin_Ioi' <| lt_succ_floor _) <| fun _y hy => + tendsto_pure.2 <| mem_of_superset (Ioc_mem_nhdsWithin_Ioi' <| lt_succ_floor _) fun _y hy => ceil_eq_on_Ioc _ _ ⟨this.trans_lt hy.1, hy.2⟩ -- porting note: new theorem diff --git a/Mathlib/Topology/Algebra/UniformGroup.lean b/Mathlib/Topology/Algebra/UniformGroup.lean index 154cb79396d4e..894aff5665a65 100644 --- a/Mathlib/Topology/Algebra/UniformGroup.lean +++ b/Mathlib/Topology/Algebra/UniformGroup.lean @@ -559,7 +559,7 @@ def TopologicalGroup.toUniformSpace : UniformSpace G where have : Tendsto (fun p : G × G ↦ (p.2 / p.1)⁻¹) (comap (fun p : G × G ↦ p.2 / p.1) (𝓝 1)) (𝓝 1⁻¹) := tendsto_id.inv.comp tendsto_comap by simpa [tendsto_comap_iff] - comp := Tendsto.le_comap <| fun U H ↦ by + comp := Tendsto.le_comap fun U H ↦ by rcases exists_nhds_one_split H with ⟨V, V_nhds, V_mul⟩ refine mem_map.2 (mem_of_superset (mem_lift' <| preimage_mem_comap V_nhds) ?_) rintro ⟨x, y⟩ ⟨z, hz₁, hz₂⟩ diff --git a/Mathlib/Topology/Basic.lean b/Mathlib/Topology/Basic.lean index 71109c438ce32..1fe9cac449c45 100644 --- a/Mathlib/Topology/Basic.lean +++ b/Mathlib/Topology/Basic.lean @@ -901,7 +901,7 @@ theorem nhds_le_of_le {f a} {s : Set α} (h : a ∈ s) (o : IsOpen s) (sf : 𝓟 -- porting note: use `∃ t, t ⊆ s ∧ _` instead of `∃ t ⊆ s, _` theorem mem_nhds_iff {a : α} {s : Set α} : s ∈ 𝓝 a ↔ ∃ t, t ⊆ s ∧ IsOpen t ∧ a ∈ t := - (nhds_basis_opens a).mem_iff.trans <| exists_congr <| fun _ => + (nhds_basis_opens a).mem_iff.trans <| exists_congr fun _ => ⟨fun h => ⟨h.2, h.1.2, h.1.1⟩, fun h => ⟨⟨h.2.2, h.2.1⟩, h.1⟩⟩ #align mem_nhds_iff mem_nhds_iffₓ diff --git a/Mathlib/Topology/Category/TopCat/Limits/Basic.lean b/Mathlib/Topology/Category/TopCat/Limits/Basic.lean index 09ee3962e834c..614c94581ea3d 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Basic.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Basic.lean @@ -91,7 +91,7 @@ def limitConeIsLimit (F : J ⥤ TopCatMax.{v, u}) : IsLimit (limitCone.{v,u} F) erw [← S.w f] rfl⟩ continuous_toFun := - Continuous.subtype_mk (continuous_pi <| fun j => (S.π.app j).2) fun x i j f => by + Continuous.subtype_mk (continuous_pi fun j => (S.π.app j).2) fun x i j f => by dsimp rw [← S.w f] rfl } diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index 26a392c956c3d..e98a426fc3409 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.lean @@ -436,7 +436,7 @@ theorem Set.Subsingleton.isCompact (hs : s.Subsingleton) : IsCompact s := -- porting note: golfed a proof instead of fixing it theorem Set.Finite.isCompact_biUnion {s : Set ι} {f : ι → Set X} (hs : s.Finite) (hf : ∀ i ∈ s, IsCompact (f i)) : IsCompact (⋃ i ∈ s, f i) := - isCompact_iff_ultrafilter_le_nhds'.2 <| fun l hl => by + isCompact_iff_ultrafilter_le_nhds'.2 fun l hl => by rw [Ultrafilter.finite_biUnion_mem_iff hs] at hl rcases hl with ⟨i, his, hi⟩ rcases (hf i his).ultrafilter_le_nhds _ (le_principal_iff.2 hi) with ⟨x, hxi, hlx⟩ diff --git a/Mathlib/Topology/Connected/LocallyConnected.lean b/Mathlib/Topology/Connected/LocallyConnected.lean index 8f7a3fcac7ae8..791840125b93f 100644 --- a/Mathlib/Topology/Connected/LocallyConnected.lean +++ b/Mathlib/Topology/Connected/LocallyConnected.lean @@ -119,7 +119,7 @@ theorem locallyConnectedSpace_iff_connected_basis : LocallyConnectedSpace α ↔ ∀ x, (𝓝 x).HasBasis (fun s : Set α => s ∈ 𝓝 x ∧ IsPreconnected s) id := by rw [locallyConnectedSpace_iff_connected_subsets] - exact forall_congr' <| fun x => Filter.hasBasis_self.symm + exact forall_congr' fun x => Filter.hasBasis_self.symm #align locally_connected_space_iff_connected_basis locallyConnectedSpace_iff_connected_basis theorem locallyConnectedSpace_of_connected_bases {ι : Type*} (b : α → ι → Set α) (p : α → ι → Prop) diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index 45b02b3ea94fa..768baa4b06cfb 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -212,7 +212,7 @@ instance Sum.discreteTopology [TopologicalSpace α] [TopologicalSpace β] [hα : instance Sigma.discreteTopology {β : α → Type v} [∀ a, TopologicalSpace (β a)] [h : ∀ a, DiscreteTopology (β a)] : DiscreteTopology (Sigma β) := - ⟨iSup_eq_bot.2 <| fun _ => by simp only [(h _).eq_bot, coinduced_bot]⟩ + ⟨iSup_eq_bot.2 fun _ => by simp only [(h _).eq_bot, coinduced_bot]⟩ #align sigma.discrete_topology Sigma.discreteTopology section Topα diff --git a/Mathlib/Topology/ContinuousOn.lean b/Mathlib/Topology/ContinuousOn.lean index 72946fc5e3eba..b7b86354d45a4 100644 --- a/Mathlib/Topology/ContinuousOn.lean +++ b/Mathlib/Topology/ContinuousOn.lean @@ -1104,7 +1104,7 @@ theorem continuousOn_of_locally_continuousOn {f : α → β} {s : Set α} -- porting note: new lemma theorem continuousOn_to_generateFrom_iff {s : Set α} {T : Set (Set β)} {f : α → β} : @ContinuousOn α β _ (.generateFrom T) f s ↔ ∀ x ∈ s, ∀ t ∈ T, f x ∈ t → f ⁻¹' t ∈ 𝓝[s] x := - forall₂_congr <| fun x _ => by + forall₂_congr fun x _ => by delta ContinuousWithinAt simp only [TopologicalSpace.nhds_generateFrom, tendsto_iInf, tendsto_principal, mem_setOf_eq, and_imp] diff --git a/Mathlib/Topology/EMetricSpace/Basic.lean b/Mathlib/Topology/EMetricSpace/Basic.lean index fb0f39723ead5..82d2ded130d93 100644 --- a/Mathlib/Topology/EMetricSpace/Basic.lean +++ b/Mathlib/Topology/EMetricSpace/Basic.lean @@ -510,7 +510,7 @@ spaces. -/ instance pseudoEMetricSpacePi [∀ b, PseudoEMetricSpace (π b)] : PseudoEMetricSpace (∀ b, π b) where edist_self f := bot_unique <| Finset.sup_le <| by simp edist_comm f g := by simp [edist_pi_def, edist_comm] - edist_triangle f g h := edist_pi_le_iff.2 <| fun b => le_trans (edist_triangle _ (g b) _) + edist_triangle f g h := edist_pi_le_iff.2 fun b => le_trans (edist_triangle _ (g b) _) (add_le_add (edist_le_pi_edist _ _ _) (edist_le_pi_edist _ _ _)) toUniformSpace := Pi.uniformSpace _ uniformity_edist := by @@ -1180,8 +1180,8 @@ instance [PseudoEMetricSpace X] : EMetricSpace (UniformSpace.SeparationQuotient edist_comm := fun x y => Quotient.inductionOn₂' x y edist_comm, edist_triangle := fun x y z => Quotient.inductionOn₃' x y z edist_triangle, toUniformSpace := inferInstance, - uniformity_edist := (uniformity_basis_edist.map _).eq_biInf.trans $ iInf_congr $ fun ε => - iInf_congr $ fun _ => congr_arg 𝓟 <| by + uniformity_edist := (uniformity_basis_edist.map _).eq_biInf.trans $ iInf_congr fun ε => + iInf_congr fun _ => congr_arg 𝓟 <| by ext ⟨⟨x⟩, ⟨y⟩⟩ refine ⟨?_, fun h => ⟨(x, y), h, rfl⟩⟩ rintro ⟨⟨x', y'⟩, h', h⟩ diff --git a/Mathlib/Topology/Homeomorph.lean b/Mathlib/Topology/Homeomorph.lean index 7d7c46b4aa2ef..eab27e4b2cba2 100644 --- a/Mathlib/Topology/Homeomorph.lean +++ b/Mathlib/Topology/Homeomorph.lean @@ -598,7 +598,7 @@ end @[simps! apply toEquiv] def piCongrLeft {ι ι' : Type*} {Y : ι' → Type*} [∀ j, TopologicalSpace (Y j)] (e : ι ≃ ι') : (∀ i, Y (e i)) ≃ₜ ∀ j, Y j where - continuous_toFun := continuous_pi <| e.forall_congr_left.mp <| fun i ↦ by + continuous_toFun := continuous_pi <| e.forall_congr_left.mp fun i ↦ by simpa only [Equiv.toFun_as_coe, Equiv.piCongrLeft_apply_apply] using continuous_apply i continuous_invFun := Pi.continuous_precomp' e toEquiv := Equiv.piCongrLeft _ e diff --git a/Mathlib/Topology/LocallyConstant/Basic.lean b/Mathlib/Topology/LocallyConstant/Basic.lean index 830a05bb51e67..3f4a1a5e8c4f0 100644 --- a/Mathlib/Topology/LocallyConstant/Basic.lean +++ b/Mathlib/Topology/LocallyConstant/Basic.lean @@ -430,7 +430,7 @@ family of locally constant functions with values in β indexed by α. -/ def unflip {X α β : Type*} [Finite α] [TopologicalSpace X] (f : α → LocallyConstant X β) : LocallyConstant X (α → β) where toFun x a := f a x - isLocallyConstant := IsLocallyConstant.iff_isOpen_fiber.2 <| fun g => by + isLocallyConstant := IsLocallyConstant.iff_isOpen_fiber.2 fun g => by have : (fun (x : X) (a : α) => f a x) ⁻¹' {g} = ⋂ a : α, f a ⁻¹' {g a} := by ext; simp [Function.funext_iff] rw [this] diff --git a/Mathlib/Topology/MetricSpace/Algebra.lean b/Mathlib/Topology/MetricSpace/Algebra.lean index e0ffe2c54b98d..dbe9a95b83f98 100644 --- a/Mathlib/Topology/MetricSpace/Algebra.lean +++ b/Mathlib/Topology/MetricSpace/Algebra.lean @@ -105,7 +105,7 @@ instance MulOpposite.lipschitzMul : LipschitzMul βᵐᵒᵖ where -- this instance could be deduced from `NormedAddCommGroup.lipschitzAdd`, but we prove it -- separately here so that it is available earlier in the hierarchy instance Real.hasLipschitzAdd : LipschitzAdd ℝ where - lipschitz_add := ⟨2, LipschitzWith.of_dist_le_mul <| fun p q => by + lipschitz_add := ⟨2, LipschitzWith.of_dist_le_mul fun p q => by simp only [Real.dist_eq, Prod.dist_eq, Prod.fst_sub, Prod.snd_sub, NNReal.coe_ofNat, add_sub_add_comm, two_mul] refine le_trans (abs_add (p.1 - q.1) (p.2 - q.2)) ?_ diff --git a/Mathlib/Topology/MetricSpace/Basic.lean b/Mathlib/Topology/MetricSpace/Basic.lean index 3a24401906077..91f5349d05d4f 100644 --- a/Mathlib/Topology/MetricSpace/Basic.lean +++ b/Mathlib/Topology/MetricSpace/Basic.lean @@ -371,7 +371,7 @@ end Metric section EqRel instance {α : Type u} [PseudoMetricSpace α] : Dist (UniformSpace.SeparationQuotient α) where - dist p q := Quotient.liftOn₂' p q dist <| fun x y x' y' hx hy => by + dist p q := Quotient.liftOn₂' p q dist fun x y x' y' hx hy => by rw [dist_edist, dist_edist, ← UniformSpace.SeparationQuotient.edist_mk x, ← UniformSpace.SeparationQuotient.edist_mk x', Quot.sound hx, Quot.sound hy] diff --git a/Mathlib/Topology/MetricSpace/Dilation.lean b/Mathlib/Topology/MetricSpace/Dilation.lean index 03f7c7d596992..c6efdd98a0c7f 100644 --- a/Mathlib/Topology/MetricSpace/Dilation.lean +++ b/Mathlib/Topology/MetricSpace/Dilation.lean @@ -150,7 +150,7 @@ theorem ratio_of_trivial [DilationClass F α β] (f : F) @[nontriviality] theorem ratio_of_subsingleton [Subsingleton α] [DilationClass F α β] (f : F) : ratio f = 1 := - if_pos <| fun x y ↦ by simp [Subsingleton.elim x y] + if_pos fun x y ↦ by simp [Subsingleton.elim x y] theorem ratio_ne_zero [DilationClass F α β] (f : F) : ratio f ≠ 0 := by rw [ratio]; split_ifs diff --git a/Mathlib/Topology/NoetherianSpace.lean b/Mathlib/Topology/NoetherianSpace.lean index 276d36fbc66d3..b2af7c38c7dc0 100644 --- a/Mathlib/Topology/NoetherianSpace.lean +++ b/Mathlib/Topology/NoetherianSpace.lean @@ -121,7 +121,7 @@ instance {α} : NoetherianSpace (CofiniteTopology α) := by theorem noetherianSpace_of_surjective [NoetherianSpace α] (f : α → β) (hf : Continuous f) (hf' : Function.Surjective f) : NoetherianSpace β := - noetherianSpace_iff_isCompact.2 $ (Set.image_surjective.mpr hf').forall.2 $ fun s => + noetherianSpace_iff_isCompact.2 $ (Set.image_surjective.mpr hf').forall.2 fun s => (NoetherianSpace.isCompact s).image hf #align topological_space.noetherian_space_of_surjective TopologicalSpace.noetherianSpace_of_surjective diff --git a/Mathlib/Topology/Order/ScottTopology.lean b/Mathlib/Topology/Order/ScottTopology.lean index ba02d7907029e..46c6b4df47967 100644 --- a/Mathlib/Topology/Order/ScottTopology.lean +++ b/Mathlib/Topology/Order/ScottTopology.lean @@ -285,7 +285,7 @@ The Scott topology on a partial order is T₀. -/ -- see Note [lower instance priority] instance (priority := 90) : T0Space α := - (t0Space_iff_inseparable α).2 $ fun x y h ↦ Iic_injective $ + (t0Space_iff_inseparable α).2 fun x y h ↦ Iic_injective $ by simpa only [inseparable_iff_closure_eq, IsScott.closure_singleton] using h end PartialOrder diff --git a/Mathlib/Topology/PartialHomeomorph.lean b/Mathlib/Topology/PartialHomeomorph.lean index 8e77cd79d5d68..d0c6a7b94550f 100644 --- a/Mathlib/Topology/PartialHomeomorph.lean +++ b/Mathlib/Topology/PartialHomeomorph.lean @@ -1244,7 +1244,7 @@ def homeomorphOfImageSubsetSource {s : Set α} {t : Set β} (hs : s ⊆ e.source s ≃ₜ t := have h₁ : MapsTo e s t := mapsTo'.2 ht.subset have h₂ : t ⊆ e.target := ht ▸ e.image_source_eq_target ▸ image_subset e hs - have h₃ : MapsTo e.symm t s := ht ▸ ball_image_iff.2 <| fun _x hx => + have h₃ : MapsTo e.symm t s := ht ▸ ball_image_iff.2 fun _x hx => (e.left_inv (hs hx)).symm ▸ hx { toFun := MapsTo.restrict e s t h₁ invFun := MapsTo.restrict e.symm t s h₃ diff --git a/Mathlib/Topology/UniformSpace/Basic.lean b/Mathlib/Topology/UniformSpace/Basic.lean index 42333bb75d707..72761866eec8c 100644 --- a/Mathlib/Topology/UniformSpace/Basic.lean +++ b/Mathlib/Topology/UniformSpace/Basic.lean @@ -1215,7 +1215,7 @@ instance : Inf (UniformSpace α) := refl := le_inf u₁.refl u₂.refl symm := u₁.symm.inf u₂.symm comp := (lift'_inf_le _ _ _).trans <| inf_le_inf u₁.comp u₂.comp } - (u₁.toTopologicalSpace ⊓ u₂.toTopologicalSpace) <| fun _ => by + (u₁.toTopologicalSpace ⊓ u₂.toTopologicalSpace) fun _ => by rw [@nhds_inf _ u₁.toTopologicalSpace u₂.toTopologicalSpace, @nhds_eq_comap_uniformity _ u₁, @nhds_eq_comap_uniformity _ u₂, comap_inf]; rfl⟩ diff --git a/Mathlib/Topology/UniformSpace/Equiv.lean b/Mathlib/Topology/UniformSpace/Equiv.lean index 1cf3b17c265bd..b4a2710337e48 100644 --- a/Mathlib/Topology/UniformSpace/Equiv.lean +++ b/Mathlib/Topology/UniformSpace/Equiv.lean @@ -348,7 +348,7 @@ theorem coe_punitProd : ⇑(punitProd α) = Prod.snd := @[simps! apply toEquiv] def piCongrLeft {ι ι' : Type*} {β : ι' → Type*} [∀ j, UniformSpace (β j)] (e : ι ≃ ι') : (∀ i, β (e i)) ≃ᵤ ∀ j, β j where - uniformContinuous_toFun := uniformContinuous_pi.mpr <| e.forall_congr_left.mp <| fun i ↦ by + uniformContinuous_toFun := uniformContinuous_pi.mpr <| e.forall_congr_left.mp fun i ↦ by simpa only [Equiv.toFun_as_coe, Equiv.piCongrLeft_apply_apply] using Pi.uniformContinuous_proj _ i uniformContinuous_invFun := Pi.uniformContinuous_precomp' _ e diff --git a/Mathlib/Topology/UniformSpace/UniformConvergence.lean b/Mathlib/Topology/UniformSpace/UniformConvergence.lean index 4a20e72d8904f..3a149e02f75fe 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergence.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergence.lean @@ -150,7 +150,7 @@ theorem TendstoUniformly.tendstoUniformlyOnFilter (h : TendstoUniformly F f p) : theorem tendstoUniformlyOn_iff_tendstoUniformly_comp_coe : TendstoUniformlyOn F f p s ↔ TendstoUniformly (fun i (x : s) => F i x) (f ∘ (↑)) p := - forall₂_congr <| fun u _ => by simp + forall₂_congr fun u _ => by simp #align tendsto_uniformly_on_iff_tendsto_uniformly_comp_coe tendstoUniformlyOn_iff_tendstoUniformly_comp_coe /-- A sequence of functions `Fₙ` converges uniformly to a limiting function `f` w.r.t. @@ -376,7 +376,7 @@ theorem UniformContinuousOn.tendstoUniformlyOn [UniformSpace α] [UniformSpace change Tendsto (Prod.map (↿F) ↿F ∘ φ) (𝓝[U] x ×ˢ 𝓟 V) (𝓤 γ) simp only [nhdsWithin, SProd.sprod, Filter.prod, comap_inf, inf_assoc, comap_principal, inf_principal] - refine hF.comp (Tendsto.inf ?_ <| tendsto_principal_principal.2 <| fun x hx => ⟨⟨hU, hx.2⟩, hx⟩) + refine hF.comp (Tendsto.inf ?_ <| tendsto_principal_principal.2 fun x hx => ⟨⟨hU, hx.2⟩, hx⟩) simp only [uniformity_prod_eq_comap_prod, tendsto_comap_iff, (· ∘ ·), nhds_eq_comap_uniformity, comap_comap] exact tendsto_comap.prod_mk (tendsto_diag_uniformity _ _) @@ -652,7 +652,7 @@ theorem TendstoLocallyUniformlyOn.mono (h : TendstoLocallyUniformlyOn F f p s) ( theorem tendstoLocallyUniformlyOn_iUnion {ι' : Sort*} {S : ι' → Set α} (hS : ∀ i, IsOpen (S i)) (h : ∀ i, TendstoLocallyUniformlyOn F f p (S i)) : TendstoLocallyUniformlyOn F f p (⋃ i, S i) := - (isOpen_iUnion hS).tendstoLocallyUniformlyOn_iff_forall_tendsto.2 $ fun _x hx => + (isOpen_iUnion hS).tendstoLocallyUniformlyOn_iff_forall_tendsto.2 fun _x hx => let ⟨i, hi⟩ := mem_iUnion.1 hx (hS i).tendstoLocallyUniformlyOn_iff_forall_tendsto.1 (h i) _ hi #align tendsto_locally_uniformly_on_Union tendstoLocallyUniformlyOn_iUnion diff --git a/Mathlib/Util/Delaborators.lean b/Mathlib/Util/Delaborators.lean index e14d724484811..c872f89c38945 100644 --- a/Mathlib/Util/Delaborators.lean +++ b/Mathlib/Util/Delaborators.lean @@ -105,7 +105,7 @@ def exists_delab : Delab := whenPPOption Lean.getPPNotation do let ppTypes ← getPPOption getPPFunBinderTypes let stx ← SubExpr.withAppArg do let dom ← SubExpr.withBindingDomain delab - withBindingBodyUnusedName $ fun x => do + withBindingBodyUnusedName fun x => do let x : TSyntax `ident := .mk x let body ← delab if prop && !dep then diff --git a/test/Traversable.lean b/test/Traversable.lean index 1b72fc56c031d..7c6f72b976138 100644 --- a/test/Traversable.lean +++ b/test/Traversable.lean @@ -74,7 +74,7 @@ def x : MyTree (List Nat) := in each node, traverses each list. For each `ℕ` visited, apply an action `ℕ → StateM (List ℕ) Unit` which adds its argument to the state. -/ def ex : StateM (List ℕ) (MyTree <| List Unit) := do - let xs ← traverse (traverse <| fun a => modify $ List.cons a) x + let xs ← traverse (traverse fun a => modify $ List.cons a) x return xs example : (ex.run []).1 = node leaf (node (node leaf leaf [(), (), ()]) leaf [(), ()]) [()] := rfl From b9715de9281350268a9022378fb824857865c6db Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Sun, 31 Dec 2023 10:00:31 +0000 Subject: [PATCH 286/353] chore: remove duplicate prodPrimeFactors_apply_of_ne_zero (#9366) --- Mathlib/NumberTheory/ArithmeticFunction.lean | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Mathlib/NumberTheory/ArithmeticFunction.lean b/Mathlib/NumberTheory/ArithmeticFunction.lean index d8403b476668f..8bbcf8a4cc114 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction.lean @@ -586,10 +586,6 @@ theorem prodPrimeFactors_apply [CommMonoidWithZero R] {f: ℕ → R} {n : ℕ} ( ∏ᵖ p ∣ n, f p = ∏ p in n.primeFactors, f p := if_neg hn -theorem prodPrimeFactors_apply_of_ne_zero [CommMonoidWithZero R] {f : ℕ → R} {n : ℕ} - (hn : n ≠ 0) : ∏ᵖ p ∣ n, f p = ∏ p in n.primeFactors, f p := - prodPrimeFactors_apply hn - end ProdPrimeFactors /-- Multiplicative functions -/ @@ -775,7 +771,7 @@ theorem prodPrimeFactors [CommMonoidWithZero R] (f : ℕ → R) : theorem prodPrimeFactors_add_of_squarefree [CommSemiring R] {f g : ArithmeticFunction R} (hf : IsMultiplicative f) (hg : IsMultiplicative g) {n : ℕ} (hn : Squarefree n) : ∏ᵖ p ∣ n, (f + g) p = (f * g) n := by - rw [prodPrimeFactors_apply_of_ne_zero hn.ne_zero] + rw [prodPrimeFactors_apply hn.ne_zero] simp_rw [add_apply (f:=f) (g:=g)] rw [Finset.prod_add, mul_apply, sum_divisorsAntidiagonal (f · * g ·), ← divisors_filter_squarefree_of_squarefree hn, sum_divisors_filter_squarefree hn.ne_zero, From 425bee91c73d1ae2e4257ff18def580a91767196 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Sun, 31 Dec 2023 10:02:41 +0000 Subject: [PATCH 287/353] chore: bump to nightly-2023-12-31 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 040f43d41bbbd..df380ce57054d 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-29 +leanprover/lean4:nightly-2023-12-31 From aa6b836dfece145e2b3bf7b26928915208b8579a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Degenne?= Date: Sun, 31 Dec 2023 11:54:35 +0000 Subject: [PATCH 288/353] feat(MeasureTheory): log-likelihood ratio of two measures (#9355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define the log-likelihood ratio between measures `μ` and `ν`: this is the function `x ↦ log (μ.rnDeriv ν x).toReal`. Co-authored-by: Rémy Degenne --- Mathlib.lean | 1 + .../Measure/LogLikelihoodRatio.lean | 200 ++++++++++++++++++ 2 files changed, 201 insertions(+) create mode 100644 Mathlib/MeasureTheory/Measure/LogLikelihoodRatio.lean diff --git a/Mathlib.lean b/Mathlib.lean index 7e17918a42c8d..ba5eda1fb5d28 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2679,6 +2679,7 @@ import Mathlib.MeasureTheory.Measure.Lebesgue.Complex import Mathlib.MeasureTheory.Measure.Lebesgue.EqHaar import Mathlib.MeasureTheory.Measure.Lebesgue.Integral import Mathlib.MeasureTheory.Measure.Lebesgue.VolumeOfBalls +import Mathlib.MeasureTheory.Measure.LogLikelihoodRatio import Mathlib.MeasureTheory.Measure.MeasureSpace import Mathlib.MeasureTheory.Measure.MeasureSpaceDef import Mathlib.MeasureTheory.Measure.MutuallySingular diff --git a/Mathlib/MeasureTheory/Measure/LogLikelihoodRatio.lean b/Mathlib/MeasureTheory/Measure/LogLikelihoodRatio.lean new file mode 100644 index 0000000000000..e8766a5134b56 --- /dev/null +++ b/Mathlib/MeasureTheory/Measure/LogLikelihoodRatio.lean @@ -0,0 +1,200 @@ +/- +Copyright (c) 2023 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +import Mathlib.MeasureTheory.Measure.Tilted + +/-! +# Log-likelihood Ratio + +The likelihood ratio between two measures `μ` and `ν` is their Radon-Nikodym derivative +`μ.rnDeriv ν`. The logarithm of that function is often used instead: this is the log-likelihood +ratio. + +This file contains a definition of the log-likelihood ratio (llr) and its properties. + +## Main definitions + +* `llr μ ν`: Log-Likelihood Ratio between `μ` and `ν`, defined as the function + `x ↦ log (μ.rnDeriv ν x).toReal`. + +-/ + +open Real + +open scoped ENNReal NNReal Topology + +namespace MeasureTheory + +variable {α : Type*} {mα : MeasurableSpace α} {μ ν : Measure α} {f : α → ℝ} + +/-- Log-Likelihood Ratio between two measures. -/ +noncomputable def llr (μ ν : Measure α) (x : α) : ℝ := log (μ.rnDeriv ν x).toReal + +lemma llr_def (μ ν : Measure α) : llr μ ν = fun x ↦ log (μ.rnDeriv ν x).toReal := rfl + +lemma exp_llr (μ ν : Measure α) [SigmaFinite μ] : + (fun x ↦ exp (llr μ ν x)) + =ᵐ[ν] fun x ↦ if μ.rnDeriv ν x = 0 then 1 else (μ.rnDeriv ν x).toReal := by + filter_upwards [Measure.rnDeriv_lt_top μ ν] with x hx + by_cases h_zero : μ.rnDeriv ν x = 0 + · simp only [llr, h_zero, ENNReal.zero_toReal, log_zero, exp_zero, ite_true] + · rw [llr, exp_log, if_neg h_zero] + exact ENNReal.toReal_pos h_zero hx.ne + +lemma exp_llr_of_ac (μ ν : Measure α) [SigmaFinite μ] [Measure.HaveLebesgueDecomposition μ ν] + (hμν : μ ≪ ν) : + (fun x ↦ exp (llr μ ν x)) =ᵐ[μ] fun x ↦ (μ.rnDeriv ν x).toReal := by + filter_upwards [hμν.ae_le (exp_llr μ ν), Measure.rnDeriv_pos hμν] with x hx_eq hx_pos + rw [hx_eq, if_neg hx_pos.ne'] + +lemma exp_llr_of_ac' (μ ν : Measure α) [SigmaFinite μ] [SigmaFinite ν] (hμν : ν ≪ μ) : + (fun x ↦ exp (llr μ ν x)) =ᵐ[ν] fun x ↦ (μ.rnDeriv ν x).toReal := by + filter_upwards [exp_llr μ ν, Measure.rnDeriv_pos' hμν] with x hx hx_pos + rwa [if_neg hx_pos.ne'] at hx + +lemma neg_llr [SigmaFinite μ] [SigmaFinite ν] (hμν : μ ≪ ν) : + - llr μ ν =ᵐ[μ] llr ν μ := by + filter_upwards [Measure.inv_rnDeriv hμν] with x hx + rw [Pi.neg_apply, llr, llr, ← log_inv, ← ENNReal.toReal_inv] + congr + +lemma exp_neg_llr [SigmaFinite μ] [SigmaFinite ν] (hμν : μ ≪ ν) : + (fun x ↦ exp (- llr μ ν x)) =ᵐ[μ] fun x ↦ (ν.rnDeriv μ x).toReal := by + filter_upwards [neg_llr hμν, exp_llr_of_ac' ν μ hμν] with x hx hx_exp_log + rw [Pi.neg_apply] at hx + rw [hx, hx_exp_log] + +lemma exp_neg_llr' [SigmaFinite μ] [SigmaFinite ν] (hμν : ν ≪ μ) : + (fun x ↦ exp (- llr μ ν x)) =ᵐ[ν] fun x ↦ (ν.rnDeriv μ x).toReal := by + filter_upwards [neg_llr hμν, exp_llr_of_ac ν μ hμν] with x hx hx_exp_log + rw [Pi.neg_apply, neg_eq_iff_eq_neg] at hx + rw [← hx, hx_exp_log] + +@[measurability] +lemma measurable_llr (μ ν : Measure α) : Measurable (llr μ ν) := + (Measure.measurable_rnDeriv μ ν).ennreal_toReal.log + +@[measurability] +lemma stronglyMeasurable_llr (μ ν : Measure α) : StronglyMeasurable (llr μ ν) := + (measurable_llr μ ν).stronglyMeasurable + +lemma llr_smul_left [IsFiniteMeasure μ] [Measure.HaveLebesgueDecomposition μ ν] + (hμν : μ ≪ ν) (c : ℝ≥0∞) (hc : c ≠ 0) (hc_ne_top : c ≠ ∞) : + llr (c • μ) ν =ᵐ[μ] fun x ↦ llr μ ν x + log c.toReal := by + simp only [llr, llr_def] + have h := Measure.rnDeriv_smul_left_of_ne_top μ ν hc_ne_top + filter_upwards [hμν.ae_le h, Measure.rnDeriv_pos hμν, hμν.ae_le (Measure.rnDeriv_lt_top μ ν)] + with x hx_eq hx_pos hx_ne_top + rw [hx_eq] + simp only [Pi.smul_apply, smul_eq_mul, ENNReal.toReal_mul] + rw [log_mul] + rotate_left + · rw [ENNReal.toReal_ne_zero] + simp [hc, hc_ne_top] + · rw [ENNReal.toReal_ne_zero] + simp [hx_pos.ne', hx_ne_top.ne] + ring + +lemma llr_smul_right [IsFiniteMeasure μ] [Measure.HaveLebesgueDecomposition μ ν] + (hμν : μ ≪ ν) (c : ℝ≥0∞) (hc : c ≠ 0) (hc_ne_top : c ≠ ∞) : + llr μ (c • ν) =ᵐ[μ] fun x ↦ llr μ ν x - log c.toReal := by + simp only [llr, llr_def] + have h := Measure.rnDeriv_smul_right_of_ne_top μ ν hc hc_ne_top + filter_upwards [hμν.ae_le h, Measure.rnDeriv_pos hμν, hμν.ae_le (Measure.rnDeriv_lt_top μ ν)] + with x hx_eq hx_pos hx_ne_top + rw [hx_eq] + simp only [Pi.smul_apply, smul_eq_mul, ENNReal.toReal_mul] + rw [log_mul] + rotate_left + · rw [ENNReal.toReal_ne_zero] + simp [hc, hc_ne_top] + · rw [ENNReal.toReal_ne_zero] + simp [hx_pos.ne', hx_ne_top.ne] + rw [ENNReal.toReal_inv, log_inv] + ring + +section llr_tilted + +lemma llr_tilted_left [SigmaFinite μ] [SigmaFinite ν] (hμν : μ ≪ ν) + (hf : Integrable (fun x ↦ exp (f x)) μ) (hfν : AEMeasurable f ν) : + (llr (μ.tilted f) ν) =ᵐ[μ] fun x ↦ f x - log (∫ z, exp (f z) ∂μ) + llr μ ν x := by + have hfμ : AEMeasurable f μ := + aemeasurable_of_aemeasurable_exp (AEStronglyMeasurable.aemeasurable hf.1) + cases eq_zero_or_neZero μ with + | inl hμ => + simp only [hμ, ae_zero, Filter.EventuallyEq]; exact Filter.eventually_bot + | inr h0 => + filter_upwards [hμν.ae_le (toReal_rnDeriv_tilted_left hfμ hfν), Measure.rnDeriv_pos hμν, + hμν.ae_le (Measure.rnDeriv_lt_top μ ν)] with x hx hx_pos hx_lt_top + rw [llr, hx, log_mul, div_eq_mul_inv, log_mul (exp_pos _).ne', log_exp, log_inv, llr, + ← sub_eq_add_neg] + · simp only [ne_eq, inv_eq_zero] + exact (integral_exp_pos hf).ne' + · simp only [ne_eq, div_eq_zero_iff] + push_neg + exact ⟨(exp_pos _).ne', (integral_exp_pos hf).ne'⟩ + · simp [ENNReal.toReal_eq_zero_iff, hx_lt_top.ne, hx_pos.ne'] + +lemma integrable_llr_tilted_left [IsFiniteMeasure μ] [SigmaFinite ν] + (hμν : μ ≪ ν) (hf : Integrable f μ) (h_int : Integrable (llr μ ν) μ) + (hfμ : Integrable (fun x ↦ exp (f x)) μ) (hfν : AEMeasurable f ν) : + Integrable (llr (μ.tilted f) ν) μ := by + rw [integrable_congr (llr_tilted_left hμν hfμ hfν)] + exact Integrable.add (hf.sub (integrable_const _)) h_int + +lemma integral_llr_tilted_left [IsProbabilityMeasure μ] [SigmaFinite ν] + (hμν : μ ≪ ν) (hf : Integrable f μ) (h_int : Integrable (llr μ ν) μ) + (hfμ : Integrable (fun x ↦ exp (f x)) μ) (hfν : AEMeasurable f ν) : + ∫ x, llr (μ.tilted f) ν x ∂μ = ∫ x, llr μ ν x ∂μ + ∫ x, f x ∂μ - log (∫ x, exp (f x) ∂μ) := by + calc ∫ x, llr (μ.tilted f) ν x ∂μ + = ∫ x, f x - log (∫ x, exp (f x) ∂μ) + llr μ ν x ∂μ := + integral_congr_ae (llr_tilted_left hμν hfμ hfν) + _ = ∫ x, f x ∂μ - log (∫ x, exp (f x) ∂μ) + ∫ x, llr μ ν x ∂μ := by + rw [integral_add ?_ h_int] + swap; · exact hf.sub (integrable_const _) + rw [integral_sub hf (integrable_const _)] + simp only [integral_const, measure_univ, ENNReal.one_toReal, smul_eq_mul, one_mul] + _ = ∫ x, llr μ ν x ∂μ + ∫ x, f x ∂μ - log (∫ x, exp (f x) ∂μ) := by abel + +lemma llr_tilted_right [SigmaFinite μ] [SigmaFinite ν] + (hμν : μ ≪ ν) (hf : Integrable (fun x ↦ exp (f x)) ν) : + (llr μ (ν.tilted f)) =ᵐ[μ] fun x ↦ - f x + log (∫ z, exp (f z) ∂ν) + llr μ ν x := by + cases eq_zero_or_neZero ν with + | inl h => + have hμ : μ = 0 := by ext s _; exact hμν (by simp [h]) + simp only [hμ, ae_zero, Filter.EventuallyEq]; exact Filter.eventually_bot + | inr h0 => + filter_upwards [hμν.ae_le (toReal_rnDeriv_tilted_right μ ν hf), Measure.rnDeriv_pos hμν, + hμν.ae_le (Measure.rnDeriv_lt_top μ ν)] with x hx hx_pos hx_lt_top + rw [llr, hx, log_mul, log_mul (exp_pos _).ne', log_exp, llr] + · exact (integral_exp_pos hf).ne' + · refine (mul_pos (exp_pos _) (integral_exp_pos hf)).ne' + · simp [ENNReal.toReal_eq_zero_iff, hx_lt_top.ne, hx_pos.ne'] + +lemma integrable_llr_tilted_right [IsFiniteMeasure μ] [SigmaFinite ν] + (hμν : μ ≪ ν) (hfμ : Integrable f μ) + (h_int : Integrable (llr μ ν) μ) (hfν : Integrable (fun x ↦ exp (f x)) ν) : + Integrable (llr μ (ν.tilted f)) μ := by + rw [integrable_congr (llr_tilted_right hμν hfν)] + exact Integrable.add (hfμ.neg.add (integrable_const _)) h_int + +lemma integral_llr_tilted_right [IsProbabilityMeasure μ] [SigmaFinite ν] + (hμν : μ ≪ ν) (hfμ : Integrable f μ) (hfν : Integrable (fun x ↦ exp (f x)) ν) + (h_int : Integrable (llr μ ν) μ) : + ∫ x, llr μ (ν.tilted f) x ∂μ = ∫ x, llr μ ν x ∂μ - ∫ x, f x ∂μ + log (∫ x, exp (f x) ∂ν) := by + calc ∫ x, llr μ (ν.tilted f) x ∂μ + = ∫ x, - f x + log (∫ x, exp (f x) ∂ν) + llr μ ν x ∂μ := + integral_congr_ae (llr_tilted_right hμν hfν) + _ = - ∫ x, f x ∂μ + log (∫ x, exp (f x) ∂ν) + ∫ x, llr μ ν x ∂μ := by + rw [← integral_neg, integral_add ?_ h_int] + swap; · exact hfμ.neg.add (integrable_const _) + rw [integral_add ?_ (integrable_const _)] + swap; · exact hfμ.neg + simp only [integral_const, measure_univ, ENNReal.one_toReal, smul_eq_mul, one_mul] + _ = ∫ x, llr μ ν x ∂μ - ∫ x, f x ∂μ + log (∫ x, exp (f x) ∂ν) := by abel + +end llr_tilted + +end MeasureTheory From a59d0136f417dcbf1d9fceaa2d42ed87d592a164 Mon Sep 17 00:00:00 2001 From: Xavier Roblot <46200072+xroblot@users.noreply.github.com> Date: Sun, 31 Dec 2023 14:56:38 +0000 Subject: [PATCH 289/353] chore(Algebra.Module.LocalizedModule): use `IsLocalization` instead of `Localization` (#9167) The construction of `LocalizedModule` is done using `IsLocalization` rather than `Localization`. The corresponding instances for `Localization` are deduced automatically by Lean. One drawback is that many instances are now marked `noncomputable`. --- Mathlib/Algebra/Module/LocalizedModule.lean | 263 ++++++++++---------- Mathlib/GroupTheory/MonoidLocalization.lean | 5 + Mathlib/RingTheory/Localization/Basic.lean | 3 + 3 files changed, 140 insertions(+), 131 deletions(-) diff --git a/Mathlib/Algebra/Module/LocalizedModule.lean b/Mathlib/Algebra/Module/LocalizedModule.lean index 4ab2e590e5ba5..1f0c6c62a8573 100644 --- a/Mathlib/Algebra/Module/LocalizedModule.lean +++ b/Mathlib/Algebra/Module/LocalizedModule.lean @@ -3,11 +3,8 @@ Copyright (c) 2022 Jujian Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang, Jujian Zhang -/ -import Mathlib.GroupTheory.MonoidLocalization -import Mathlib.RingTheory.Localization.Basic -import Mathlib.RingTheory.Localization.Module -import Mathlib.Algebra.Algebra.RestrictScalars import Mathlib.RingTheory.IsTensorProduct +import Mathlib.RingTheory.Localization.Module #align_import algebra.module.localized_module from "leanprover-community/mathlib"@"831c494092374cfe9f50591ed0ac81a25efc5b86" @@ -49,6 +46,8 @@ variable {R : Type u} [CommSemiring R] (S : Submonoid R) variable (M : Type v) [AddCommMonoid M] [Module R M] +variable (T : Type*) [CommSemiring T] [Algebra R T] [IsLocalization S T] + /-- The equivalence relation on `M × S` where `(m1, s1) ≈ (m2, s2)` if and only if for some (u : S), u * (s2 • m1 - s1 • m2) = 0-/ /- Porting note: We use small letter `r` since `R` is used for a ring. -/ @@ -318,90 +317,88 @@ theorem mk_mul_mk {A : Type*} [Semiring A] [Algebra R A] {a₁ a₂ : A} {s₁ s rfl #align localized_module.mk_mul_mk LocalizedModule.mk_mul_mk -instance : SMul (Localization S) (LocalizedModule S M) where - smul f x := - (Localization.liftOn f - (fun r s => - (liftOn x (fun p => (mk (r • p.1) (s * p.2))) - (by - rintro ⟨m1, t1⟩ ⟨m2, t2⟩ ⟨u, h⟩ - refine' mk_eq.mpr ⟨u, _⟩ - have h' := congr_arg ((s • r) • ·) h - simp only [← mul_smul, smul_eq_mul, mul_comm, mul_left_comm, Submonoid.smul_def, - Submonoid.coe_mul] at h' ⊢ - rw [h']))) +noncomputable instance : SMul T (LocalizedModule S M) where + smul x p := + let a := IsLocalization.sec S x + liftOn p (fun p ↦ mk (a.1 • p.1) (a.2 * p.2)) (by - induction' x using LocalizedModule.induction_on with m t - rintro r r' s s' h - simp only [liftOn_mk, liftOn_mk, mk_eq] - obtain ⟨u, eq1⟩ := Localization.r_iff_exists.mp h - use u - have eq1' := congr_arg (· • t • m) eq1 - simp only [← mul_smul, smul_assoc, Submonoid.smul_def, Submonoid.coe_mul] at eq1' ⊢ - ring_nf at eq1' ⊢ - rw [eq1'])) + rintro p p' ⟨s, h⟩ + refine mk_eq.mpr ⟨s, ?_⟩ + calc + _ = a.2 • a.1 • s • p'.2 • p.1 := by + simp_rw [Submonoid.smul_def, Submonoid.coe_mul, ← mul_smul]; ring_nf + _ = a.2 • a.1 • s • p.2 • p'.1 := by rw [h] + _ = s • (a.2 * p.2) • a.1 • p'.1 := by + simp_rw [Submonoid.smul_def, ← mul_smul, Submonoid.coe_mul]; ring_nf ) + +theorem smul_def (x : T) (m : M) (s : S) : + x • mk m s = mk ((IsLocalization.sec S x).1 • m) ((IsLocalization.sec S x).2 * s) := rfl + +theorem mk'_smul_mk (r : R) (m : M) (s s' : S) : + IsLocalization.mk' T r s • mk m s' = mk (r • m) (s * s') := by + rw [smul_def, mk_eq] + obtain ⟨c, hc⟩ := IsLocalization.eq.mp <| IsLocalization.mk'_sec T (IsLocalization.mk' T r s) + use c + simp_rw [← mul_smul, Submonoid.smul_def, Submonoid.coe_mul, ← mul_smul, ← mul_assoc, + mul_comm _ (s':R), mul_assoc, hc] theorem mk_smul_mk (r : R) (m : M) (s t : S) : Localization.mk r s • mk m t = mk (r • m) (s * t) := by - dsimp only [HSMul.hSMul, SMul.smul] - rw [Localization.liftOn_mk, liftOn_mk] + rw [Localization.mk_eq_mk'] + exact mk'_smul_mk .. #align localized_module.mk_smul_mk LocalizedModule.mk_smul_mk -private theorem one_smul' (m : LocalizedModule S M) : (1 : Localization S) • m = m := by - induction' m using LocalizedModule.induction_on with m s - rw [← Localization.mk_one, mk_smul_mk, one_smul, one_mul] - -private theorem mul_smul' (x y : Localization S) (m : LocalizedModule S M) : - (x * y) • m = x • y • m := by - induction' x using Localization.induction_on with data - induction' y using Localization.induction_on with data' - rcases data, data' with ⟨⟨r, s⟩, ⟨r', s'⟩⟩ - induction' m using LocalizedModule.induction_on with m t - rw [Localization.mk_mul, mk_smul_mk, mk_smul_mk, mk_smul_mk, mul_smul, mul_assoc] - -private theorem smul_add' (x : Localization S) (y z : LocalizedModule S M) : - x • (y + z) = x • y + x • z := by - induction' x using Localization.induction_on with data - rcases data with ⟨r, u⟩ - induction' y using LocalizedModule.induction_on with m s - induction' z using LocalizedModule.induction_on with n t - rw [mk_smul_mk, mk_smul_mk, mk_add_mk, mk_smul_mk, mk_add_mk, mk_eq] - use 1 - simp only [one_smul, smul_add, ← mul_smul, Submonoid.smul_def, Submonoid.coe_mul] - ring_nf - -private theorem smul_zero' (x : Localization S) : x • (0 : LocalizedModule S M) = 0 := by - induction' x using Localization.induction_on with data - rcases data with ⟨r, s⟩ - rw [← zero_mk s, mk_smul_mk, smul_zero, zero_mk, zero_mk] - -private theorem add_smul' (x y : Localization S) (z : LocalizedModule S M) : - (x + y) • z = x • z + y • z := by - induction' x using Localization.induction_on with datax - induction' y using Localization.induction_on with datay - induction' z using LocalizedModule.induction_on with m t - rcases datax, datay with ⟨⟨r, s⟩, ⟨r', s'⟩⟩ - rw [Localization.add_mk, mk_smul_mk, mk_smul_mk, mk_smul_mk, mk_add_mk, mk_eq] - use 1 - simp only [one_smul, add_smul, smul_add, ← mul_smul, Submonoid.smul_def, Submonoid.coe_mul, - Submonoid.coe_one] - rw [add_comm] - -- Commutativity of addition in the module is not applied by `Ring`. - ring_nf - -private theorem zero_smul' (x : LocalizedModule S M) : (0 : Localization S) • x = 0 := by - induction' x using LocalizedModule.induction_on with m s - rw [← Localization.mk_zero s, mk_smul_mk, zero_smul, zero_mk] - -instance isModule : Module (Localization S) (LocalizedModule S M) where +variable {T} + +private theorem one_smul_aux (p : LocalizedModule S M) : (1 : T) • p = p := by + induction' p using LocalizedModule.induction_on with m s + rw [show (1:T) = IsLocalization.mk' T (1:R) (1:S) by rw [IsLocalization.mk'_one, map_one]] + rw [mk'_smul_mk, one_smul, one_mul] + +private theorem mul_smul_aux (x y : T) (p : LocalizedModule S M) : + (x * y) • p = x • y • p := by + induction' p using LocalizedModule.induction_on with m s + rw [← IsLocalization.mk'_sec (M := S) T x, ← IsLocalization.mk'_sec (M := S) T y] + simp_rw [← IsLocalization.mk'_mul, mk'_smul_mk, ← mul_smul, mul_assoc] + +private theorem smul_add_aux (x : T) (p q : LocalizedModule S M) : + x • (p + q) = x • p + x • q := by + induction' p using LocalizedModule.induction_on with m s + induction' q using LocalizedModule.induction_on with n t + rw [smul_def, smul_def, mk_add_mk, mk_add_mk] + rw [show x • _ = IsLocalization.mk' T _ _ • _ by rw [IsLocalization.mk'_sec (M := S) T]] + rw [← IsLocalization.mk'_cancel _ _ (IsLocalization.sec S x).2, mk'_smul_mk] + congr 1 + · simp only [Submonoid.smul_def, smul_add, ← mul_smul, Submonoid.coe_mul]; ring_nf + · rw [mul_mul_mul_comm] -- ring does not work here + +private theorem smul_zero_aux (x : T) : x • (0 : LocalizedModule S M) = 0 := by + erw [smul_def, smul_zero, zero_mk] + +private theorem add_smul_aux (x y : T) (p : LocalizedModule S M) : + (x + y) • p = x • p + y • p := by + induction' p using LocalizedModule.induction_on with m s + rw [smul_def T x, smul_def T y, mk_add_mk, show (x + y) • _ = IsLocalization.mk' T _ _ • _ by + rw [← IsLocalization.mk'_sec (M := S) T x, ← IsLocalization.mk'_sec (M := S) T y, + ← IsLocalization.mk'_add, IsLocalization.mk'_cancel _ _ s], mk'_smul_mk, ← smul_assoc, + ← smul_assoc, ← add_smul] + congr 1 + · simp only [Submonoid.smul_def, Submonoid.coe_mul, smul_eq_mul]; ring_nf + · rw [mul_mul_mul_comm, mul_assoc] -- ring does not work here + +private theorem zero_smul_aux (p : LocalizedModule S M) : (0 : T) • p = 0 := by + induction' p using LocalizedModule.induction_on with m s + rw [show (0:T) = IsLocalization.mk' T (0:R) (1:S) by rw [IsLocalization.mk'_zero], mk'_smul_mk, + zero_smul, zero_mk] + +noncomputable instance isModule : Module T (LocalizedModule S M) where smul := (· • ·) - one_smul := one_smul' - mul_smul := mul_smul' - smul_add := smul_add' - smul_zero := smul_zero' - add_smul := add_smul' - zero_smul := zero_smul' -#align localized_module.is_module LocalizedModule.isModule + one_smul := one_smul_aux + mul_smul := mul_smul_aux + smul_add := smul_add_aux + smul_zero := smul_zero_aux + add_smul := add_smul_aux + zero_smul := zero_smul_aux @[simp] theorem mk_cancel_common_left (s' s : S) (m : M) : mk (s' • m) (s' * s) = mk m s := @@ -421,7 +418,7 @@ theorem mk_cancel_common_right (s s' : S) (m : M) : mk (s' • m) (s * s') = mk mk_eq.mpr ⟨1, by simp [mul_smul]⟩ #align localized_module.mk_cancel_common_right LocalizedModule.mk_cancel_common_right -instance isModule' : Module R (LocalizedModule S M) := +noncomputable instance isModule' : Module R (LocalizedModule S M) := { Module.compHom (LocalizedModule S M) <| algebraMap R (Localization S) with } #align localized_module.is_module' LocalizedModule.isModule' @@ -429,35 +426,43 @@ theorem smul'_mk (r : R) (s : S) (m : M) : r • mk m s = mk (r • m) s := by erw [mk_smul_mk r m 1 s, one_mul] #align localized_module.smul'_mk LocalizedModule.smul'_mk -instance {A : Type*} [Semiring A] [Algebra R A] : - Algebra (Localization S) (LocalizedModule S A) := - Algebra.ofModule - (by - intro r x₁ x₂ - obtain ⟨y, s, rfl : IsLocalization.mk' _ y s = r⟩ := IsLocalization.mk'_surjective S r - obtain ⟨⟨a₁, s₁⟩, rfl : mk a₁ s₁ = x₁⟩ := Quotient.exists_rep x₁ - obtain ⟨⟨a₂, s₂⟩, rfl : mk a₂ s₂ = x₂⟩ := Quotient.exists_rep x₂ - rw [mk_mul_mk, ← Localization.mk_eq_mk', mk_smul_mk, mk_smul_mk, mk_mul_mk, mul_assoc, - smul_mul_assoc]) - (by - intro r x₁ x₂ - obtain ⟨y, s, rfl : IsLocalization.mk' _ y s = r⟩ := IsLocalization.mk'_surjective S r - obtain ⟨⟨a₁, s₁⟩, rfl : mk a₁ s₁ = x₁⟩ := Quotient.exists_rep x₁ - obtain ⟨⟨a₂, s₂⟩, rfl : mk a₂ s₂ = x₂⟩ := Quotient.exists_rep x₂ - rw [mk_mul_mk, ← Localization.mk_eq_mk', mk_smul_mk, mk_smul_mk, mk_mul_mk, mul_left_comm, - mul_smul_comm]) +theorem smul'_mul {A : Type*} [Semiring A] [Algebra R A] (x : T) (p₁ p₂ : LocalizedModule S A) : + x • p₁ * p₂ = x • (p₁ * p₂) := by + obtain ⟨⟨a₁, s₁⟩, rfl : mk a₁ s₁ = p₁⟩ := Quotient.exists_rep p₁ + obtain ⟨⟨a₂, s₂⟩, rfl : mk a₂ s₂ = p₂⟩ := Quotient.exists_rep p₂ + rw [mk_mul_mk, smul_def, smul_def, mk_mul_mk, mul_assoc, smul_mul_assoc] -theorem algebraMap_mk {A : Type*} [Semiring A] [Algebra R A] (a : R) (s : S) : - algebraMap _ _ (Localization.mk a s) = mk (algebraMap R A a) s := by +theorem mul_smul' {A : Type*} [Semiring A] [Algebra R A] (x : T) (p₁ p₂ : LocalizedModule S A) : + p₁ * x • p₂ = x • (p₁ * p₂) := by + obtain ⟨⟨a₁, s₁⟩, rfl : mk a₁ s₁ = p₁⟩ := Quotient.exists_rep p₁ + obtain ⟨⟨a₂, s₂⟩, rfl : mk a₂ s₂ = p₂⟩ := Quotient.exists_rep p₂ + rw [smul_def, mk_mul_mk, mk_mul_mk, smul_def, mul_left_comm, mul_smul_comm] + +variable (T) + +noncomputable instance {A : Type*} [Semiring A] [Algebra R A] : Algebra T (LocalizedModule S A) := + Algebra.ofModule smul'_mul mul_smul' + +theorem algebraMap_mk' {A : Type*} [Semiring A] [Algebra R A] (a : R) (s : S) : + algebraMap _ _ (IsLocalization.mk' T a s) = mk (algebraMap R A a) s := by rw [Algebra.algebraMap_eq_smul_one] change _ • mk _ _ = _ - rw [mk_smul_mk, Algebra.algebraMap_eq_smul_one, mul_one] + rw [mk'_smul_mk, Algebra.algebraMap_eq_smul_one, mul_one] + +theorem algebraMap_mk {A : Type*} [Semiring A] [Algebra R A] (a : R) (s : S) : + algebraMap _ _ (Localization.mk a s) = mk (algebraMap R A a) s := by + rw [Localization.mk_eq_mk'] + exact algebraMap_mk' .. #align localized_module.algebra_map_mk LocalizedModule.algebraMap_mk -instance : IsScalarTower R (Localization S) (LocalizedModule S M) := - RestrictScalars.isScalarTower R (Localization S) (LocalizedModule S M) +instance : IsScalarTower R T (LocalizedModule S M) where + smul_assoc r x p := by + induction' p using LocalizedModule.induction_on with m s + rw [← IsLocalization.mk'_sec (M := S) T x, IsLocalization.smul_mk', mk'_smul_mk, mk'_smul_mk, + smul'_mk, mul_smul] -instance algebra' {A : Type*} [Semiring A] [Algebra R A] : Algebra R (LocalizedModule S A) := +noncomputable instance algebra' {A : Type*} [Semiring A] [Algebra R A] : + Algebra R (LocalizedModule S A) := { (algebraMap (Localization S) (LocalizedModule S A)).comp (algebraMap R <| Localization S), show Module R (LocalizedModule S A) by infer_instance with commutes' := by @@ -494,25 +499,21 @@ end @[simps] def divBy (s : S) : LocalizedModule S M →ₗ[R] LocalizedModule S M where toFun p := - p.liftOn (fun p => mk p.1 (s * p.2)) fun ⟨a, b⟩ ⟨a', b'⟩ ⟨c, eq1⟩ => - mk_eq.mpr ⟨c, by rw [mul_smul, mul_smul, smul_comm c, eq1, smul_comm s]⟩ - map_add' x y := - x.induction_on₂ - (by - intro m₁ m₂ t₁ t₂ - simp only [mk_add_mk, LocalizedModule.liftOn_mk, mul_smul, ← smul_add, mul_assoc, - mk_cancel_common_left s] - rw [show s * (t₁ * t₂) = t₁ * (s * t₂) by - ext - simp only [Submonoid.coe_mul] - ring]) - y - map_smul' r x := - x.inductionOn <| by - intro - dsimp only - change liftOn (mk _ _) _ _ = r • (liftOn (mk _ _) _ _) - simp [LocalizedModule.liftOn_mk, smul'_mk] + p.liftOn (fun p => mk p.1 (p.2 * s)) fun ⟨a, b⟩ ⟨a', b'⟩ ⟨c, eq1⟩ => + mk_eq.mpr ⟨c, by rw [mul_smul, mul_smul, smul_comm _ s, smul_comm _ s, eq1, smul_comm _ s, + smul_comm _ s]⟩ + map_add' x y := by + refine x.induction_on₂ ?_ y + intro m₁ m₂ t₁ t₂ + simp_rw [mk_add_mk, LocalizedModule.liftOn_mk, mk_add_mk, mul_smul, mul_comm _ s, mul_assoc, + smul_comm _ s, ← smul_add, mul_left_comm s t₁ t₂, mk_cancel_common_left s] + map_smul' r x := by + refine x.inductionOn (fun _ ↦ ?_) + dsimp only + change liftOn (mk _ _) _ _ = r • (liftOn (mk _ _) _ _) + simp_rw [RingHom.toMonoidHom_eq_coe, OneHom.toFun_eq_coe, MonoidHom.toOneHom_coe, + MonoidHom.coe_coe, ZeroHom.coe_mk, liftOn_mk, mul_assoc, ← smul_def] + rfl #align localized_module.div_by LocalizedModule.divBy theorem divBy_mul_by (s : S) (p : LocalizedModule S M) : @@ -520,11 +521,11 @@ theorem divBy_mul_by (s : S) (p : LocalizedModule S M) : p.inductionOn (by intro ⟨m, t⟩ - simp only [Module.algebraMap_end_apply, smul'_mk, divBy_apply] + rw [Module.algebraMap_end_apply, divBy_apply] erw [LocalizedModule.liftOn_mk] - simp only [one_mul] - change mk (s • m) (s * t) = mk m t - rw [mk_cancel_common_left s t]) + rw [mul_assoc, ← smul_def, ZeroHom.coe_mk, RingHom.toFun_eq_coe, algebraMap_smul, smul'_mk, + ← Submonoid.smul_def, mk_cancel_common_right _ s] + rfl) #align localized_module.div_by_mul_by LocalizedModule.divBy_mul_by theorem mul_by_divBy (s : S) (p : LocalizedModule S M) : @@ -532,10 +533,10 @@ theorem mul_by_divBy (s : S) (p : LocalizedModule S M) : p.inductionOn (by intro ⟨m, t⟩ - simp only [LocalizedModule.liftOn_mk, divBy_apply, Module.algebraMap_end_apply, smul'_mk] + rw [divBy_apply, Module.algebraMap_end_apply] erw [LocalizedModule.liftOn_mk, smul'_mk] - change mk (s • m) (s * t) = mk m t - rw [mk_cancel_common_left s t]) + rw [← Submonoid.smul_def, mk_cancel_common_right _ s] + rfl) #align localized_module.mul_by_div_by LocalizedModule.mul_by_divBy end diff --git a/Mathlib/GroupTheory/MonoidLocalization.lean b/Mathlib/GroupTheory/MonoidLocalization.lean index b6a8a69d017ab..62af25259b56c 100644 --- a/Mathlib/GroupTheory/MonoidLocalization.lean +++ b/Mathlib/GroupTheory/MonoidLocalization.lean @@ -839,6 +839,11 @@ theorem mk'_eq_of_eq' {a₁ b₁ : M} {a₂ b₂ : S} (H : b₁ * ↑a₂ = a₁ #align submonoid.localization_map.mk'_eq_of_eq' Submonoid.LocalizationMap.mk'_eq_of_eq' #align add_submonoid.localization_map.mk'_eq_of_eq' AddSubmonoid.LocalizationMap.mk'_eq_of_eq' +@[to_additive] +theorem mk'_cancel (a : M) (b c : S) : + f.mk' (a * c) (b * c) = f.mk' a b := + mk'_eq_of_eq' f (by rw [Submonoid.coe_mul, mul_comm (b:M), mul_assoc]) + @[to_additive (attr := simp)] theorem mk'_self' (y : S) : f.mk' (y : M) y = 1 := show _ * _ = _ by rw [mul_inv_left, mul_one] diff --git a/Mathlib/RingTheory/Localization/Basic.lean b/Mathlib/RingTheory/Localization/Basic.lean index e8165150d19db..8cab829ba29a5 100644 --- a/Mathlib/RingTheory/Localization/Basic.lean +++ b/Mathlib/RingTheory/Localization/Basic.lean @@ -383,6 +383,9 @@ theorem mk'_eq_of_eq' {a₁ b₁ : R} {a₂ b₂ : M} (H : b₁ * ↑a₂ = a₁ (toLocalizationMap M S).mk'_eq_of_eq' H #align is_localization.mk'_eq_of_eq' IsLocalization.mk'_eq_of_eq' +theorem mk'_cancel (a : R) (b c : M) : + mk' S (a * c) (b * c) = mk' S a b := (toLocalizationMap M S).mk'_cancel _ _ _ + variable (S) @[simp] From 7d31d03376f02197961d8bd00d110d74b59a1d07 Mon Sep 17 00:00:00 2001 From: Yakov Pechersky Date: Sun, 31 Dec 2023 21:44:50 +0000 Subject: [PATCH 290/353] feat: Fin CharP and lemmas for Fin rollover (#9033) Co-authored-by: Yakov Pechersky Co-authored-by: Junyan Xu --- Mathlib/Algebra/CharP/Basic.lean | 8 ++++++ Mathlib/Data/Fin/Basic.lean | 43 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/Mathlib/Algebra/CharP/Basic.lean b/Mathlib/Algebra/CharP/Basic.lean index 5df7a76e492ee..e312db33bddfc 100644 --- a/Mathlib/Algebra/CharP/Basic.lean +++ b/Mathlib/Algebra/CharP/Basic.lean @@ -739,3 +739,11 @@ theorem charZero_iff_forall_prime_ne_zero exact CharP.charP_to_charZero R end CharZero + +namespace Fin + +instance charP (n : ℕ) : CharP (Fin (n + 1)) (n + 1) where + cast_eq_zero_iff' := by + simp [Fin.eq_iff_veq, Nat.dvd_iff_mod_eq_zero] + +end Fin diff --git a/Mathlib/Data/Fin/Basic.lean b/Mathlib/Data/Fin/Basic.lean index c7f05f6268a35..f69eb91d41f8c 100644 --- a/Mathlib/Data/Fin/Basic.lean +++ b/Mathlib/Data/Fin/Basic.lean @@ -1328,6 +1328,49 @@ theorem last_sub (i : Fin (n + 1)) : last n - i = Fin.rev i := ext <| by rw [coe_sub_iff_le.2 i.le_last, val_last, val_rev, Nat.succ_sub_succ_eq_sub] #align fin.last_sub Fin.last_sub +theorem add_one_le_of_lt {n : ℕ} {a b : Fin (n + 1)} (h : a < b) : a + 1 ≤ b := by + cases' a with a ha + cases' b with b hb + cases n + · simp only [Nat.zero_eq, zero_add, Nat.lt_one_iff] at ha hb + simp [ha, hb] + simp only [le_iff_val_le_val, val_add, lt_iff_val_lt_val, val_mk, val_one] at h ⊢ + rwa [Nat.mod_eq_of_lt, Nat.succ_le_iff] + rw [Nat.succ_lt_succ_iff] + exact h.trans_le (Nat.le_of_lt_succ hb) + +theorem exists_eq_add_of_le {n : ℕ} {a b : Fin n} (h : a ≤ b) : ∃ k ≤ b, b = a + k := by + obtain ⟨k, hk⟩ : ∃ k : ℕ, (b : ℕ) = a + k := Nat.exists_eq_add_of_le h + have hkb : k ≤ b := le_add_self.trans hk.ge + refine' ⟨⟨k, hkb.trans_lt b.is_lt⟩, hkb, _⟩ + simp [Fin.ext_iff, Fin.val_add, ← hk, Nat.mod_eq_of_lt b.is_lt] + +theorem exists_eq_add_of_lt {n : ℕ} {a b : Fin (n + 1)} (h : a < b) : + ∃ k < b, k + 1 ≤ b ∧ b = a + k + 1 := by + cases n + · cases' a with a ha + cases' b with b hb + simp only [Nat.zero_eq, zero_add, Nat.lt_one_iff] at ha hb + simp [ha, hb] at h + obtain ⟨k, hk⟩ : ∃ k : ℕ, (b : ℕ) = a + k + 1 := Nat.exists_eq_add_of_lt h + have hkb : k < b := by + rw [hk, add_comm _ k, Nat.lt_succ_iff] + exact le_self_add + refine' ⟨⟨k, hkb.trans b.is_lt⟩, hkb, _, _⟩ + · rw [Fin.le_iff_val_le_val, Fin.val_add_one] + split_ifs <;> simp [Nat.succ_le_iff, hkb] + simp [Fin.ext_iff, Fin.val_add, ← hk, Nat.mod_eq_of_lt b.is_lt] + +@[simp] +theorem neg_last (n : ℕ) : -Fin.last n = 1 := by simp [neg_eq_iff_add_eq_zero] + +theorem neg_nat_cast_eq_one (n : ℕ) : -(n : Fin (n + 1)) = 1 := by + simp only [cast_nat_eq_last, neg_last] + +lemma pos_of_ne_zero {n : ℕ} {a : Fin (n + 1)} (h : a ≠ 0) : + 0 < a := + Nat.pos_of_ne_zero (val_ne_of_ne h) + end AddGroup section SuccAbove From 37c36be5e9639ab9ee330ad12f150b804bddaf21 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Mon, 1 Jan 2024 05:58:55 +0000 Subject: [PATCH 291/353] feat(Data/Finset/Card): bounds on cardinalities of explicit finsets (#9362) --- Mathlib/Data/Finset/Card.lean | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean index e284e7657663d..44a1850032bb5 100644 --- a/Mathlib/Data/Finset/Card.lean +++ b/Mathlib/Data/Finset/Card.lean @@ -120,6 +120,26 @@ theorem card_insert_le (a : α) (s : Finset α) : card (insert a s) ≤ s.card + · rw [card_insert_of_not_mem h] #align finset.card_insert_le Finset.card_insert_le +section + +variable {a b c d e f : α} + +theorem card_le_two : card {a, b} ≤ 2 := card_insert_le _ _ + +theorem card_le_three : card {a, b, c} ≤ 3 := + (card_insert_le _ _).trans (Nat.succ_le_succ card_le_two) + +theorem card_le_four : card {a, b, c, d} ≤ 4 := + (card_insert_le _ _).trans (Nat.succ_le_succ card_le_three) + +theorem card_le_five : card {a, b, c, d, e} ≤ 5 := + (card_insert_le _ _).trans (Nat.succ_le_succ card_le_four) + +theorem card_le_six : card {a, b, c, d, e, f} ≤ 6 := + (card_insert_le _ _).trans (Nat.succ_le_succ card_le_five) + +end + /-- If `a ∈ s` is known, see also `Finset.card_insert_of_mem` and `Finset.card_insert_of_not_mem`. -/ theorem card_insert_eq_ite : card (insert a s) = if a ∈ s then s.card else s.card + 1 := by From f3a26801e0fab592ddb8ed611d001804e7a2633e Mon Sep 17 00:00:00 2001 From: Jujian Zhang Date: Mon, 1 Jan 2024 07:00:55 +0000 Subject: [PATCH 292/353] feat(AlgebraicGeometry/PrimeSpectrum/*) : the collection of minimal prime ideals of a Noetherian ring is finite (#9088) Co-PR : #9087 (maximal ideals of Artinian ring are finite) Co-authored-by: Andrew Yang Co-authored-by: Junyan Xu Co-authored-by: Junyan Xu --- .../PrimeSpectrum/Basic.lean | 73 +++++++++++++++++++ .../PrimeSpectrum/Noetherian.lean | 5 ++ Mathlib/RingTheory/Ideal/MinimalPrime.lean | 4 + 3 files changed, 82 insertions(+) diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean index b31c49ee9770f..d396af7afdcd6 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean @@ -6,6 +6,7 @@ Authors: Johan Commelin import Mathlib.LinearAlgebra.Finsupp import Mathlib.RingTheory.Ideal.Over import Mathlib.RingTheory.Ideal.Prod +import Mathlib.RingTheory.Ideal.MinimalPrime import Mathlib.RingTheory.Localization.Away.Basic import Mathlib.RingTheory.Nilpotent import Mathlib.Topology.Sets.Closeds @@ -544,6 +545,19 @@ theorem isIrreducible_iff_vanishingIdeal_isPrime {s : Set (PrimeSpectrum R)} : isIrreducible_zeroLocus_iff_of_radical _ (isRadical_vanishingIdeal s)] #align prime_spectrum.is_irreducible_iff_vanishing_ideal_is_prime PrimeSpectrum.isIrreducible_iff_vanishingIdeal_isPrime +lemma vanishingIdeal_isIrreducible {R} [CommRing R] : + vanishingIdeal (R := R) '' {s | IsIrreducible s} = {P | P.IsPrime} := + Set.ext fun I ↦ ⟨fun ⟨_, hs, e⟩ ↦ e ▸ isIrreducible_iff_vanishingIdeal_isPrime.mp hs, + fun h ↦ ⟨zeroLocus I, (isIrreducible_zeroLocus_iff_of_radical _ h.isRadical).mpr h, + (vanishingIdeal_zeroLocus_eq_radical I).trans h.radical⟩⟩ + +lemma vanishingIdeal_isClosed_isIrreducible {R} [CommRing R] : + vanishingIdeal (R := R) '' {s | IsClosed s ∧ IsIrreducible s} = {P | P.IsPrime} := by + refine (subset_antisymm ?_ ?_).trans vanishingIdeal_isIrreducible + · exact Set.image_subset _ fun _ ↦ And.right + rintro _ ⟨s, hs, rfl⟩ + exact ⟨closure s, ⟨isClosed_closure, hs.closure⟩, vanishingIdeal_closure s⟩ + instance irreducibleSpace [IsDomain R] : IrreducibleSpace (PrimeSpectrum R) := by rw [irreducibleSpace_def, Set.top_eq_univ, ← zeroLocus_bot, isIrreducible_zeroLocus_iff] simpa using Ideal.bot_prime @@ -927,6 +941,65 @@ def localizationMapOfSpecializes {x y : PrimeSpectrum R} (h : x ⤳ y) : ⟨a, show a ∈ x.asIdeal.primeCompl from h ha⟩ : _)) #align prime_spectrum.localization_map_of_specializes PrimeSpectrum.localizationMapOfSpecializes +variable (R) in +/-- +Zero loci of prime ideals are closed irreducible sets in the Zariski topology and any closed +irreducible set is a zero locus of some prime ideal. +-/ +protected def pointsEquivIrreducibleCloseds : + PrimeSpectrum R ≃o {s : Set (PrimeSpectrum R) | IsIrreducible s ∧ IsClosed s}ᵒᵈ where + __ := irreducibleSetEquivPoints.toEquiv.symm.trans OrderDual.toDual + map_rel_iff' {p q} := + (RelIso.symm irreducibleSetEquivPoints).map_rel_iff.trans (le_iff_specializes p q).symm + +end PrimeSpectrum + +open PrimeSpectrum in +/-- +[Stacks: Lemma 00ES (3)](https://stacks.math.columbia.edu/tag/00ES) +Zero loci of minimal prime ideals of `R` are irreducible components in `Spec R` and any +irreducible component is a zero locus of some minimal prime ideal. +-/ +protected def minimalPrimes.equivIrreducibleComponents : + minimalPrimes R ≃o (irreducibleComponents <| PrimeSpectrum R)ᵒᵈ := + let e : {p : Ideal R | p.IsPrime ∧ ⊥ ≤ p} ≃o PrimeSpectrum R := + ⟨⟨fun x ↦ ⟨x.1, x.2.1⟩, fun x ↦ ⟨x.1, x.2, bot_le⟩, fun _ ↦ rfl, fun _ ↦ rfl⟩, Iff.rfl⟩ + (e.trans <| PrimeSpectrum.pointsEquivIrreducibleCloseds R).minimalsIsoMaximals.trans + (OrderIso.setCongr _ _ <| by simp_rw [irreducibleComponents_eq_maximals_closed, and_comm]).dual + +namespace PrimeSpectrum + +lemma vanishingIdeal_irreducibleComponents : + vanishingIdeal '' (irreducibleComponents <| PrimeSpectrum R) = + minimalPrimes R := by + rw [irreducibleComponents_eq_maximals_closed, minimalPrimes_eq_minimals, ← minimals_swap, + ← PrimeSpectrum.vanishingIdeal_isClosed_isIrreducible, image_minimals_of_rel_iff_rel] + exact fun s t hs _ ↦ vanishingIdeal_anti_mono_iff hs.1 + +lemma zeroLocus_minimalPrimes : + zeroLocus ∘ (↑) '' minimalPrimes R = + irreducibleComponents (PrimeSpectrum R) := by + rw [← vanishingIdeal_irreducibleComponents, ← Set.image_comp, Set.EqOn.image_eq_self] + intros s hs + simpa [zeroLocus_vanishingIdeal_eq_closure, closure_eq_iff_isClosed] + using isClosed_of_mem_irreducibleComponents s hs + +variable {R} + +lemma vanishingIdeal_mem_minimalPrimes {s : Set (PrimeSpectrum R)} : + vanishingIdeal s ∈ minimalPrimes R ↔ closure s ∈ irreducibleComponents (PrimeSpectrum R) := by + constructor + · rw [← zeroLocus_minimalPrimes, ← zeroLocus_vanishingIdeal_eq_closure] + exact Set.mem_image_of_mem _ + · rw [← vanishingIdeal_irreducibleComponents, ← vanishingIdeal_closure] + exact Set.mem_image_of_mem _ + +lemma zeroLocus_ideal_mem_irreducibleComponents {I : Ideal R} : + zeroLocus I ∈ irreducibleComponents (PrimeSpectrum R) ↔ I.radical ∈ minimalPrimes R := by + rw [← vanishingIdeal_zeroLocus_eq_radical] + conv_lhs => rw [← (isClosed_zeroLocus _).closure_eq] + exact vanishingIdeal_mem_minimalPrimes.symm + end PrimeSpectrum namespace LocalRing diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean index 7048cabc717c3..b6540fb770f4a 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean @@ -107,4 +107,9 @@ instance : NoetherianSpace (PrimeSpectrum R) := by rw [isNoetherianRing_iff, isNoetherian_iff_wellFounded] at H exact (closedsEmbedding R).dual.wellFounded H +lemma _root_.minimalPrimes.finite_of_isNoetherianRing : (minimalPrimes R).Finite := + minimalPrimes.equivIrreducibleComponents R + |>.set_finite_iff + |>.mpr NoetherianSpace.finite_irreducibleComponents + end PrimeSpectrum diff --git a/Mathlib/RingTheory/Ideal/MinimalPrime.lean b/Mathlib/RingTheory/Ideal/MinimalPrime.lean index a482fee1e85c7..0c316125e9cfd 100644 --- a/Mathlib/RingTheory/Ideal/MinimalPrime.lean +++ b/Mathlib/RingTheory/Ideal/MinimalPrime.lean @@ -45,6 +45,10 @@ def minimalPrimes (R : Type*) [CommRing R] : Set (Ideal R) := Ideal.minimalPrimes ⊥ #align minimal_primes minimalPrimes +lemma minimalPrimes_eq_minimals {R} [CommRing R] : + minimalPrimes R = minimals (· ≤ ·) (setOf Ideal.IsPrime) := + congr_arg (minimals (· ≤ ·)) (by simp) + variable {I J} theorem Ideal.exists_minimalPrimes_le [J.IsPrime] (e : I ≤ J) : ∃ p ∈ I.minimalPrimes, p ≤ J := by From bded32ac283fda910f93483406717d28164e69dd Mon Sep 17 00:00:00 2001 From: Jz Pan Date: Mon, 1 Jan 2024 07:00:56 +0000 Subject: [PATCH 293/353] feat(FieldTheory/SeparableClosure): (relative) separable closure (#9338) Main definitions: - `separableClosure`: the (relative) separable closure of `E / F`, or called maximal separable subextension of `E / F`, is defined to be the intermediate field of `E / F` consisting of all separable elements. - `Field.sepDegree F E`: the (infinite) separable degree `[E:F]_s` of an algebraic extension `E / F` of fields, defined to be the degree of `separableClosure F E / F`. - `Field.insepDegree F E`: the (infinite) inseparable degree `[E:F]_i` of an algebraic extension `E / F` of fields, defined to be the degree of `E / separableClosure F E`. - `Field.finInsepDegree F E`: the (finite) inseparable degree `[E:F]_i` of an algebraic extension `E / F` of fields, defined to be the degree of `E / separableClosure F E` as a natural number. It is zero if such field extension is not finite. Main results: - `le_separableClosure_iff`: an intermediate field of `E / F` is contained in the (relative) separable closure of `E / F` if and only if it is separable over `F`. - `separableClosure.normalClosure_eq_self`: the normal closure of the (relative) separable closure of `E / F` is equal to itself. - `separableClosure.normal`: the (relative) separable closure of a normal extension is normal. - `separableClosure.isSepClosure`: the (relative) separable closure of a separably closed extension is a separable closure of the base field. - `IntermediateField.isSeparable_adjoin_iff_separable`: `F(S) / F` is a separable extension if and only if all elements of `S` are separable elements. - `separableClosure.eq_top_iff`: the (relative) separable closure of `E / F` is equal to `E` if and only if `E / F` is separable. --- Mathlib.lean | 1 + Mathlib/FieldTheory/Adjoin.lean | 4 + Mathlib/FieldTheory/IsAlgClosed/Basic.lean | 9 + Mathlib/FieldTheory/IsSepClosed.lean | 29 +- Mathlib/FieldTheory/SeparableClosure.lean | 386 +++++++++++++++++++++ Mathlib/FieldTheory/SeparableDegree.lean | 34 +- 6 files changed, 442 insertions(+), 21 deletions(-) create mode 100644 Mathlib/FieldTheory/SeparableClosure.lean diff --git a/Mathlib.lean b/Mathlib.lean index ba5eda1fb5d28..0f72eb31465b9 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2085,6 +2085,7 @@ import Mathlib.FieldTheory.PolynomialGaloisGroup import Mathlib.FieldTheory.PrimitiveElement import Mathlib.FieldTheory.RatFunc import Mathlib.FieldTheory.Separable +import Mathlib.FieldTheory.SeparableClosure import Mathlib.FieldTheory.SeparableDegree import Mathlib.FieldTheory.SplittingField.Construction import Mathlib.FieldTheory.SplittingField.IsSplittingField diff --git a/Mathlib/FieldTheory/Adjoin.lean b/Mathlib/FieldTheory/Adjoin.lean index b8beaf4641b94..ada78d06a3dfd 100644 --- a/Mathlib/FieldTheory/Adjoin.lean +++ b/Mathlib/FieldTheory/Adjoin.lean @@ -102,6 +102,10 @@ instance : CompleteLattice (IntermediateField F E) where instance : Inhabited (IntermediateField F E) := ⟨⊤⟩ +instance : Unique (IntermediateField F F) := + { inferInstanceAs (Inhabited (IntermediateField F F)) with + uniq := fun _ ↦ toSubalgebra_injective <| Subsingleton.elim _ _ } + theorem coe_bot : ↑(⊥ : IntermediateField F E) = Set.range (algebraMap F E) := rfl #align intermediate_field.coe_bot IntermediateField.coe_bot diff --git a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean index 9f307115bfc88..5aa7f231ec507 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean @@ -184,6 +184,15 @@ theorem algebraMap_surjective_of_isAlgebraic {k K : Type*} [Field k] [Ring K] [I end IsAlgClosed +/-- If `k` is algebraically closed, `K / k` is a field extension, `L / k` is an intermediate field +which is algebraic, then `L` is equal to `k`. A corollary of +`IsAlgClosed.algebraMap_surjective_of_isAlgebraic`. -/ +theorem IntermediateField.eq_bot_of_isAlgClosed_of_isAlgebraic {k K : Type*} [Field k] [Field K] + [IsAlgClosed k] [Algebra k K] (L : IntermediateField k K) (hf : Algebra.IsAlgebraic k L) : + L = ⊥ := bot_unique fun x hx ↦ by + obtain ⟨y, hy⟩ := IsAlgClosed.algebraMap_surjective_of_isAlgebraic hf ⟨x, hx⟩ + exact ⟨y, congr_arg (algebraMap L K) hy⟩ + /-- Typeclass for an extension being an algebraic closure. -/ class IsAlgClosure (R : Type u) (K : Type v) [CommRing R] [Field K] [Algebra R K] [NoZeroSMulDivisors R K] : Prop where diff --git a/Mathlib/FieldTheory/IsSepClosed.lean b/Mathlib/FieldTheory/IsSepClosed.lean index d455deb141c88..76070f0d8a24d 100644 --- a/Mathlib/FieldTheory/IsSepClosed.lean +++ b/Mathlib/FieldTheory/IsSepClosed.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jz Pan -/ import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure +import Mathlib.FieldTheory.Galois /-! # Separably Closed Field @@ -29,15 +30,17 @@ and prove some of their properties. separable closure, separably closed -## TODO +## Related + +- `separableClosure`: maximal separable subextension of `K/k`, consisting of all elements of `K` + which are separable over `k`. -- Maximal separable subextension of `K/k`, consisting of all elements of `K` which are separable - over `k`. +- `separableClosure.isSepClosure`: if `K` is a separably closed field containing `k`, then the + maximal separable subextension of `K/k` is a separable closure of `k`. -- If `K` is a separably closed field containing `k`, then the maximal separable subextension - of `K/k` is a separable closure of `k`. +- In particular, a separable closure (`SeparableClosure`) exists. -- In particular, a separable closure exists. +## TODO - If `k` is a perfect field, then its separable closure coincides with its algebraic closure. @@ -153,7 +156,7 @@ theorem degree_eq_one_of_irreducible [IsSepClosed k] {p : k[X]} (hp : Irreducible p) (hsep : p.Separable) : p.degree = 1 := degree_eq_one_of_irreducible_of_splits hp (IsSepClosed.splits_codomain p hsep) -variable {k} +variable (K) theorem algebraMap_surjective [IsSepClosed k] [Algebra k K] [IsSeparable k K] : @@ -170,6 +173,13 @@ theorem algebraMap_surjective end IsSepClosed +/-- If `k` is separably closed, `K / k` is a field extension, `L / k` is an intermediate field +which is separable, then `L` is equal to `k`. A corollary of `IsSepClosed.algebraMap_surjective`. -/ +theorem IntermediateField.eq_bot_of_isSepClosed_of_isSeparable [IsSepClosed k] [Algebra k K] + (L : IntermediateField k K) [IsSeparable k L] : L = ⊥ := bot_unique fun x hx ↦ by + obtain ⟨y, hy⟩ := IsSepClosed.algebraMap_surjective k L ⟨x, hx⟩ + exact ⟨y, congr_arg (algebraMap L K) hy⟩ + variable (k) (K) /-- Typeclass for an extension being a separable closure. -/ @@ -192,8 +202,9 @@ namespace IsSepClosure instance isSeparable [Algebra k K] [IsSepClosure k K] : IsSeparable k K := IsSepClosure.separable -instance (priority := 100) normal [Algebra k K] [IsSepClosure k K] : Normal k K := - ⟨fun x ↦ (IsSeparable.isIntegral k x).isAlgebraic, +instance (priority := 100) isGalois [Algebra k K] [IsSepClosure k K] : IsGalois k K where + to_isSeparable := IsSepClosure.separable + to_normal := ⟨fun x ↦ (IsSeparable.isIntegral k x).isAlgebraic, fun x ↦ (IsSepClosure.sep_closed k).splits_codomain _ (IsSeparable.separable k x)⟩ end IsSepClosure diff --git a/Mathlib/FieldTheory/SeparableClosure.lean b/Mathlib/FieldTheory/SeparableClosure.lean new file mode 100644 index 0000000000000..29e5e2dd93ca7 --- /dev/null +++ b/Mathlib/FieldTheory/SeparableClosure.lean @@ -0,0 +1,386 @@ +/- +Copyright (c) 2023 Jz Pan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jz Pan +-/ +import Mathlib.FieldTheory.SeparableDegree +import Mathlib.FieldTheory.IsSepClosed + +/-! + +# Separable closure + +This file contains basics about the (relative) separable closure of a field extension. + +## Main definitions + +- `separableClosure`: the (relative) separable closure of `E / F`, or called maximal separable + subextension of `E / F`, is defined to be the intermediate field of `E / F` consisting of all + separable elements. + +- `SeparableClosure`: the (absolute) separable closure, defined to be the (relative) separable + closure inside the algebraic closure. + +- `Field.sepDegree F E`: the (infinite) separable degree $[E:F]_s$ of an algebraic extension + `E / F` of fields, defined to be the degree of `separableClosure F E / F`. Later we will show + that (`Field.finSepDegree_eq`, not in this file), if `Field.Emb F E` is finite, then this + coincides with `Field.finSepDegree F E`. + +- `Field.insepDegree F E`: the (infinite) inseparable degree $[E:F]_i$ of an algebraic extension + `E / F` of fields, defined to be the degree of `E / separableClosure F E`. + +- `Field.finInsepDegree F E`: the (finite) inseparable degree $[E:F]_i$ of an algebraic extension + `E / F` of fields, defined to be the degree of `E / separableClosure F E` as a natural number. + It is zero if such field extension is not finite. + +## Main results + +- `le_separableClosure_iff`: an intermediate field of `E / F` is contained in the (relative) + separable closure of `E / F` if and only if it is separable over `F`. + +- `separableClosure.normalClosure_eq_self`: the normal closure of the (relative) separable + closure of `E / F` is equal to itself. + +- `separableClosure.isGalois`: the (relative) separable closure of a normal extension is Galois + (namely, normal and separable). + +- `separableClosure.isSepClosure`: the (relative) separable closure of a separably closed extension + is a separable closure of the base field. + +- `IntermediateField.isSeparable_adjoin_iff_separable`: `F(S) / F` is a separable extension if and + only if all elements of `S` are separable elements. + +- `separableClosure.eq_top_iff`: the (relative) separable closure of `E / F` is equal to `E` + if and only if `E / F` is separable. + +## Tags + +separable degree, degree, separable closure + +-/ + +open scoped Classical Polynomial + +open FiniteDimensional Polynomial IntermediateField Field + +noncomputable section + +universe u v w + +variable (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] + +variable (K : Type w) [Field K] [Algebra F K] + +section separableClosure + +/-- The (relative) separable closure of `E / F`, or called maximal separable subextension +of `E / F`, is defined to be the intermediate field of `E / F` consisting of all separable +elements. The previous results prove that these elements are closed under field operations. -/ +def separableClosure : IntermediateField F E where + carrier := {x | (minpoly F x).Separable} + mul_mem' := separable_mul + one_mem' := map_one (algebraMap F E) ▸ separable_algebraMap E 1 + add_mem' := separable_add + zero_mem' := map_zero (algebraMap F E) ▸ separable_algebraMap E 0 + algebraMap_mem' := separable_algebraMap E + inv_mem' := separable_inv + +variable {F E K} + +/-- An element is contained in the (relative) separable closure of `E / F` if and only if +it is a separable element. -/ +theorem mem_separableClosure_iff {x : E} : + x ∈ separableClosure F E ↔ (minpoly F x).Separable := Iff.rfl + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then `i x` is contained in +`separableClosure F K` if and only if `x` is contained in `separableClosure F E`. -/ +theorem map_mem_separableClosure_iff (i : E →ₐ[F] K) {x : E} : + i x ∈ separableClosure F K ↔ x ∈ separableClosure F E := by + simp_rw [mem_separableClosure_iff, minpoly.algHom_eq i i.injective] + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then `separableClosure F E` is equal to +the preimage of `separableClosure F K` under the map `i`. -/ +theorem separableClosure.eq_comap_of_algHom (i : E →ₐ[F] K) : + separableClosure F E = (separableClosure F K).comap i := by + ext x + exact (map_mem_separableClosure_iff i).symm + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then `separableClosure F K` contains +the image of `separableClosure F E` under the map `i`. -/ +theorem separableClosure.map_le_of_algHom (i : E →ₐ[F] K) : + (separableClosure F E).map i ≤ separableClosure F K := + map_le_iff_le_comap.2 (eq_comap_of_algHom i).le + +variable (F) in +/-- If `K / E / F` is a field extension tower, such that `K / E` has no non-trivial separable +subextensions (when `K / E` is algebraic, this means that it is purely inseparable), +then `separableClosure F K` is equal to `separableClosure F E`. -/ +theorem separableClosure.eq_map_of_separableClosure_eq_bot [Algebra E K] [IsScalarTower F E K] + (h : separableClosure E K = ⊥) : + separableClosure F K = (separableClosure F E).map (IsScalarTower.toAlgHom F E K) := by + refine le_antisymm (fun x hx ↦ ?_) (map_le_of_algHom _) + obtain ⟨y, rfl⟩ := mem_bot.1 <| h ▸ mem_separableClosure_iff.2 + (mem_separableClosure_iff.1 hx |>.map_minpoly E) + exact ⟨y, (map_mem_separableClosure_iff <| IsScalarTower.toAlgHom F E K).mp hx, rfl⟩ + +/-- If `i` is an `F`-algebra isomorphism of `E` and `K`, then `separableClosure F K` is equal to +the image of `separableClosure F E` under the map `i`. -/ +theorem separableClosure.eq_map_of_algEquiv (i : E ≃ₐ[F] K) : + separableClosure F K = (separableClosure F E).map i := + le_antisymm (fun x h ↦ ⟨_, (map_mem_separableClosure_iff i.symm).2 h, by simp⟩) + (map_le_of_algHom i.toAlgHom) + +/-- If `E` and `K` are isomorphic as `F`-algebras, then `separableClosure F E` and +`separableClosure F K` are also isomorphic as `F`-algebras. -/ +def separableClosure.algEquivOfAlgEquiv (i : E ≃ₐ[F] K) : + separableClosure F E ≃ₐ[F] separableClosure F K := + ((separableClosure F E).intermediateFieldMap i).trans + (equivOfEq (eq_map_of_algEquiv i).symm) + +alias AlgEquiv.separableClosure := separableClosure.algEquivOfAlgEquiv + +variable (F E K) + +/-- The (relative) separable closure of `E / F` is algebraic over `F`. -/ +theorem separableClosure.isAlgebraic : Algebra.IsAlgebraic F (separableClosure F E) := + fun x ↦ isAlgebraic_iff.2 x.2.isIntegral.isAlgebraic + +/-- The (relative) separable closure of `E / F` is separable over `F`. -/ +instance separableClosure.isSeparable : IsSeparable F (separableClosure F E) := + ⟨fun x ↦ by simpa only [minpoly_eq] using x.2⟩ + +/-- An intermediate field of `E / F` is contained in the (relative) separable closure of `E / F` +if all of its elements are separable over `F`. -/ +theorem le_separableClosure' {L : IntermediateField F E} (hs : ∀ x : L, (minpoly F x).Separable) : + L ≤ separableClosure F E := fun x h ↦ by simpa only [minpoly_eq] using hs ⟨x, h⟩ + +/-- An intermediate field of `E / F` is contained in the (relative) separable closure of `E / F` +if it is separable over `F`. -/ +theorem le_separableClosure (L : IntermediateField F E) [IsSeparable F L] : + L ≤ separableClosure F E := le_separableClosure' F E (IsSeparable.separable F) + +/-- An intermediate field of `E / F` is contained in the (relative) separable closure of `E / F` +if and only if it is separable over `F`. -/ +theorem le_separableClosure_iff (L : IntermediateField F E) : + L ≤ separableClosure F E ↔ IsSeparable F L := + ⟨fun h ↦ ⟨fun x ↦ by simpa only [minpoly_eq] using h x.2⟩, fun _ ↦ le_separableClosure _ _ _⟩ + +/-- The (relative) separable closure of the (relative) separable closure of `E / F` is equal to +itself. -/ +theorem separableClosure.separableClosure_eq_bot : + separableClosure (separableClosure F E) E = ⊥ := bot_unique fun x hx ↦ + mem_bot.2 ⟨⟨x, mem_separableClosure_iff.1 hx |>.comap_minpoly_of_isSeparable F⟩, rfl⟩ + +/-- The normal closure of the (relative) separable closure of `E / F` is equal to itself. -/ +theorem separableClosure.normalClosure_eq_self : + normalClosure F (separableClosure F E) E = separableClosure F E := + le_antisymm (normalClosure_le_iff.2 fun i ↦ + haveI : IsSeparable F i.fieldRange := (AlgEquiv.ofInjectiveField i).isSeparable + le_separableClosure F E _) (le_normalClosure _) + +/-- If `E` is normal over `F`, then the (relative) separable closure of `E / F` is Galois (i.e. +normal and separable) over `F`. -/ +instance separableClosure.isGalois [Normal F E] : IsGalois F (separableClosure F E) where + to_isSeparable := separableClosure.isSeparable F E + to_normal := by + rw [← separableClosure.normalClosure_eq_self] + exact normalClosure.normal F _ E + +/-- If `E / F` is a field extension, `E` is separably closed, then the (relative) separable closure +of `E / F` is equal to `F` if and only if `F` is separably closed. -/ +theorem IsSepClosed.separableClosure_eq_bot_iff [IsSepClosed E] : + separableClosure F E = ⊥ ↔ IsSepClosed F := by + refine ⟨fun h ↦ IsSepClosed.of_exists_root _ fun p _ hirr hsep ↦ ?_, + fun _ ↦ IntermediateField.eq_bot_of_isSepClosed_of_isSeparable _⟩ + obtain ⟨x, hx⟩ := IsSepClosed.exists_aeval_eq_zero E p (degree_pos_of_irreducible hirr).ne' hsep + obtain ⟨x, rfl⟩ := h ▸ mem_separableClosure_iff.2 (hsep.of_dvd <| minpoly.dvd _ x hx) + exact ⟨x, by simpa [Algebra.ofId_apply] using hx⟩ + +/-- If `E` is separably closed, then the (relative) separable closure of `E / F` is a +separable closure of `F`. -/ +instance separableClosure.isSepClosure [IsSepClosed E] : IsSepClosure F (separableClosure F E) := + ⟨(IsSepClosed.separableClosure_eq_bot_iff _ E).mp (separableClosure.separableClosure_eq_bot F E), + isSeparable F E⟩ + +/-- The (absolute) separable closure is defined to be the (relative) separable closure inside the +algebraic closure. It is indeed a separable closure (`IsSepClosure`) by +`separableClosure.isSepClosure`, and it is Galois (`IsGalois`) by `separableClosure.isGalois` +or `IsSepClosure.isGalois`, and every separable extension embeds into it (`IsSepClosed.lift`). -/ +abbrev SeparableClosure : Type _ := separableClosure F (AlgebraicClosure F) + +/-- `F(S) / F` is a separable extension if and only if all elements of `S` are +separable elements. -/ +theorem IntermediateField.isSeparable_adjoin_iff_separable {S : Set E} : + IsSeparable F (adjoin F S) ↔ ∀ x ∈ S, (minpoly F x).Separable := + (le_separableClosure_iff F E _).symm.trans adjoin_le_iff + +/-- The (relative) separable closure of `E / F` is equal to `E` if and only if `E / F` is +separable. -/ +theorem separableClosure.eq_top_iff : separableClosure F E = ⊤ ↔ IsSeparable F E := + ⟨fun h ↦ ⟨fun _ ↦ mem_separableClosure_iff.1 (h ▸ mem_top)⟩, + fun _ ↦ top_unique fun x _ ↦ mem_separableClosure_iff.2 (IsSeparable.separable _ x)⟩ + +/-- If `K / E / F` is a field extension tower, then `separableClosure F K` is contained in +`separableClosure E K`. -/ +theorem separableClosure.le_restrictScalars [Algebra E K] [IsScalarTower F E K] : + separableClosure F K ≤ (separableClosure E K).restrictScalars F := fun _ h ↦ h.map_minpoly E + +/-- If `K / E / F` is a field extension tower, such that `E / F` is separable, then +`separableClosure F K` is equal to `separableClosure E K`. -/ +theorem separableClosure.eq_restrictScalars_of_isSeparable [Algebra E K] [IsScalarTower F E K] + [IsSeparable F E] : separableClosure F K = (separableClosure E K).restrictScalars F := + (separableClosure.le_restrictScalars F E K).antisymm fun _ h ↦ h.comap_minpoly_of_isSeparable F + +/-- If `K / E / F` is a field extension tower, then `E` adjoin `separableClosure F K` is contained +in `separableClosure E K`. -/ +theorem separableClosure.adjoin_le [Algebra E K] [IsScalarTower F E K] : + adjoin E (separableClosure F K) ≤ separableClosure E K := + adjoin_le_iff.2 <| le_restrictScalars F E K + +/-- A compositum of two separable extensions is separable. -/ +instance IntermediateField.isSeparable_sup (L1 L2 : IntermediateField F E) + [h1 : IsSeparable F L1] [h2 : IsSeparable F L2] : + IsSeparable F (L1 ⊔ L2 : IntermediateField F E) := by + rw [← le_separableClosure_iff] at h1 h2 ⊢ + exact sup_le h1 h2 + +/-- A compositum of separable extensions is separable. -/ +instance IntermediateField.isSeparable_iSup {ι : Type*} {t : ι → IntermediateField F E} + [h : ∀ i, IsSeparable F (t i)] : IsSeparable F (⨆ i, t i : IntermediateField F E) := by + simp_rw [← le_separableClosure_iff] at h ⊢ + exact iSup_le h + +end separableClosure + +namespace Field + +/-- The (infinite) separable degree for a general field extension `E / F` is defined +to be the degree of `separableClosure F E / F`. -/ +def sepDegree := Module.rank F (separableClosure F E) + +/-- The (infinite) inseparable degree for a general field extension `E / F` is defined +to be the degree of `E / separableClosure F E`. -/ +def insepDegree := Module.rank (separableClosure F E) E + +/-- The (finite) inseparable degree for a general field extension `E / F` is defined +to be the degree of `E / separableClosure F E` as a natural number. It is defined to be zero +if such field extension is infinite. -/ +def finInsepDegree : ℕ := finrank (separableClosure F E) E + +theorem finInsepDegree_def' : finInsepDegree F E = Cardinal.toNat (insepDegree F E) := rfl + +instance instNeZeroSepDegree : NeZero (sepDegree F E) := ⟨rank_pos.ne'⟩ + +instance instNeZeroInsepDegree : NeZero (insepDegree F E) := ⟨rank_pos.ne'⟩ + +instance instNeZeroFinInsepDegree [FiniteDimensional F E] : + NeZero (finInsepDegree F E) := ⟨finrank_pos.ne'⟩ + +/-- If `E` and `K` are isomorphic as `F`-algebras, then they have the same (infinite) +separable degree over `F`. -/ +theorem lift_sepDegree_eq_of_equiv (i : E ≃ₐ[F] K) : + Cardinal.lift.{w} (sepDegree F E) = Cardinal.lift.{v} (sepDegree F K) := + i.separableClosure.toLinearEquiv.lift_rank_eq + +/-- The same-universe version of `Field.lift_sepDegree_eq_of_equiv`. -/ +theorem sepDegree_eq_of_equiv (K : Type v) [Field K] [Algebra F K] (i : E ≃ₐ[F] K) : + sepDegree F E = sepDegree F K := + i.separableClosure.toLinearEquiv.rank_eq + +/-- The (infinite) separable degree multiply by the (infinite) inseparable degree is equal +to the (infinite) field extension degree. -/ +theorem sepDegree_mul_insepDegree : sepDegree F E * insepDegree F E = Module.rank F E := + rank_mul_rank F (separableClosure F E) E + +/-- If `E` and `K` are isomorphic as `F`-algebras, then they have the same (infinite) +inseparable degree over `F`. -/ +theorem lift_insepDegree_eq_of_equiv (i : E ≃ₐ[F] K) : + Cardinal.lift.{w} (insepDegree F E) = Cardinal.lift.{v} (insepDegree F K) := + Algebra.lift_rank_eq_of_equiv_equiv i.separableClosure i rfl + +/-- The same-universe version of `Field.lift_insepDegree_eq_of_equiv`. -/ +theorem insepDegree_eq_of_equiv (K : Type v) [Field K] [Algebra F K] (i : E ≃ₐ[F] K) : + insepDegree F E = insepDegree F K := + Algebra.rank_eq_of_equiv_equiv i.separableClosure i rfl + +/-- If `E` and `K` are isomorphic as `F`-algebras, then they have the same (finite) +inseparable degree over `F`. -/ +theorem finInsepDegree_eq_of_equiv (i : E ≃ₐ[F] K) : + finInsepDegree F E = finInsepDegree F K := by + simpa only [Cardinal.toNat_lift] using congr_arg Cardinal.toNat + (lift_insepDegree_eq_of_equiv F E K i) + +@[simp] +theorem sepDegree_self : sepDegree F F = 1 := by + rw [sepDegree, Subsingleton.elim (separableClosure F F) ⊥, IntermediateField.rank_bot] + +@[simp] +theorem insepDegree_self : insepDegree F F = 1 := by + rw [insepDegree, Subsingleton.elim (separableClosure F F) ⊤, IntermediateField.rank_top] + +@[simp] +theorem finInsepDegree_self : finInsepDegree F F = 1 := by + rw [finInsepDegree_def', insepDegree_self, Cardinal.one_toNat] + +end Field + +namespace IntermediateField + +@[simp] +theorem sepDegree_bot : sepDegree F (⊥ : IntermediateField F E) = 1 := by + have := lift_sepDegree_eq_of_equiv _ _ _ (botEquiv F E) + rwa [sepDegree_self, Cardinal.lift_one, ← Cardinal.lift_one.{u, v}, Cardinal.lift_inj] at this + +@[simp] +theorem insepDegree_bot : insepDegree F (⊥ : IntermediateField F E) = 1 := by + have := lift_insepDegree_eq_of_equiv _ _ _ (botEquiv F E) + rwa [insepDegree_self, Cardinal.lift_one, ← Cardinal.lift_one.{u, v}, Cardinal.lift_inj] at this + +@[simp] +theorem finInsepDegree_bot : finInsepDegree F (⊥ : IntermediateField F E) = 1 := by + rw [finInsepDegree_eq_of_equiv _ _ _ (botEquiv F E), finInsepDegree_self] + +section Tower + +variable [Algebra E K] [IsScalarTower F E K] + +theorem lift_sepDegree_bot' : Cardinal.lift.{v} (sepDegree F (⊥ : IntermediateField E K)) = + Cardinal.lift.{w} (sepDegree F E) := + lift_sepDegree_eq_of_equiv _ _ _ ((botEquiv E K).restrictScalars F) + +theorem lift_insepDegree_bot' : Cardinal.lift.{v} (insepDegree F (⊥ : IntermediateField E K)) = + Cardinal.lift.{w} (insepDegree F E) := + lift_insepDegree_eq_of_equiv _ _ _ ((botEquiv E K).restrictScalars F) + +variable {F} + +@[simp] +theorem finInsepDegree_bot' : + finInsepDegree F (⊥ : IntermediateField E K) = finInsepDegree F E := by + simpa only [Cardinal.toNat_lift] using congr_arg Cardinal.toNat (lift_insepDegree_bot' F E K) + +@[simp] +theorem sepDegree_top : sepDegree F (⊤ : IntermediateField E K) = sepDegree F K := + sepDegree_eq_of_equiv _ _ _ ((topEquiv (F := E) (E := K)).restrictScalars F) + +@[simp] +theorem insepDegree_top : insepDegree F (⊤ : IntermediateField E K) = insepDegree F K := + insepDegree_eq_of_equiv _ _ _ ((topEquiv (F := E) (E := K)).restrictScalars F) + +@[simp] +theorem finInsepDegree_top : finInsepDegree F (⊤ : IntermediateField E K) = finInsepDegree F K := by + rw [finInsepDegree_def', insepDegree_top, ← finInsepDegree_def'] + +variable (K : Type v) [Field K] [Algebra F K] [Algebra E K] [IsScalarTower F E K] + +@[simp] +theorem sepDegree_bot' : sepDegree F (⊥ : IntermediateField E K) = sepDegree F E := + sepDegree_eq_of_equiv _ _ _ ((botEquiv E K).restrictScalars F) + +@[simp] +theorem insepDegree_bot' : insepDegree F (⊥ : IntermediateField E K) = insepDegree F E := + insepDegree_eq_of_equiv _ _ _ ((botEquiv E K).restrictScalars F) + +end Tower + +end IntermediateField diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean index fe70c9b5b9745..ff9f8f743c017 100644 --- a/Mathlib/FieldTheory/SeparableDegree.lean +++ b/Mathlib/FieldTheory/SeparableDegree.lean @@ -625,9 +625,11 @@ theorem IntermediateField.isSeparable_adjoin_simple_iff_separable {x : E} : rwa [← finSepDegree_eq_finrank_iff, finSepDegree_adjoin_simple_eq_finrank_iff F E x h.isAlgebraic] -/-- If `E / F` and `K / E` are both separable extensions, then `K / F` is also separable. -/ -theorem IsSeparable.trans [Algebra E K] [IsScalarTower F E K] - [IsSeparable F E] [IsSeparable E K] : IsSeparable F K := (isSeparable_def F K).2 fun x ↦ by +variable {E K} in +/-- If `K / E / F` is an extension tower such that `E / F` is separable, +`x : K` is separable over `E`, then it's also separable over `F`. -/ +theorem Polynomial.Separable.comap_minpoly_of_isSeparable [Algebra E K] [IsScalarTower F E K] + [IsSeparable F E] {x : K} (hsep : (minpoly E x).Separable) : (minpoly F x).Separable := by let f := minpoly E x let E' : IntermediateField F E := adjoin F f.frange haveI : FiniteDimensional F E' := finiteDimensional_adjoin fun x _ ↦ IsSeparable.isIntegral F x @@ -637,10 +639,9 @@ theorem IsSeparable.trans [Algebra E K] [IsScalarTower F E K] have hx : x ∈ restrictScalars F E'⟮x⟯ := mem_adjoin_simple_self _ x have hzero : aeval x g = 0 := by simpa only [← h, aeval_map_algebraMap] using minpoly.aeval E x - have halg : IsIntegral E' x := (IsSeparable.isAlgebraic F E).trans - (IsSeparable.isAlgebraic E K) x |>.isIntegral.tower_top - have hsep : f.Separable := IsSeparable.separable E x - rw [← h, separable_map] at hsep + have halg : IsIntegral E' x := + isIntegral_trans (IsSeparable.isAlgebraic F E).isIntegral _ hsep.isIntegral |>.tower_top + simp_rw [← h, separable_map] at hsep replace hsep := hsep.of_dvd <| minpoly.dvd _ _ hzero haveI : IsSeparable F E' := isSeparable_tower_bot_of_isSeparable F E' E haveI := (isSeparable_adjoin_simple_iff_separable _ _).2 hsep @@ -654,6 +655,11 @@ theorem IsSeparable.trans [Algebra E K] [IsScalarTower F E K] change IsSeparable F (restrictScalars F E'⟮x⟯) at this exact separable_of_mem_isSeparable F K hx +/-- If `E / F` and `K / E` are both separable extensions, then `K / F` is also separable. -/ +theorem IsSeparable.trans [Algebra E K] [IsScalarTower F E K] + [IsSeparable F E] [IsSeparable E K] : IsSeparable F K := + ⟨fun x ↦ (IsSeparable.separable E x).comap_minpoly_of_isSeparable F⟩ + /-- If `x` and `y` are both separable elements, then `F⟮x, y⟯ / F` is a separable extension. As a consequence, any rational function of `x` and `y` is also a separable element. -/ theorem IntermediateField.isSeparable_adjoin_pair_of_separable {x y : E} @@ -666,6 +672,15 @@ theorem IntermediateField.isSeparable_adjoin_pair_of_separable {x y : E} namespace Field +variable {F} + +/-- Any element `x` of `F` is a separable element of `E / F` when embedded into `E`. -/ +theorem separable_algebraMap (x : F) : (minpoly F ((algebraMap F E) x)).Separable := by + rw [minpoly.algebraMap_eq (algebraMap F E).injective] + exact IsSeparable.separable F x + +variable {E} + /-- If `x` and `y` are both separable elements, then `x * y` is also a separable element. -/ theorem separable_mul {x y : E} (hx : (minpoly F x).Separable) (hy : (minpoly F y).Separable) : (minpoly F (x * y)).Separable := @@ -680,11 +695,6 @@ theorem separable_add {x y : E} (hx : (minpoly F x).Separable) (hy : (minpoly F separable_of_mem_isSeparable F E <| F⟮x, y⟯.add_mem (subset_adjoin F _ (.inl rfl)) (subset_adjoin F _ (.inr rfl)) -/-- Any element `x` of `F` is a separable element of `E / F` when embedded into `E`. -/ -theorem separable_algebraMap (x : F) : (minpoly F ((algebraMap F E) x)).Separable := by - rw [minpoly.algebraMap_eq (algebraMap F E).injective] - exact IsSeparable.separable F x - /-- If `x` is a separable element, then `x⁻¹` is also a separable element. -/ theorem separable_inv (x : E) (hx : (minpoly F x).Separable) : (minpoly F x⁻¹).Separable := haveI := (isSeparable_adjoin_simple_iff_separable F E).2 hx From 0c9d4118caa615ee8c9592a1da2e3fd79d682cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 1 Jan 2024 07:00:57 +0000 Subject: [PATCH 294/353] chore: Generalise monotonicity of multiplication lemmas to semirings (#9369) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many lemmas about `BlahOrderedRing α` did not mention negation. I could generalise almost all those lemmas to `BlahOrderedSemiring α` + `ExistsAddOfLE α` except for a series of five lemmas (left a TODO about them). Now those lemmas apply to things like the naturals. This is not very useful on its own, because those lemmas are trivially true on canonically ordered semirings (they are about multiplication by negative elements, of which there are none, or nonnegativity of squares, but we already know everything is nonnegative), except that I will soon add more complicated inequalities that are based on those, and it would be a shame having to write two versions of each: one for ordered rings, one for canonically ordered semirings. A similar refactor could be made for scalar multiplication, but this PR is big enough already. From LeanAPAP --- Mathlib.lean | 1 + Mathlib/Algebra/Divisibility/Basic.lean | 19 +- Mathlib/Algebra/FreeMonoid/Basic.lean | 1 + Mathlib/Algebra/GroupPower/Basic.lean | 52 +-- Mathlib/Algebra/GroupPower/Hom.lean | 49 +++ Mathlib/Algebra/GroupPower/Order.lean | 22 +- Mathlib/Algebra/GroupPower/Ring.lean | 2 +- Mathlib/Algebra/Order/Monoid/MinMax.lean | 19 +- Mathlib/Algebra/Order/Ring/Canonical.lean | 59 --- Mathlib/Algebra/Order/Ring/Defs.lean | 444 +++++++++++++--------- Mathlib/Algebra/Ring/Idempotents.lean | 3 +- Mathlib/Data/Int/Cast/Lemmas.lean | 1 + Mathlib/Data/Multiset/Bind.lean | 1 + Mathlib/Data/Set/Pointwise/Basic.lean | 1 + 14 files changed, 354 insertions(+), 320 deletions(-) create mode 100644 Mathlib/Algebra/GroupPower/Hom.lean diff --git a/Mathlib.lean b/Mathlib.lean index 0f72eb31465b9..33e166c4d41b1 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -205,6 +205,7 @@ import Mathlib.Algebra.Group.WithOne.Defs import Mathlib.Algebra.Group.WithOne.Units import Mathlib.Algebra.GroupPower.Basic import Mathlib.Algebra.GroupPower.CovariantClass +import Mathlib.Algebra.GroupPower.Hom import Mathlib.Algebra.GroupPower.Identities import Mathlib.Algebra.GroupPower.IterateHom import Mathlib.Algebra.GroupPower.Lemmas diff --git a/Mathlib/Algebra/Divisibility/Basic.lean b/Mathlib/Algebra/Divisibility/Basic.lean index ffe42c16e9afa..c9b1c2bd497b1 100644 --- a/Mathlib/Algebra/Divisibility/Basic.lean +++ b/Mathlib/Algebra/Divisibility/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Amelia Livingston, Yury Kudryashov, Neil Strickland, Aaron Anderson -/ -import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.GroupPower.Basic import Mathlib.Algebra.Group.Hom.Defs #align_import algebra.divisibility.basic from "leanprover-community/mathlib"@"e8638a0fcaf73e4500469f368ef9494e495099b3" @@ -115,8 +115,7 @@ end map_dvd end Semigroup section Monoid - -variable [Monoid α] {a b : α} +variable [Monoid α] {a b : α} {m n : ℕ} @[refl, simp] theorem dvd_refl (a : α) : a ∣ a := @@ -139,6 +138,20 @@ theorem dvd_of_eq (h : a = b) : a ∣ b := by rw [h] alias Eq.dvd := dvd_of_eq #align eq.dvd Eq.dvd +lemma pow_dvd_pow (a : α) (h : m ≤ n) : a ^ m ∣ a ^ n := + ⟨a ^ (n - m), by rw [← pow_add, Nat.add_comm, Nat.sub_add_cancel h]⟩ +#align pow_dvd_pow pow_dvd_pow + +lemma dvd_pow (hab : a ∣ b) : ∀ {n : ℕ} (_ : n ≠ 0), a ∣ b ^ n + | 0, hn => (hn rfl).elim + | n + 1, _ => by rw [pow_succ]; exact hab.mul_right _ +#align dvd_pow dvd_pow + +alias Dvd.dvd.pow := dvd_pow + +lemma dvd_pow_self (a : α) {n : ℕ} (hn : n ≠ 0) : a ∣ a ^ n := dvd_rfl.pow hn +#align dvd_pow_self dvd_pow_self + end Monoid section CommSemigroup diff --git a/Mathlib/Algebra/FreeMonoid/Basic.lean b/Mathlib/Algebra/FreeMonoid/Basic.lean index 7a3dc6acda31e..c6f9728026773 100644 --- a/Mathlib/Algebra/FreeMonoid/Basic.lean +++ b/Mathlib/Algebra/FreeMonoid/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, Yury Kudryashov -/ import Mathlib.Data.List.BigOperators.Basic +import Mathlib.GroupTheory.GroupAction.Defs #align_import algebra.free_monoid.basic from "leanprover-community/mathlib"@"657df4339ae6ceada048c8a2980fb10e393143ec" diff --git a/Mathlib/Algebra/GroupPower/Basic.lean b/Mathlib/Algebra/GroupPower/Basic.lean index 75eb3a4b5a381..7987521fafe72 100644 --- a/Mathlib/Algebra/GroupPower/Basic.lean +++ b/Mathlib/Algebra/GroupPower/Basic.lean @@ -3,9 +3,9 @@ Copyright (c) 2015 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Robert Y. Lewis -/ -import Mathlib.Algebra.Divisibility.Basic import Mathlib.Algebra.Group.Commute.Units -import Mathlib.Algebra.Group.TypeTags +import Mathlib.Algebra.GroupWithZero.Defs +import Mathlib.Tactic.Convert #align_import algebra.group_power.basic from "leanprover-community/mathlib"@"9b2660e1b25419042c8da10bf411aa3c67f14383" @@ -230,19 +230,6 @@ theorem pow_mul_pow_eq_one {a b : M} (n : ℕ) (h : a * b = 1) : a ^ n * b ^ n = #align pow_mul_pow_eq_one pow_mul_pow_eq_one #align nsmul_add_nsmul_eq_zero nsmul_add_nsmul_eq_zero -theorem dvd_pow {x y : M} (hxy : x ∣ y) : ∀ {n : ℕ} (_ : n ≠ 0), x ∣ y ^ n - | 0, hn => (hn rfl).elim - | n + 1, _ => by - rw [pow_succ] - exact hxy.mul_right _ -#align dvd_pow dvd_pow - -alias Dvd.dvd.pow := dvd_pow - -theorem dvd_pow_self (a : M) {n : ℕ} (hn : n ≠ 0) : a ∣ a ^ n := - dvd_rfl.pow hn -#align dvd_pow_self dvd_pow_self - end Monoid lemma eq_zero_or_one_of_sq_eq_self [CancelMonoidWithZero M] {x : M} (hx : x ^ 2 = x) : @@ -254,8 +241,7 @@ lemma eq_zero_or_one_of_sq_eq_self [CancelMonoidWithZero M] {x : M} (hx : x ^ 2 -/ section CommMonoid - -variable [CommMonoid M] [AddCommMonoid A] +variable [CommMonoid M] @[to_additive nsmul_add] theorem mul_pow (a b : M) (n : ℕ) : (a * b) ^ n = a ^ n * b ^ n := @@ -263,20 +249,6 @@ theorem mul_pow (a b : M) (n : ℕ) : (a * b) ^ n = a ^ n * b ^ n := #align mul_pow mul_pow #align nsmul_add nsmul_add -/-- The `n`th power map on a commutative monoid for a natural `n`, considered as a morphism of -monoids. -/ -@[to_additive (attr := simps) - "Multiplication by a natural `n` on a commutative additive - monoid, considered as a morphism of additive monoids."] -def powMonoidHom (n : ℕ) : M →* M where - toFun := (· ^ n) - map_one' := one_pow _ - map_mul' a b := mul_pow a b n -#align pow_monoid_hom powMonoidHom -#align nsmul_add_monoid_hom nsmulAddMonoidHom -#align pow_monoid_hom_apply powMonoidHom_apply -#align nsmul_add_monoid_hom_apply nsmulAddMonoidHom_apply - end CommMonoid section DivInvMonoid @@ -403,20 +375,6 @@ theorem div_zpow (a b : α) (n : ℤ) : (a / b) ^ n = a ^ n / b ^ n := by #align div_zpow div_zpow #align zsmul_sub zsmul_sub -/-- The `n`-th power map (for an integer `n`) on a commutative group, considered as a group -homomorphism. -/ -@[to_additive (attr := simps) - "Multiplication by an integer `n` on a commutative additive group, considered as an - additive group homomorphism."] -def zpowGroupHom (n : ℤ) : α →* α where - toFun := (· ^ n) - map_one' := one_zpow n - map_mul' a b := mul_zpow a b n -#align zpow_group_hom zpowGroupHom -#align zsmul_add_group_hom zsmulAddGroupHom -#align zpow_group_hom_apply zpowGroupHom_apply -#align zsmul_add_group_hom_apply zsmulAddGroupHom_apply - end DivisionCommMonoid section Group @@ -443,10 +401,6 @@ theorem inv_pow_sub (a : G) {m n : ℕ} (h : n ≤ m) : a⁻¹ ^ (m - n) = (a ^ end Group -theorem pow_dvd_pow [Monoid R] (a : R) {m n : ℕ} (h : m ≤ n) : a ^ m ∣ a ^ n := - ⟨a ^ (n - m), by rw [← pow_add, Nat.add_comm, Nat.sub_add_cancel h]⟩ -#align pow_dvd_pow pow_dvd_pow - @[to_additive (attr := simp)] theorem SemiconjBy.zpow_right [Group G] {a x y : G} (h : SemiconjBy a x y) : ∀ m : ℤ, SemiconjBy a (x ^ m) (y ^ m) diff --git a/Mathlib/Algebra/GroupPower/Hom.lean b/Mathlib/Algebra/GroupPower/Hom.lean new file mode 100644 index 0000000000000..59343e937d54e --- /dev/null +++ b/Mathlib/Algebra/GroupPower/Hom.lean @@ -0,0 +1,49 @@ +/- +Copyright (c) 2021 Kevin Buzzard. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kevin Buzzard +-/ +import Mathlib.Algebra.GroupPower.Basic +import Mathlib.Algebra.Group.Hom.Defs + +/-! +# Power as a monoid hom +-/ + +variable {α : Type*} + +section CommMonoid +variable [CommMonoid α] + +/-- The `n`th power map on a commutative monoid for a natural `n`, considered as a morphism of +monoids. -/ +@[to_additive (attr := simps) "Multiplication by a natural `n` on a commutative additive monoid, +considered as a morphism of additive monoids."] +def powMonoidHom (n : ℕ) : α →* α where + toFun := (· ^ n) + map_one' := one_pow _ + map_mul' a b := mul_pow a b n +#align pow_monoid_hom powMonoidHom +#align nsmul_add_monoid_hom nsmulAddMonoidHom +#align pow_monoid_hom_apply powMonoidHom_apply +#align nsmul_add_monoid_hom_apply nsmulAddMonoidHom_apply + +end CommMonoid + +section DivisionCommMonoid +variable [DivisionCommMonoid α] + +/-- The `n`-th power map (for an integer `n`) on a commutative group, considered as a group +homomorphism. -/ +@[to_additive (attr := simps) "Multiplication by an integer `n` on a commutative additive group, +considered as an additive group homomorphism."] +def zpowGroupHom (n : ℤ) : α →* α where + toFun := (· ^ n) + map_one' := one_zpow n + map_mul' a b := mul_zpow a b n +#align zpow_group_hom zpowGroupHom +#align zsmul_add_group_hom zsmulAddGroupHom +#align zpow_group_hom_apply zpowGroupHom_apply +#align zsmul_add_group_hom_apply zsmulAddGroupHom_apply + +end DivisionCommMonoid diff --git a/Mathlib/Algebra/GroupPower/Order.lean b/Mathlib/Algebra/GroupPower/Order.lean index cc7b451a04e82..5e89df4fa0631 100644 --- a/Mathlib/Algebra/GroupPower/Order.lean +++ b/Mathlib/Algebra/GroupPower/Order.lean @@ -167,9 +167,7 @@ theorem pow_lt_self_of_lt_one (h₀ : 0 < a) (h₁ : a < 1) (hn : 1 < n) : a ^ n simpa only [pow_one] using pow_lt_pow_right_of_lt_one h₀ h₁ hn #align pow_lt_self_of_lt_one pow_lt_self_of_lt_one -theorem sq_pos_of_pos (ha : 0 < a) : 0 < a ^ 2 := by - rw [sq] - exact mul_pos ha ha +theorem sq_pos_of_pos (ha : 0 < a) : 0 < a ^ 2 := pow_pos ha _ #align sq_pos_of_pos sq_pos_of_pos end StrictOrderedSemiring @@ -297,10 +295,6 @@ theorem pow_bit0_nonneg (a : R) (n : ℕ) : 0 ≤ a ^ bit0 n := by exact mul_self_nonneg _ #align pow_bit0_nonneg pow_bit0_nonneg -theorem sq_nonneg (a : R) : 0 ≤ a ^ 2 := - pow_bit0_nonneg a 1 -#align sq_nonneg sq_nonneg - alias pow_two_nonneg := sq_nonneg #align pow_two_nonneg pow_two_nonneg @@ -402,20 +396,6 @@ theorem pow_four_le_pow_two_of_pow_two_le {x y : R} (h : x ^ 2 ≤ y) : x ^ 4 end LinearOrderedRing -section LinearOrderedCommRing - -variable [LinearOrderedCommRing R] - -/-- Arithmetic mean-geometric mean (AM-GM) inequality for linearly ordered commutative rings. -/ -theorem two_mul_le_add_sq (a b : R) : 2 * a * b ≤ a ^ 2 + b ^ 2 := - sub_nonneg.mp ((sub_add_eq_add_sub _ _ _).subst ((sub_sq a b).subst (sq_nonneg _))) -#align two_mul_le_add_sq two_mul_le_add_sq - -alias two_mul_le_add_pow_two := two_mul_le_add_sq -#align two_mul_le_add_pow_two two_mul_le_add_pow_two - -end LinearOrderedCommRing - section LinearOrderedCommMonoidWithZero variable [LinearOrderedCommMonoidWithZero M] [NoZeroDivisors M] {a : M} {n : ℕ} diff --git a/Mathlib/Algebra/GroupPower/Ring.lean b/Mathlib/Algebra/GroupPower/Ring.lean index 35544e30212c3..df006e0e8f526 100644 --- a/Mathlib/Algebra/GroupPower/Ring.lean +++ b/Mathlib/Algebra/GroupPower/Ring.lean @@ -5,7 +5,7 @@ Authors: Jeremy Avigad, Robert Y. Lewis -/ import Mathlib.Algebra.Group.Units.Hom -import Mathlib.Algebra.GroupPower.Basic +import Mathlib.Algebra.GroupPower.Hom import Mathlib.Algebra.GroupWithZero.Commute import Mathlib.Algebra.GroupWithZero.Divisibility import Mathlib.Algebra.Ring.Commute diff --git a/Mathlib/Algebra/Order/Monoid/MinMax.lean b/Mathlib/Algebra/Order/Monoid/MinMax.lean index 471ad32b95c74..7deead61e0f12 100644 --- a/Mathlib/Algebra/Order/Monoid/MinMax.lean +++ b/Mathlib/Algebra/Order/Monoid/MinMax.lean @@ -20,20 +20,29 @@ variable {α β : Type*} /-! Some lemmas about types that have an ordering and a binary operation, with no rules relating them. -/ +section CommSemigroup +variable[LinearOrder α] [CommSemigroup α] [CommSemigroup β] @[to_additive] -theorem fn_min_mul_fn_max [LinearOrder α] [CommSemigroup β] (f : α → β) (n m : α) : - f (min n m) * f (max n m) = f n * f m := by - rcases le_total n m with h | h <;> simp [h, mul_comm] +lemma fn_min_mul_fn_max (f : α → β) (a b : α) : f (min a b) * f (max a b) = f a * f b := by + obtain h | h := le_total a b <;> simp [h, mul_comm] #align fn_min_mul_fn_max fn_min_mul_fn_max #align fn_min_add_fn_max fn_min_add_fn_max @[to_additive] -theorem min_mul_max [LinearOrder α] [CommSemigroup α] (n m : α) : min n m * max n m = n * m := - fn_min_mul_fn_max id n m +lemma fn_max_mul_fn_min (f : α → β) (a b : α) : f (max a b) * f (min a b) = f a * f b := by + obtain h | h := le_total a b <;> simp [h, mul_comm] + +@[to_additive (attr := simp)] +lemma min_mul_max (a b : α) : min a b * max a b = a * b := fn_min_mul_fn_max id _ _ #align min_mul_max min_mul_max #align min_add_max min_add_max +@[to_additive (attr := simp)] +lemma max_mul_min (a b : α) : max a b * min a b = a * b := fn_max_mul_fn_min id _ _ + +end CommSemigroup + section CovariantClassMulLe variable [LinearOrder α] diff --git a/Mathlib/Algebra/Order/Ring/Canonical.lean b/Mathlib/Algebra/Order/Ring/Canonical.lean index 923c86569fc58..7c0e976d0189f 100644 --- a/Mathlib/Algebra/Order/Ring/Canonical.lean +++ b/Mathlib/Algebra/Order/Ring/Canonical.lean @@ -5,7 +5,6 @@ Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro -/ import Mathlib.Algebra.Order.Ring.Defs import Mathlib.Algebra.Order.Sub.Canonical -import Mathlib.GroupTheory.GroupAction.Defs #align_import algebra.order.ring.canonical from "leanprover-community/mathlib"@"824f9ae93a4f5174d2ea948e2d75843dd83447bb" @@ -39,64 +38,6 @@ class CanonicallyOrderedCommSemiring (α : Type*) extends CanonicallyOrderedAddC protected eq_zero_or_eq_zero_of_mul_eq_zero : ∀ {a b : α}, a * b = 0 → a = 0 ∨ b = 0 #align canonically_ordered_comm_semiring CanonicallyOrderedCommSemiring -section StrictOrderedSemiring - -variable [StrictOrderedSemiring α] {a b c d : α} - -section ExistsAddOfLE - -variable [ExistsAddOfLE α] - -/-- Binary **rearrangement inequality**. -/ -theorem mul_add_mul_le_mul_add_mul (hab : a ≤ b) (hcd : c ≤ d) : a * d + b * c ≤ a * c + b * d := by - obtain ⟨b, rfl⟩ := exists_add_of_le hab - obtain ⟨d, rfl⟩ := exists_add_of_le hcd - rw [mul_add, add_right_comm, mul_add, ← add_assoc] - exact add_le_add_left (mul_le_mul_of_nonneg_right hab <| (le_add_iff_nonneg_right _).1 hcd) _ -#align mul_add_mul_le_mul_add_mul mul_add_mul_le_mul_add_mul - -/-- Binary **rearrangement inequality**. -/ -theorem mul_add_mul_le_mul_add_mul' (hba : b ≤ a) (hdc : d ≤ c) : - a • d + b • c ≤ a • c + b • d := by - rw [add_comm (a • d), add_comm (a • c)] - exact mul_add_mul_le_mul_add_mul hba hdc -#align mul_add_mul_le_mul_add_mul' mul_add_mul_le_mul_add_mul' - -/-- Binary strict **rearrangement inequality**. -/ -theorem mul_add_mul_lt_mul_add_mul (hab : a < b) (hcd : c < d) : a * d + b * c < a * c + b * d := by - obtain ⟨b, rfl⟩ := exists_add_of_le hab.le - obtain ⟨d, rfl⟩ := exists_add_of_le hcd.le - rw [mul_add, add_right_comm, mul_add, ← add_assoc] - exact add_lt_add_left (mul_lt_mul_of_pos_right hab <| (lt_add_iff_pos_right _).1 hcd) _ -#align mul_add_mul_lt_mul_add_mul mul_add_mul_lt_mul_add_mul - -/-- Binary **rearrangement inequality**. -/ -theorem mul_add_mul_lt_mul_add_mul' (hba : b < a) (hdc : d < c) : - a • d + b • c < a • c + b • d := by - rw [add_comm (a • d), add_comm (a • c)] - exact mul_add_mul_lt_mul_add_mul hba hdc -#align mul_add_mul_lt_mul_add_mul' mul_add_mul_lt_mul_add_mul' - -end ExistsAddOfLE - -end StrictOrderedSemiring - -section LinearOrderedCommSemiring -variable [LinearOrderedCommSemiring α] [ExistsAddOfLE α] {a b : α} - -lemma add_sq_le : (a + b) ^ 2 ≤ 2 * (a ^ 2 + b ^ 2) := by - calc - (a + b) ^ 2 = a ^ 2 + b ^ 2 + (a * b + b * a) := by - simp_rw [pow_succ, pow_zero, mul_one, add_mul_self_eq, mul_assoc, two_mul, - add_right_comm _ (_ + _), mul_comm] - _ ≤ a ^ 2 + b ^ 2 + (a * a + b * b) := add_le_add_left ?_ _ - _ = _ := by simp_rw [pow_succ, pow_zero, mul_one, two_mul] - cases le_total a b - · exact mul_add_mul_le_mul_add_mul ‹_› ‹_› - · exact mul_add_mul_le_mul_add_mul' ‹_› ‹_› - -end LinearOrderedCommSemiring - namespace CanonicallyOrderedCommSemiring variable [CanonicallyOrderedCommSemiring α] {a b c d : α} diff --git a/Mathlib/Algebra/Order/Ring/Defs.lean b/Mathlib/Algebra/Order/Ring/Defs.lean index 0281527fcfa1e..3835425993a34 100644 --- a/Mathlib/Algebra/Order/Ring/Defs.lean +++ b/Mathlib/Algebra/Order/Ring/Defs.lean @@ -4,16 +4,16 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Yaël Dillies -/ import Mathlib.Algebra.Group.Units +import Mathlib.Algebra.GroupPower.Basic import Mathlib.Algebra.GroupWithZero.NeZero import Mathlib.Algebra.Order.Group.Defs -import Mathlib.Algebra.Order.Monoid.Defs import Mathlib.Algebra.Order.Monoid.Canonical.Defs +import Mathlib.Algebra.Order.Monoid.MinMax import Mathlib.Algebra.Order.Monoid.NatCast import Mathlib.Algebra.Order.Monoid.WithZero.Defs import Mathlib.Algebra.Order.Ring.Lemmas -import Mathlib.Algebra.Ring.Defs import Mathlib.Data.Pi.Algebra -import Mathlib.Order.MinMax +import Mathlib.Tactic.ByContra import Mathlib.Tactic.Nontriviality import Mathlib.Tactic.Tauto @@ -333,27 +333,24 @@ theorem mul_lt_one_of_nonneg_of_lt_one_right (ha : a ≤ 1) (hb₀ : 0 ≤ b) (h (mul_le_of_le_one_left hb₀ ha).trans_lt hb #align mul_lt_one_of_nonneg_of_lt_one_right mul_lt_one_of_nonneg_of_lt_one_right -end OrderedSemiring - -section OrderedRing - -variable [OrderedRing α] {a b c d : α} - --- see Note [lower instance priority] -instance (priority := 100) OrderedRing.toOrderedSemiring : OrderedSemiring α := - { ‹OrderedRing α›, (Ring.toSemiring : Semiring α) with - mul_le_mul_of_nonneg_left := fun a b c h hc => by - simpa only [mul_sub, sub_nonneg] using OrderedRing.mul_nonneg _ _ hc (sub_nonneg.2 h), - mul_le_mul_of_nonneg_right := fun a b c h hc => by - simpa only [sub_mul, sub_nonneg] using OrderedRing.mul_nonneg _ _ (sub_nonneg.2 h) hc } -#align ordered_ring.to_ordered_semiring OrderedRing.toOrderedSemiring +variable [ExistsAddOfLE α] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] theorem mul_le_mul_of_nonpos_left (h : b ≤ a) (hc : c ≤ 0) : c * a ≤ c * b := by - simpa only [neg_mul, neg_le_neg_iff] using mul_le_mul_of_nonneg_left h (neg_nonneg.2 hc) + obtain ⟨d, hcd⟩ := exists_add_of_le hc + refine le_of_add_le_add_right (a := d * b + d * a) ?_ + calc + _ = d * b := by rw [add_left_comm, ← add_mul, ← hcd, zero_mul, add_zero] + _ ≤ d * a := mul_le_mul_of_nonneg_left h $ hcd.trans_le $ add_le_of_nonpos_left hc + _ = _ := by rw [← add_assoc, ← add_mul, ← hcd, zero_mul, zero_add] #align mul_le_mul_of_nonpos_left mul_le_mul_of_nonpos_left theorem mul_le_mul_of_nonpos_right (h : b ≤ a) (hc : c ≤ 0) : a * c ≤ b * c := by - simpa only [mul_neg, neg_le_neg_iff] using mul_le_mul_of_nonneg_right h (neg_nonneg.2 hc) + obtain ⟨d, hcd⟩ := exists_add_of_le hc + refine le_of_add_le_add_right (a := b * d + a * d) ?_ + calc + _ = b * d := by rw [add_left_comm, ← mul_add, ← hcd, mul_zero, add_zero] + _ ≤ a * d := mul_le_mul_of_nonneg_right h $ hcd.trans_le $ add_le_of_nonpos_left hc + _ = _ := by rw [← add_assoc, ← mul_add, ← hcd, mul_zero, zero_add] #align mul_le_mul_of_nonpos_right mul_le_mul_of_nonpos_right theorem mul_nonneg_of_nonpos_of_nonpos (ha : a ≤ 0) (hb : b ≤ 0) : 0 ≤ a * b := by @@ -454,12 +451,31 @@ theorem Antitone.mul (hf : Antitone f) (hg : Antitone g) (hf₀ : ∀ x, f x ≤ end Monotone -theorem le_iff_exists_nonneg_add (a b : α) : a ≤ b ↔ ∃ c ≥ 0, b = a + c := - ⟨fun h => ⟨b - a, sub_nonneg.mpr h, by simp⟩, fun ⟨c, hc, h⟩ => by - rw [h, le_add_iff_nonneg_right] - exact hc⟩ +variable [ContravariantClass α α (· + ·) (· ≤ ·)] + +lemma le_iff_exists_nonneg_add (a b : α) : a ≤ b ↔ ∃ c ≥ 0, b = a + c := by + refine ⟨fun h ↦ ?_, ?_⟩ + · obtain ⟨c, rfl⟩ := exists_add_of_le h + exact ⟨c, nonneg_of_le_add_right h, rfl⟩ + · rintro ⟨c, hc, rfl⟩ + exact le_add_of_nonneg_right hc #align le_iff_exists_nonneg_add le_iff_exists_nonneg_add +end OrderedSemiring + +section OrderedRing + +variable [OrderedRing α] {a b c d : α} + +-- see Note [lower instance priority] +instance (priority := 100) OrderedRing.toOrderedSemiring : OrderedSemiring α := + { ‹OrderedRing α›, (Ring.toSemiring : Semiring α) with + mul_le_mul_of_nonneg_left := fun a b c h hc => by + simpa only [mul_sub, sub_nonneg] using OrderedRing.mul_nonneg _ _ hc (sub_nonneg.2 h), + mul_le_mul_of_nonneg_right := fun a b c h hc => by + simpa only [sub_mul, sub_nonneg] using OrderedRing.mul_nonneg _ _ (sub_nonneg.2 h) hc } +#align ordered_ring.to_ordered_semiring OrderedRing.toOrderedSemiring + end OrderedRing section OrderedCommRing @@ -628,71 +644,24 @@ instance (priority := 100) StrictOrderedSemiring.toNoMaxOrder : NoMaxOrder α := ⟨fun a => ⟨a + 1, lt_add_of_pos_right _ one_pos⟩⟩ #align strict_ordered_semiring.to_no_max_order StrictOrderedSemiring.toNoMaxOrder -end StrictOrderedSemiring - -section StrictOrderedCommSemiring - -variable [StrictOrderedCommSemiring α] - --- See note [reducible non-instances] -/-- A choice-free version of `StrictOrderedCommSemiring.toOrderedCommSemiring'` to avoid using -choice in basic `Nat` lemmas. -/ -@[reducible] -def StrictOrderedCommSemiring.toOrderedCommSemiring' [@DecidableRel α (· ≤ ·)] : - OrderedCommSemiring α := - { ‹StrictOrderedCommSemiring α›, StrictOrderedSemiring.toOrderedSemiring' with } -#align strict_ordered_comm_semiring.to_ordered_comm_semiring' StrictOrderedCommSemiring.toOrderedCommSemiring' - --- see Note [lower instance priority] -instance (priority := 100) StrictOrderedCommSemiring.toOrderedCommSemiring : - OrderedCommSemiring α := - { ‹StrictOrderedCommSemiring α›, StrictOrderedSemiring.toOrderedSemiring with } -#align strict_ordered_comm_semiring.to_ordered_comm_semiring StrictOrderedCommSemiring.toOrderedCommSemiring - -end StrictOrderedCommSemiring - -section StrictOrderedRing - -variable [StrictOrderedRing α] {a b c : α} - --- see Note [lower instance priority] -instance (priority := 100) StrictOrderedRing.toStrictOrderedSemiring : StrictOrderedSemiring α := - { ‹StrictOrderedRing α›, (Ring.toSemiring : Semiring α) with - le_of_add_le_add_left := @le_of_add_le_add_left α _ _ _, - mul_lt_mul_of_pos_left := fun a b c h hc => by - simpa only [mul_sub, sub_pos] using StrictOrderedRing.mul_pos _ _ hc (sub_pos.2 h), - mul_lt_mul_of_pos_right := fun a b c h hc => by - simpa only [sub_mul, sub_pos] using StrictOrderedRing.mul_pos _ _ (sub_pos.2 h) hc } -#align strict_ordered_ring.to_strict_ordered_semiring StrictOrderedRing.toStrictOrderedSemiring - --- See note [reducible non-instances] -/-- A choice-free version of `StrictOrderedRing.toOrderedRing` to avoid using choice in basic -`Int` lemmas. -/ -@[reducible] -def StrictOrderedRing.toOrderedRing' [@DecidableRel α (· ≤ ·)] : OrderedRing α := - { ‹StrictOrderedRing α›, (Ring.toSemiring : Semiring α) with - mul_nonneg := fun a b ha hb => by - obtain ha | ha := Decidable.eq_or_lt_of_le ha - · rw [← ha, zero_mul] - obtain hb | hb := Decidable.eq_or_lt_of_le hb - · rw [← hb, mul_zero] - · exact (StrictOrderedRing.mul_pos _ _ ha hb).le } -#align strict_ordered_ring.to_ordered_ring' StrictOrderedRing.toOrderedRing' - --- see Note [lower instance priority] -instance (priority := 100) StrictOrderedRing.toOrderedRing : OrderedRing α := - { ‹StrictOrderedRing α› with - mul_nonneg := fun a b => - letI := @StrictOrderedRing.toOrderedRing' α _ (Classical.decRel _) - mul_nonneg } -#align strict_ordered_ring.to_ordered_ring StrictOrderedRing.toOrderedRing +variable [ExistsAddOfLE α] theorem mul_lt_mul_of_neg_left (h : b < a) (hc : c < 0) : c * a < c * b := by - simpa only [neg_mul, neg_lt_neg_iff] using mul_lt_mul_of_pos_left h (neg_pos_of_neg hc) + obtain ⟨d, hcd⟩ := exists_add_of_le hc.le + refine (add_lt_add_iff_right (d * b + d * a)).1 ?_ + calc + _ = d * b := by rw [add_left_comm, ← add_mul, ← hcd, zero_mul, add_zero] + _ < d * a := mul_lt_mul_of_pos_left h $ hcd.trans_lt $ add_lt_of_neg_left _ hc + _ = _ := by rw [← add_assoc, ← add_mul, ← hcd, zero_mul, zero_add] #align mul_lt_mul_of_neg_left mul_lt_mul_of_neg_left theorem mul_lt_mul_of_neg_right (h : b < a) (hc : c < 0) : a * c < b * c := by - simpa only [mul_neg, neg_lt_neg_iff] using mul_lt_mul_of_pos_right h (neg_pos_of_neg hc) + obtain ⟨d, hcd⟩ := exists_add_of_le hc.le + refine (add_lt_add_iff_right (b * d + a * d)).1 ?_ + calc + _ = b * d := by rw [add_left_comm, ← mul_add, ← hcd, mul_zero, add_zero] + _ < a * d := mul_lt_mul_of_pos_right h $ hcd.trans_lt $ add_lt_of_neg_left _ hc + _ = _ := by rw [← add_assoc, ← mul_add, ← hcd, mul_zero, zero_add] #align mul_lt_mul_of_neg_right mul_lt_mul_of_neg_right theorem mul_pos_of_neg_of_neg {a b : α} (ha : a < 0) (hb : b < 0) : 0 < a * b := by @@ -753,6 +722,90 @@ theorem StrictAnti.mul_const_of_neg (hf : StrictAnti f) (ha : a < 0) : end Monotone +/-- Binary **rearrangement inequality**. -/ +lemma mul_add_mul_le_mul_add_mul (hab : a ≤ b) (hcd : c ≤ d) : a * d + b * c ≤ a * c + b * d := by + obtain ⟨b, rfl⟩ := exists_add_of_le hab + obtain ⟨d, rfl⟩ := exists_add_of_le hcd + rw [mul_add, add_right_comm, mul_add, ← add_assoc] + exact add_le_add_left (mul_le_mul_of_nonneg_right hab <| (le_add_iff_nonneg_right _).1 hcd) _ +#align mul_add_mul_le_mul_add_mul mul_add_mul_le_mul_add_mul + +/-- Binary **rearrangement inequality**. -/ +lemma mul_add_mul_le_mul_add_mul' (hba : b ≤ a) (hdc : d ≤ c) : a * d + b * c ≤ a * c + b * d := by + rw [add_comm (a * d), add_comm (a * c)]; exact mul_add_mul_le_mul_add_mul hba hdc +#align mul_add_mul_le_mul_add_mul' mul_add_mul_le_mul_add_mul' + +/-- Binary strict **rearrangement inequality**. -/ +lemma mul_add_mul_lt_mul_add_mul (hab : a < b) (hcd : c < d) : a * d + b * c < a * c + b * d := by + obtain ⟨b, rfl⟩ := exists_add_of_le hab.le + obtain ⟨d, rfl⟩ := exists_add_of_le hcd.le + rw [mul_add, add_right_comm, mul_add, ← add_assoc] + exact add_lt_add_left (mul_lt_mul_of_pos_right hab <| (lt_add_iff_pos_right _).1 hcd) _ +#align mul_add_mul_lt_mul_add_mul mul_add_mul_lt_mul_add_mul + +/-- Binary **rearrangement inequality**. -/ +lemma mul_add_mul_lt_mul_add_mul' (hba : b < a) (hdc : d < c) : a * d + b * c < a * c + b * d := by + rw [add_comm (a * d), add_comm (a * c)] + exact mul_add_mul_lt_mul_add_mul hba hdc +#align mul_add_mul_lt_mul_add_mul' mul_add_mul_lt_mul_add_mul' + +end StrictOrderedSemiring + +section StrictOrderedCommSemiring +variable [StrictOrderedCommSemiring α] + +-- See note [reducible non-instances] +/-- A choice-free version of `StrictOrderedCommSemiring.toOrderedCommSemiring'` to avoid using +choice in basic `Nat` lemmas. -/ +@[reducible] +def StrictOrderedCommSemiring.toOrderedCommSemiring' [@DecidableRel α (· ≤ ·)] : + OrderedCommSemiring α := + { ‹StrictOrderedCommSemiring α›, StrictOrderedSemiring.toOrderedSemiring' with } +#align strict_ordered_comm_semiring.to_ordered_comm_semiring' StrictOrderedCommSemiring.toOrderedCommSemiring' + +-- see Note [lower instance priority] +instance (priority := 100) StrictOrderedCommSemiring.toOrderedCommSemiring : + OrderedCommSemiring α := + { ‹StrictOrderedCommSemiring α›, StrictOrderedSemiring.toOrderedSemiring with } +#align strict_ordered_comm_semiring.to_ordered_comm_semiring StrictOrderedCommSemiring.toOrderedCommSemiring + +end StrictOrderedCommSemiring + +section StrictOrderedRing +variable [StrictOrderedRing α] {a b c : α} + +-- see Note [lower instance priority] +instance (priority := 100) StrictOrderedRing.toStrictOrderedSemiring : StrictOrderedSemiring α := + { ‹StrictOrderedRing α›, (Ring.toSemiring : Semiring α) with + le_of_add_le_add_left := @le_of_add_le_add_left α _ _ _, + mul_lt_mul_of_pos_left := fun a b c h hc => by + simpa only [mul_sub, sub_pos] using StrictOrderedRing.mul_pos _ _ hc (sub_pos.2 h), + mul_lt_mul_of_pos_right := fun a b c h hc => by + simpa only [sub_mul, sub_pos] using StrictOrderedRing.mul_pos _ _ (sub_pos.2 h) hc } +#align strict_ordered_ring.to_strict_ordered_semiring StrictOrderedRing.toStrictOrderedSemiring + +-- See note [reducible non-instances] +/-- A choice-free version of `StrictOrderedRing.toOrderedRing` to avoid using choice in basic +`Int` lemmas. -/ +@[reducible] +def StrictOrderedRing.toOrderedRing' [@DecidableRel α (· ≤ ·)] : OrderedRing α := + { ‹StrictOrderedRing α›, (Ring.toSemiring : Semiring α) with + mul_nonneg := fun a b ha hb => by + obtain ha | ha := Decidable.eq_or_lt_of_le ha + · rw [← ha, zero_mul] + obtain hb | hb := Decidable.eq_or_lt_of_le hb + · rw [← hb, mul_zero] + · exact (StrictOrderedRing.mul_pos _ _ ha hb).le } +#align strict_ordered_ring.to_ordered_ring' StrictOrderedRing.toOrderedRing' + +-- see Note [lower instance priority] +instance (priority := 100) StrictOrderedRing.toOrderedRing : OrderedRing α := + { ‹StrictOrderedRing α› with + mul_nonneg := fun a b => + letI := @StrictOrderedRing.toOrderedRing' α _ (Classical.decRel _) + mul_nonneg } +#align strict_ordered_ring.to_ordered_ring StrictOrderedRing.toOrderedRing + end StrictOrderedRing section StrictOrderedCommRing @@ -995,52 +1048,26 @@ theorem mul_self_inj {a b : α} (h1 : 0 ≤ a) (h2 : 0 ≤ b) : a * a = b * b (@strictMonoOn_mul_self α _).eq_iff_eq h1 h2 #align mul_self_inj mul_self_inj -end LinearOrderedSemiring +variable [ExistsAddOfLE α] -- See note [lower instance priority] -instance (priority := 100) LinearOrderedCommSemiring.toLinearOrderedCancelAddCommMonoid - [LinearOrderedCommSemiring α] : LinearOrderedCancelAddCommMonoid α := - { ‹LinearOrderedCommSemiring α› with } -#align linear_ordered_comm_semiring.to_linear_ordered_cancel_add_comm_monoid LinearOrderedCommSemiring.toLinearOrderedCancelAddCommMonoid - -section LinearOrderedRing - -variable [LinearOrderedRing α] {a b c : α} - -attribute [local instance] LinearOrderedRing.decidableLE LinearOrderedRing.decidableLT - --- see Note [lower instance priority] -instance (priority := 100) LinearOrderedRing.toLinearOrderedSemiring : LinearOrderedSemiring α := - { ‹LinearOrderedRing α›, StrictOrderedRing.toStrictOrderedSemiring with } -#align linear_ordered_ring.to_linear_ordered_semiring LinearOrderedRing.toLinearOrderedSemiring - --- see Note [lower instance priority] -instance (priority := 100) LinearOrderedRing.toLinearOrderedAddCommGroup : - LinearOrderedAddCommGroup α := - { ‹LinearOrderedRing α› with } -#align linear_ordered_ring.to_linear_ordered_add_comm_group LinearOrderedRing.toLinearOrderedAddCommGroup - --- see Note [lower instance priority] -instance (priority := 100) LinearOrderedRing.noZeroDivisors : NoZeroDivisors α := - { ‹LinearOrderedRing α› with - eq_zero_or_eq_zero_of_mul_eq_zero := by - intro a b hab - refine' Decidable.or_iff_not_and_not.2 fun h => _; revert hab - cases' lt_or_gt_of_ne h.1 with ha ha <;> cases' lt_or_gt_of_ne h.2 with hb hb - exacts [(mul_pos_of_neg_of_neg ha hb).ne.symm, (mul_neg_of_neg_of_pos ha hb).ne, - (mul_neg_of_pos_of_neg ha hb).ne, (mul_pos ha hb).ne.symm] } -#align linear_ordered_ring.no_zero_divisors LinearOrderedRing.noZeroDivisors - --- see Note [lower instance priority] ---We don't want to import `Algebra.Ring.Basic`, so we cannot use `NoZeroDivisors.to_isDomain`. -instance (priority := 100) LinearOrderedRing.isDomain : IsDomain α := - { (inferInstance : Nontrivial α) with - mul_left_cancel_of_ne_zero := fun {a b c} ha h => by - rw [← sub_eq_zero, ← mul_sub] at h - exact sub_eq_zero.1 ((eq_zero_or_eq_zero_of_mul_eq_zero h).resolve_left ha), - mul_right_cancel_of_ne_zero := fun {a b c} hb h => by - rw [← sub_eq_zero, ← sub_mul] at h - exact sub_eq_zero.1 ((eq_zero_or_eq_zero_of_mul_eq_zero h).resolve_right hb) } +instance (priority := 100) LinearOrderedSemiring.noZeroDivisors : NoZeroDivisors α where + eq_zero_or_eq_zero_of_mul_eq_zero {a b} hab := by + contrapose! hab + obtain ha | ha := hab.1.lt_or_lt <;> obtain hb | hb := hab.2.lt_or_lt + exacts [(mul_pos_of_neg_of_neg ha hb).ne', (mul_neg_of_neg_of_pos ha hb).ne, + (mul_neg_of_pos_of_neg ha hb).ne, (mul_pos ha hb).ne'] +#align linear_ordered_ring.no_zero_divisors LinearOrderedSemiring.noZeroDivisors + +-- Note that we can't use `NoZeroDivisors.to_isDomain` since we are merely in a semiring. +-- See note [lower instance priority] +instance (priority := 100) LinearOrderedRing.isDomain : IsDomain α where + mul_left_cancel_of_ne_zero {a b c} ha h := by + obtain ha | ha := ha.lt_or_lt + exacts [(strictAnti_mul_left ha).injective h, (strictMono_mul_left_of_pos ha).injective h] + mul_right_cancel_of_ne_zero {b a c} ha h := by + obtain ha | ha := ha.lt_or_lt + exacts [(strictAnti_mul_right ha).injective h, (strictMono_mul_right_of_pos ha).injective h] #align linear_ordered_ring.is_domain LinearOrderedRing.isDomain theorem mul_pos_iff : 0 < a * b ↔ 0 < a ∧ 0 < b ∨ a < 0 ∧ b < 0 := @@ -1048,10 +1075,6 @@ theorem mul_pos_iff : 0 < a * b ↔ 0 < a ∧ 0 < b ∨ a < 0 ∧ b < 0 := h.elim (and_imp.2 mul_pos) (and_imp.2 mul_pos_of_neg_of_neg)⟩ #align mul_pos_iff mul_pos_iff -theorem mul_neg_iff : a * b < 0 ↔ 0 < a ∧ b < 0 ∨ a < 0 ∧ 0 < b := by - rw [← neg_pos, neg_mul_eq_mul_neg, mul_pos_iff, neg_pos, neg_lt_zero] -#align mul_neg_iff mul_neg_iff - theorem mul_nonneg_iff : 0 ≤ a * b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := ⟨nonneg_and_nonneg_or_nonpos_and_nonpos_of_mul_nonneg, fun h => h.elim (and_imp.2 mul_nonneg) (and_imp.2 mul_nonneg_of_nonpos_of_nonpos)⟩ @@ -1083,10 +1106,6 @@ theorem mul_nonneg_of_three (a b c : α) : 0 ≤ a * b ∨ 0 ≤ b * c ∨ 0 ≤ (fun (h6 : a ≤ 0) => Or.inl (Or.inr ⟨h6, h4⟩)))) #align mul_nonneg_of_three mul_nonneg_of_three -theorem mul_nonpos_iff : a * b ≤ 0 ↔ 0 ≤ a ∧ b ≤ 0 ∨ a ≤ 0 ∧ 0 ≤ b := by - rw [← neg_nonneg, neg_mul_eq_mul_neg, mul_nonneg_iff, neg_nonneg, neg_nonpos] -#align mul_nonpos_iff mul_nonpos_iff - lemma mul_nonneg_iff_pos_imp_nonneg : 0 ≤ a * b ↔ (0 < a → 0 ≤ b) ∧ (0 < b → 0 ≤ a) := by refine mul_nonneg_iff.trans ?_ simp_rw [← not_le, ← or_iff_not_imp_left] @@ -1094,23 +1113,6 @@ lemma mul_nonneg_iff_pos_imp_nonneg : 0 ≤ a * b ↔ (0 < a → 0 ≤ b) ∧ (0 have := le_total b 0 tauto -lemma mul_nonneg_iff_neg_imp_nonpos : 0 ≤ a * b ↔ (a < 0 → b ≤ 0) ∧ (b < 0 → a ≤ 0) := by - rw [← neg_mul_neg, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] - -lemma mul_nonpos_iff_pos_imp_nonpos : a * b ≤ 0 ↔ (0 < a → b ≤ 0) ∧ (b < 0 → 0 ≤ a) := by - rw [← neg_nonneg, ← mul_neg, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] - -lemma mul_nonpos_iff_neg_imp_nonneg : a * b ≤ 0 ↔ (a < 0 → 0 ≤ b) ∧ (0 < b → a ≤ 0) := by - rw [← neg_nonneg, ← neg_mul, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] - -theorem mul_self_nonneg (a : α) : 0 ≤ a * a := - (le_total 0 a).elim (fun h => mul_nonneg h h) fun h => mul_nonneg_of_nonpos_of_nonpos h h -#align mul_self_nonneg mul_self_nonneg - -theorem neg_one_lt_zero : -1 < (0 : α) := - neg_lt_zero.2 zero_lt_one -#align neg_one_lt_zero neg_one_lt_zero - @[simp] theorem mul_le_mul_left_of_neg {a b c : α} (h : c < 0) : c * a ≤ c * b ↔ b ≤ a := (strictAnti_mul_left h).le_iff_le @@ -1132,11 +1134,11 @@ theorem mul_lt_mul_right_of_neg {a b c : α} (h : c < 0) : a * c < b * c ↔ b < #align mul_lt_mul_right_of_neg mul_lt_mul_right_of_neg theorem lt_of_mul_lt_mul_of_nonpos_left (h : c * a < c * b) (hc : c ≤ 0) : b < a := - lt_of_mul_lt_mul_left (by rwa [neg_mul, neg_mul, neg_lt_neg_iff]) <| neg_nonneg.2 hc + (antitone_mul_left hc).reflect_lt h #align lt_of_mul_lt_mul_of_nonpos_left lt_of_mul_lt_mul_of_nonpos_left theorem lt_of_mul_lt_mul_of_nonpos_right (h : a * c < b * c) (hc : c ≤ 0) : b < a := - lt_of_mul_lt_mul_right (by rwa [mul_neg, mul_neg, neg_lt_neg_iff]) <| neg_nonneg.2 hc + (antitone_mul_right hc).reflect_lt h #align lt_of_mul_lt_mul_of_nonpos_right lt_of_mul_lt_mul_of_nonpos_right theorem cmp_mul_neg_left {a : α} (ha : a < 0) (b c : α) : cmp (a * b) (a * c) = cmp c b := @@ -1147,10 +1149,6 @@ theorem cmp_mul_neg_right {a : α} (ha : a < 0) (b c : α) : cmp (b * a) (c * a) (strictAnti_mul_right ha).cmp_map_eq b c #align cmp_mul_neg_right cmp_mul_neg_right -theorem sub_one_lt (a : α) : a - 1 < a := - sub_lt_iff_lt_add.2 (lt_add_one a) -#align sub_one_lt sub_one_lt - @[simp] theorem mul_self_pos {a : α} : 0 < a * a ↔ a ≠ 0 := by constructor @@ -1162,12 +1160,6 @@ theorem mul_self_pos {a : α} : 0 < a * a ↔ a ≠ 0 := by exacts [mul_pos_of_neg_of_neg h h, mul_pos h h] #align mul_self_pos mul_self_pos -theorem mul_self_le_mul_self_of_le_of_neg_le {x y : α} (h₁ : x ≤ y) (h₂ : -x ≤ y) : x * x ≤ y * y := - (le_total 0 x).elim (fun h => mul_le_mul h₁ h₁ h (h.trans h₁)) fun h => - le_of_eq_of_le (neg_mul_neg x x).symm - (mul_le_mul h₂ h₂ (neg_nonneg.mpr h) ((neg_nonneg.mpr h).trans h₂)) -#align mul_self_le_mul_self_of_le_of_neg_le mul_self_le_mul_self_of_le_of_neg_le - theorem nonneg_of_mul_nonpos_left {a b : α} (h : a * b ≤ 0) (hb : b < 0) : 0 ≤ a := le_of_not_gt fun ha => absurd h (mul_pos_of_neg_of_neg ha hb).not_le #align nonneg_of_mul_nonpos_left nonneg_of_mul_nonpos_left @@ -1192,15 +1184,118 @@ theorem pos_iff_neg_of_mul_neg (hab : a * b < 0) : 0 < a ↔ b < 0 := ⟨neg_of_mul_neg_right hab ∘ le_of_lt, pos_of_mul_neg_left hab ∘ le_of_lt⟩ #align pos_iff_neg_of_mul_neg pos_iff_neg_of_mul_neg +lemma sq_nonneg (a : α) : 0 ≤ a ^ 2 := by + obtain ha | ha := le_total 0 a + · exact pow_nonneg ha _ + obtain ⟨b, hab⟩ := exists_add_of_le ha + calc + 0 ≤ b ^ 2 := pow_nonneg (not_lt.1 fun hb ↦ hab.not_gt $ add_neg_of_nonpos_of_neg ha hb) _ + _ = a ^ 2 := add_left_injective (a * b) ?_ + calc + b ^ 2 + a * b = (a + b) * b := by rw [add_comm, sq, add_mul] + _ = a * (a + b) := by simp [← hab] + _ = a ^ 2 + a * b := by rw [sq, mul_add] + +lemma mul_self_nonneg (a : α) : 0 ≤ a * a := by simpa only [sq] using sq_nonneg a + /-- The sum of two squares is zero iff both elements are zero. -/ -theorem mul_self_add_mul_self_eq_zero {x y : α} : x * x + y * y = 0 ↔ x = 0 ∧ y = 0 := by +lemma mul_self_add_mul_self_eq_zero : a * a + b * b = 0 ↔ a = 0 ∧ b = 0 := by rw [add_eq_zero_iff', mul_self_eq_zero, mul_self_eq_zero] <;> apply mul_self_nonneg #align mul_self_add_mul_self_eq_zero mul_self_add_mul_self_eq_zero -theorem eq_zero_of_mul_self_add_mul_self_eq_zero (h : a * a + b * b = 0) : a = 0 := +lemma eq_zero_of_mul_self_add_mul_self_eq_zero (h : a * a + b * b = 0) : a = 0 := (mul_self_add_mul_self_eq_zero.mp h).left #align eq_zero_of_mul_self_add_mul_self_eq_zero eq_zero_of_mul_self_add_mul_self_eq_zero +lemma add_sq_le : (a + b) ^ 2 ≤ 2 * (a ^ 2 + b ^ 2) := by + calc + (a + b) ^ 2 = a ^ 2 + b ^ 2 + (a * b + b * a) := by + simp_rw [pow_succ, pow_zero, mul_one, add_mul, mul_add, add_comm (b * a), add_add_add_comm] + _ ≤ a ^ 2 + b ^ 2 + (a * a + b * b) := add_le_add_left ?_ _ + _ = _ := by simp_rw [pow_succ, pow_zero, mul_one, two_mul] + cases le_total a b + · exact mul_add_mul_le_mul_add_mul ‹_› ‹_› + · exact mul_add_mul_le_mul_add_mul' ‹_› ‹_› + +end LinearOrderedSemiring + +section LinearOrderedCommSemiring +variable [LinearOrderedCommSemiring α] {a b c d : α} + +-- See note [lower instance priority] +instance (priority := 100) LinearOrderedCommSemiring.toLinearOrderedCancelAddCommMonoid : + LinearOrderedCancelAddCommMonoid α where __ := ‹LinearOrderedCommSemiring α› +#align linear_ordered_comm_semiring.to_linear_ordered_cancel_add_comm_monoid LinearOrderedCommSemiring.toLinearOrderedCancelAddCommMonoid + +lemma max_mul_mul_le_max_mul_max (b c : α) (ha : 0 ≤ a) (hd : 0 ≤ d) : + max (a * b) (d * c) ≤ max a c * max d b := + have ba : b * a ≤ max d b * max c a := + mul_le_mul (le_max_right d b) (le_max_right c a) ha (le_trans hd (le_max_left d b)) + have cd : c * d ≤ max a c * max b d := + mul_le_mul (le_max_right a c) (le_max_right b d) hd (le_trans ha (le_max_left a c)) + max_le (by simpa [mul_comm, max_comm] using ba) (by simpa [mul_comm, max_comm] using cd) +#align max_mul_mul_le_max_mul_max max_mul_mul_le_max_mul_max + +variable [ExistsAddOfLE α] + +/-- Binary **arithmetic mean-geometric mean inequality** (aka AM-GM inequality) for linearly ordered +commutative semirings. -/ +lemma two_mul_le_add_sq (a b : α) : 2 * a * b ≤ a ^ 2 + b ^ 2 := by + simpa [fn_min_add_fn_max (fun x ↦ x * x), sq, two_mul, add_mul] + using mul_add_mul_le_mul_add_mul (@min_le_max _ _ a b) (@min_le_max _ _ a b) +#align two_mul_le_add_sq two_mul_le_add_sq + +alias two_mul_le_add_pow_two := two_mul_le_add_sq +#align two_mul_le_add_pow_two two_mul_le_add_pow_two + +end LinearOrderedCommSemiring + +section LinearOrderedRing +variable [LinearOrderedRing α] {a b c : α} + +attribute [local instance] LinearOrderedRing.decidableLE LinearOrderedRing.decidableLT + +-- see Note [lower instance priority] +instance (priority := 100) LinearOrderedRing.toLinearOrderedSemiring : LinearOrderedSemiring α := + { ‹LinearOrderedRing α›, StrictOrderedRing.toStrictOrderedSemiring with } +#align linear_ordered_ring.to_linear_ordered_semiring LinearOrderedRing.toLinearOrderedSemiring + +-- see Note [lower instance priority] +instance (priority := 100) LinearOrderedRing.toLinearOrderedAddCommGroup : + LinearOrderedAddCommGroup α where __ := ‹LinearOrderedRing α› +#align linear_ordered_ring.to_linear_ordered_add_comm_group LinearOrderedRing.toLinearOrderedAddCommGroup + +-- TODO: Can the following five lemmas be generalised to +-- `[LinearOrderedSemiring α] [ExistsAddOfLE α]`? + +lemma mul_neg_iff : a * b < 0 ↔ 0 < a ∧ b < 0 ∨ a < 0 ∧ 0 < b := by + rw [← neg_pos, neg_mul_eq_mul_neg, mul_pos_iff, neg_pos, neg_lt_zero] +#align mul_neg_iff mul_neg_iff + +lemma mul_nonpos_iff : a * b ≤ 0 ↔ 0 ≤ a ∧ b ≤ 0 ∨ a ≤ 0 ∧ 0 ≤ b := by + rw [← neg_nonneg, neg_mul_eq_mul_neg, mul_nonneg_iff, neg_nonneg, neg_nonpos] +#align mul_nonpos_iff mul_nonpos_iff + +lemma mul_nonneg_iff_neg_imp_nonpos : 0 ≤ a * b ↔ (a < 0 → b ≤ 0) ∧ (b < 0 → a ≤ 0) := by + rw [← neg_mul_neg, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + +lemma mul_nonpos_iff_pos_imp_nonpos : a * b ≤ 0 ↔ (0 < a → b ≤ 0) ∧ (b < 0 → 0 ≤ a) := by + rw [← neg_nonneg, ← mul_neg, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + +lemma mul_nonpos_iff_neg_imp_nonneg : a * b ≤ 0 ↔ (a < 0 → 0 ≤ b) ∧ (0 < b → a ≤ 0) := by + rw [← neg_nonneg, ← neg_mul, mul_nonneg_iff_pos_imp_nonneg]; simp only [neg_pos, neg_nonneg] + +lemma neg_one_lt_zero : -1 < (0 : α) := neg_lt_zero.2 zero_lt_one +#align neg_one_lt_zero neg_one_lt_zero + +lemma sub_one_lt (a : α) : a - 1 < a := sub_lt_iff_lt_add.2 $ lt_add_one a +#align sub_one_lt sub_one_lt + +lemma mul_self_le_mul_self_of_le_of_neg_le (h₁ : a ≤ b) (h₂ : -a ≤ b) : a * a ≤ b * b := + (le_total 0 a).elim (mul_self_le_mul_self · h₁) fun h ↦ + (neg_mul_neg a a).symm.trans_le $ mul_le_mul h₂ h₂ (neg_nonneg.2 h) $ (neg_nonneg.2 h).trans h₂ +#align mul_self_le_mul_self_of_le_of_neg_le mul_self_le_mul_self_of_le_of_neg_le + end LinearOrderedRing -- see Note [lower instance priority] @@ -1215,21 +1310,6 @@ instance (priority := 100) LinearOrderedCommRing.toLinearOrderedCommSemiring { d, LinearOrderedRing.toLinearOrderedSemiring with } #align linear_ordered_comm_ring.to_linear_ordered_comm_semiring LinearOrderedCommRing.toLinearOrderedCommSemiring -section LinearOrderedCommRing - -variable [LinearOrderedCommRing α] {a b c d : α} - -theorem max_mul_mul_le_max_mul_max (b c : α) (ha : 0 ≤ a) (hd : 0 ≤ d) : - max (a * b) (d * c) ≤ max a c * max d b := - have ba : b * a ≤ max d b * max c a := - mul_le_mul (le_max_right d b) (le_max_right c a) ha (le_trans hd (le_max_left d b)) - have cd : c * d ≤ max a c * max b d := - mul_le_mul (le_max_right a c) (le_max_right b d) hd (le_trans ha (le_max_left a c)) - max_le (by simpa [mul_comm, max_comm] using ba) (by simpa [mul_comm, max_comm] using cd) -#align max_mul_mul_le_max_mul_max max_mul_mul_le_max_mul_max - -end LinearOrderedCommRing - /-! ### Deprecated lemmas @@ -1240,3 +1320,5 @@ Those lemmas have been deprecated on 2023/12/23 @[deprecated] alias zero_le_mul_right := mul_nonneg_iff_of_pos_right @[deprecated] alias zero_lt_mul_left := mul_pos_iff_of_pos_left @[deprecated] alias zero_lt_mul_right := mul_pos_iff_of_pos_right + +assert_not_exists MonoidHom diff --git a/Mathlib/Algebra/Ring/Idempotents.lean b/Mathlib/Algebra/Ring/Idempotents.lean index 8e634cfa0387a..f7699e3dc8c9e 100644 --- a/Mathlib/Algebra/Ring/Idempotents.lean +++ b/Mathlib/Algebra/Ring/Idempotents.lean @@ -3,9 +3,10 @@ Copyright (c) 2022 Christopher Hoskin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Christopher Hoskin -/ -import Mathlib.Order.Basic import Mathlib.Algebra.GroupPower.Basic import Mathlib.Algebra.Ring.Defs +import Mathlib.Order.Basic +import Mathlib.Tactic.Conv #align_import algebra.ring.idempotents from "leanprover-community/mathlib"@"655994e298904d7e5bbd1e18c95defd7b543eb94" diff --git a/Mathlib/Data/Int/Cast/Lemmas.lean b/Mathlib/Data/Int/Cast/Lemmas.lean index 557ffd7adac5e..462fcc0d89724 100644 --- a/Mathlib/Data/Int/Cast/Lemmas.lean +++ b/Mathlib/Data/Int/Cast/Lemmas.lean @@ -3,6 +3,7 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Mathlib.Algebra.Group.TypeTags import Mathlib.Algebra.Ring.Hom.Basic import Mathlib.Data.Int.Order.Basic import Mathlib.Data.Nat.Cast.Commute diff --git a/Mathlib/Data/Multiset/Bind.lean b/Mathlib/Data/Multiset/Bind.lean index 275725fde8fad..4707a03d719e0 100644 --- a/Mathlib/Data/Multiset/Bind.lean +++ b/Mathlib/Data/Multiset/Bind.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Algebra.BigOperators.Multiset.Basic +import Mathlib.GroupTheory.GroupAction.Defs #align_import data.multiset.bind from "leanprover-community/mathlib"@"f694c7dead66f5d4c80f446c796a5aad14707f0e" diff --git a/Mathlib/Data/Set/Pointwise/Basic.lean b/Mathlib/Data/Set/Pointwise/Basic.lean index 5a7d07805a9b8..a75a47092fb93 100644 --- a/Mathlib/Data/Set/Pointwise/Basic.lean +++ b/Mathlib/Data/Set/Pointwise/Basic.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.Algebra.Group.Units.Hom import Mathlib.Algebra.GroupPower.Basic import Mathlib.Algebra.GroupWithZero.Basic +import Mathlib.Algebra.Opposites import Mathlib.Data.Nat.Order.Basic import Mathlib.Data.Set.Lattice import Mathlib.Tactic.Common From 0d6117a47dd8f9fe074025146a29b195bf0230f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 1 Jan 2024 12:02:33 +0000 Subject: [PATCH 295/353] feat: Cauchy-Schwarz in semirings (#9371) This is a version of the Cauchy-Schwarz inequality that works in semirings. From LeanAPAP and PFR --- Mathlib/Algebra/BigOperators/Order.lean | 47 +++++++++++++++++-------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/Mathlib/Algebra/BigOperators/Order.lean b/Mathlib/Algebra/BigOperators/Order.lean index e3f0dedb9ff23..a6d7806a0c6e2 100644 --- a/Mathlib/Algebra/BigOperators/Order.lean +++ b/Mathlib/Algebra/BigOperators/Order.lean @@ -5,9 +5,10 @@ Authors: Johannes Hölzl -/ import Mathlib.Algebra.Order.AbsoluteValue import Mathlib.Algebra.Order.Ring.WithTop -import Mathlib.Algebra.BigOperators.Basic +import Mathlib.Algebra.BigOperators.Ring import Mathlib.Data.Fintype.Card import Mathlib.Tactic.GCongr.Core +import Mathlib.Tactic.Ring #align_import algebra.big_operators.order from "leanprover-community/mathlib"@"65a1391a0106c9204fe45bc73a039f056558cb83" @@ -191,13 +192,11 @@ theorem prod_eq_one_iff_of_one_le' : #align finset.prod_eq_one_iff_of_one_le' Finset.prod_eq_one_iff_of_one_le' #align finset.sum_eq_zero_iff_of_nonneg Finset.sum_eq_zero_iff_of_nonneg -@[to_additive existing sum_eq_zero_iff_of_nonneg] +@[to_additive sum_eq_zero_iff_of_nonpos] theorem prod_eq_one_iff_of_le_one' : (∀ i ∈ s, f i ≤ 1) → ((∏ i in s, f i) = 1 ↔ ∀ i ∈ s, f i = 1) := @prod_eq_one_iff_of_one_le' _ Nᵒᵈ _ _ _ #align finset.prod_eq_one_iff_of_le_one' Finset.prod_eq_one_iff_of_le_one' --- Porting note: there is no align for the additive version since it aligns to the --- same one as the previous lemma @[to_additive single_le_sum] theorem single_le_prod' (hf : ∀ i ∈ s, 1 ≤ f i) {a} (h : a ∈ s) : f a ≤ ∏ x in s, f x := @@ -685,6 +684,28 @@ theorem prod_lt_prod_of_nonempty (hf : ∀ i ∈ s, 0 < f i) (hfg : ∀ i ∈ s, end StrictOrderedCommSemiring +section LinearOrderedCommSemiring +variable [LinearOrderedCommSemiring α] [ExistsAddOfLE α] + +lemma sum_mul_sq_le_sq_mul_sq (s : Finset ι) (f g : ι → α) : + (∑ i in s, f i * g i) ^ 2 ≤ (∑ i in s, f i ^ 2) * ∑ i in s, g i ^ 2 := by + nontriviality α + obtain h' | h' := (sum_nonneg fun _ _ ↦ sq_nonneg $ g _).eq_or_lt + · have h'' : ∀ i ∈ s, g i = 0 := fun i hi ↦ by + simpa using (sum_eq_zero_iff_of_nonneg fun i _ ↦ sq_nonneg (g i)).1 h'.symm i hi + rw [← h', sum_congr rfl (show ∀ i ∈ s, f i * g i = 0 from fun i hi ↦ by simp [h'' i hi])] + simp + refine le_of_mul_le_mul_of_pos_left + (le_of_add_le_add_left (a := (∑ i in s, g i ^ 2) * (∑ j in s, f j * g j) ^ 2) ?_) h' + calc + _ = ∑ i in s, 2 * (f i * ∑ j in s, g j ^ 2) * (g i * ∑ j in s, f j * g j) := by + simp_rw [mul_assoc (2 : α), mul_mul_mul_comm, ← mul_sum, ← sum_mul]; ring + _ ≤ ∑ i in s, ((f i * ∑ j in s, g j ^ 2) ^ 2 + (g i * ∑ j in s, f j * g j) ^ 2) := + sum_le_sum fun i _ ↦ two_mul_le_add_sq (f i * ∑ j in s, g j ^ 2) (g i * ∑ j in s, f j * g j) + _ = _ := by simp_rw [sum_add_distrib, mul_pow, ← sum_mul]; ring + +end LinearOrderedCommSemiring + section CanonicallyOrderedCommSemiring variable [CanonicallyOrderedCommSemiring R] {f g h : ι → R} {s : Finset ι} {i : ι} @@ -730,6 +751,14 @@ lemma one_le_prod (hf : 1 ≤ f) : 1 ≤ ∏ i, f i := Finset.one_le_prod' λ _ @[to_additive] lemma prod_le_one (hf : f ≤ 1) : ∏ i, f i ≤ 1 := Finset.prod_le_one' λ _ _ ↦ hf _ +@[to_additive] +lemma prod_eq_one_iff_of_one_le (hf : 1 ≤ f) : ∏ i, f i = 1 ↔ f = 1 := + (Finset.prod_eq_one_iff_of_one_le' fun i _ ↦ hf i).trans $ by simp [Function.funext_iff] + +@[to_additive] +lemma prod_eq_one_iff_of_le_one (hf : f ≤ 1) : ∏ i, f i = 1 ↔ f = 1 := + (Finset.prod_eq_one_iff_of_le_one' fun i _ ↦ hf i).trans $ by simp [Function.funext_iff] + end OrderedCommMonoid section OrderedCancelCommMonoid @@ -759,16 +788,6 @@ lemma one_lt_prod_iff_of_one_le (hf : 1 ≤ f) : 1 < ∏ i, f i ↔ 1 < f := by lemma prod_lt_one_iff_of_le_one (hf : f ≤ 1) : ∏ i, f i < 1 ↔ f < 1 := by obtain rfl | hf := hf.eq_or_lt <;> simp [*, prod_lt_one] -@[to_additive] -lemma prod_eq_one_iff_of_one_le (hf : 1 ≤ f) : ∏ i, f i = 1 ↔ f = 1 := by - simpa only [(one_le_prod hf).not_gt_iff_eq, hf.not_gt_iff_eq] - using (one_lt_prod_iff_of_one_le hf).not - -@[to_additive] -lemma prod_eq_one_iff_of_le_one (hf : f ≤ 1) : ∏ i, f i = 1 ↔ f = 1 := by - simpa only [(prod_le_one hf).not_gt_iff_eq, hf.not_gt_iff_eq, eq_comm] - using (prod_lt_one_iff_of_le_one hf).not - end OrderedCancelCommMonoid end Fintype From 0b41ea95f7808c33d88e7139df523da41408192d Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Mon, 1 Jan 2024 14:48:15 +0000 Subject: [PATCH 296/353] chore: Reorganize results about `rank` and `finrank`. (#9349) The files `Mathlib.LinearAlgebra.FreeModule.Rank`, `Mathlib.LinearAlgebra.FreeModule.Finite.Rank`, `Mathlib.LinearAlgebra.Dimension` and `Mathlib.LinearAlgebra.Finrank` were reorganized into a folder `Mathlib.LinearAlgebra.Dimension`, containing the following files - `Basic.lean`: Contains the definition of `Module.rank`. - `Finrank.lean`: Contains the definition of `FiniteDimensional.finrank`. - `StrongRankCondition.lean`: Contains results about `rank` and `finrank` over rings satisfying strong rank condition - `Free.lean`: Contains results about `rank` and `finrank` of free modules - `Finite.lean`: Contains conditions or consequences for `rank` to be finite or zero - `Constructions.lean`: Contains the calculation of the `rank` of various constructions. - `DivisionRing.lean`: Contains results about `rank` and `finrank` of spaces over division rings. - `LinearMap.lean`: Contains results about `LinearMap.rank` API changes: `IsNoetherian.rank_lt_aleph0` and `FiniteDimensional.rank_lt_aleph0` are replaced with `rank_lt_aleph0`. `Module.Free.finite_basis` was renamed to `Module.Finite.finite_basis`. `FiniteDimensional.finrank_eq_rank` was renamed to `finrank_eq_rank`. `rank_eq_cardinal_basis` and `rank_eq_cardinal_basis'` were removed in favour of `Basis.mk_eq_mk` and `Basis.mk_eq_mk''`. Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 12 +- Mathlib/Algebra/Category/ModuleCat/Free.lean | 9 +- Mathlib/Algebra/DirectSum/LinearMap.lean | 2 +- Mathlib/Algebra/Lie/Weights/Linear.lean | 1 + Mathlib/Algebra/LinearRecurrence.lean | 2 +- Mathlib/Algebra/Quaternion.lean | 2 +- Mathlib/Analysis/NormedSpace/Connected.lean | 2 +- Mathlib/Data/Matrix/Rank.lean | 4 - Mathlib/FieldTheory/Finiteness.lean | 10 +- Mathlib/FieldTheory/MvPolynomial.lean | 4 +- .../GroupTheory/FreeAbelianGroupFinsupp.lean | 4 +- Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean | 5 + Mathlib/LinearAlgebra/Dimension.lean | 1558 ----------------- Mathlib/LinearAlgebra/Dimension/Basic.lean | 375 ++++ .../Dimension/Constructions.lean | 509 ++++++ .../LinearAlgebra/Dimension/DivisionRing.lean | 644 +++++++ Mathlib/LinearAlgebra/Dimension/Finite.lean | 518 ++++++ Mathlib/LinearAlgebra/Dimension/Finrank.lean | 144 ++ Mathlib/LinearAlgebra/Dimension/Free.lean | 206 +++ .../LinearAlgebra/Dimension/LinearMap.lean | 143 ++ .../Dimension/StrongRankCondition.lean | 498 ++++++ Mathlib/LinearAlgebra/FiniteDimensional.lean | 12 +- Mathlib/LinearAlgebra/Finrank.lean | 621 ------- Mathlib/LinearAlgebra/FreeAlgebra.lean | 1 - .../FreeModule/Finite/Basic.lean | 12 +- .../FreeModule/Finite/Matrix.lean | 4 +- .../LinearAlgebra/FreeModule/Finite/Rank.lean | 592 ------- .../FreeModule/IdealQuotient.lean | 2 - Mathlib/LinearAlgebra/FreeModule/PID.lean | 5 +- Mathlib/LinearAlgebra/FreeModule/Rank.lean | 257 --- Mathlib/LinearAlgebra/Matrix/Diagonal.lean | 3 +- .../LinearAlgebra/TensorAlgebra/Basis.lean | 3 - Mathlib/LinearAlgebra/Trace.lean | 7 - .../Measure/Lebesgue/EqHaar.lean | 2 +- Mathlib/NumberTheory/RamificationInertia.lean | 1 - Mathlib/RingTheory/Finiteness.lean | 7 + 36 files changed, 3079 insertions(+), 3102 deletions(-) delete mode 100644 Mathlib/LinearAlgebra/Dimension.lean create mode 100644 Mathlib/LinearAlgebra/Dimension/Basic.lean create mode 100644 Mathlib/LinearAlgebra/Dimension/Constructions.lean create mode 100644 Mathlib/LinearAlgebra/Dimension/DivisionRing.lean create mode 100644 Mathlib/LinearAlgebra/Dimension/Finite.lean create mode 100644 Mathlib/LinearAlgebra/Dimension/Finrank.lean create mode 100644 Mathlib/LinearAlgebra/Dimension/Free.lean create mode 100644 Mathlib/LinearAlgebra/Dimension/LinearMap.lean create mode 100644 Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean delete mode 100644 Mathlib/LinearAlgebra/Finrank.lean delete mode 100644 Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean delete mode 100644 Mathlib/LinearAlgebra/FreeModule/Rank.lean diff --git a/Mathlib.lean b/Mathlib.lean index 33e166c4d41b1..4d2803ffe58ed 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2383,7 +2383,14 @@ import Mathlib.LinearAlgebra.Contraction import Mathlib.LinearAlgebra.CrossProduct import Mathlib.LinearAlgebra.DFinsupp import Mathlib.LinearAlgebra.Determinant -import Mathlib.LinearAlgebra.Dimension +import Mathlib.LinearAlgebra.Dimension.Basic +import Mathlib.LinearAlgebra.Dimension.Constructions +import Mathlib.LinearAlgebra.Dimension.DivisionRing +import Mathlib.LinearAlgebra.Dimension.Finite +import Mathlib.LinearAlgebra.Dimension.Finrank +import Mathlib.LinearAlgebra.Dimension.Free +import Mathlib.LinearAlgebra.Dimension.LinearMap +import Mathlib.LinearAlgebra.Dimension.StrongRankCondition import Mathlib.LinearAlgebra.DirectSum.Finsupp import Mathlib.LinearAlgebra.DirectSum.TensorProduct import Mathlib.LinearAlgebra.Dual @@ -2395,7 +2402,6 @@ import Mathlib.LinearAlgebra.ExteriorAlgebra.Grading import Mathlib.LinearAlgebra.ExteriorAlgebra.OfAlternating import Mathlib.LinearAlgebra.FiniteDimensional import Mathlib.LinearAlgebra.FiniteSpan -import Mathlib.LinearAlgebra.Finrank import Mathlib.LinearAlgebra.Finsupp import Mathlib.LinearAlgebra.FinsuppVectorSpace import Mathlib.LinearAlgebra.FreeAlgebra @@ -2403,11 +2409,9 @@ import Mathlib.LinearAlgebra.FreeModule.Basic import Mathlib.LinearAlgebra.FreeModule.Determinant import Mathlib.LinearAlgebra.FreeModule.Finite.Basic import Mathlib.LinearAlgebra.FreeModule.Finite.Matrix -import Mathlib.LinearAlgebra.FreeModule.Finite.Rank import Mathlib.LinearAlgebra.FreeModule.IdealQuotient import Mathlib.LinearAlgebra.FreeModule.Norm import Mathlib.LinearAlgebra.FreeModule.PID -import Mathlib.LinearAlgebra.FreeModule.Rank import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition import Mathlib.LinearAlgebra.GeneralLinearGroup import Mathlib.LinearAlgebra.InvariantBasisNumber diff --git a/Mathlib/Algebra/Category/ModuleCat/Free.lean b/Mathlib/Algebra/Category/ModuleCat/Free.lean index 8c7e71bae019f..1070a9f4c3f89 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Free.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Free.lean @@ -3,13 +3,8 @@ Copyright (c) 2023 Dagur Asgeirsson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Dagur Asgeirsson -/ -import Mathlib.Algebra.Category.ModuleCat.Abelian -import Mathlib.Algebra.Category.ModuleCat.Adjunctions +import Mathlib.LinearAlgebra.Dimension.Finite import Mathlib.Algebra.Homology.ShortComplex.ModuleCat -import Mathlib.LinearAlgebra.FreeModule.Basic -import Mathlib.LinearAlgebra.FreeModule.Finite.Rank -import Mathlib.LinearAlgebra.Dimension -import Mathlib.LinearAlgebra.Finrank /-! # Exact sequences with free modules @@ -179,6 +174,6 @@ theorem free_shortExact_finrank_add [Module.Free R S.X₁] [Module.Free R S.X₃ FiniteDimensional.finrank R S.X₂ = n + p := by apply FiniteDimensional.finrank_eq_of_rank_eq rw [free_shortExact_rank_add hS', ← hN, ← hP] - simp only [Nat.cast_add, FiniteDimensional.finrank_eq_rank] + simp only [Nat.cast_add, finrank_eq_rank] end ModuleCat diff --git a/Mathlib/Algebra/DirectSum/LinearMap.lean b/Mathlib/Algebra/DirectSum/LinearMap.lean index 99256260d820c..a9aed2d4a03b9 100644 --- a/Mathlib/Algebra/DirectSum/LinearMap.lean +++ b/Mathlib/Algebra/DirectSum/LinearMap.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Oliver Nash. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Oliver Nash -/ -import Mathlib.Algebra.DirectSum.Module +import Mathlib.LinearAlgebra.FreeModule.PID import Mathlib.LinearAlgebra.Eigenspace.Basic import Mathlib.LinearAlgebra.Trace diff --git a/Mathlib/Algebra/Lie/Weights/Linear.lean b/Mathlib/Algebra/Lie/Weights/Linear.lean index 3d8593edd93e5..e2967a3e5c4ed 100644 --- a/Mathlib/Algebra/Lie/Weights/Linear.lean +++ b/Mathlib/Algebra/Lie/Weights/Linear.lean @@ -5,6 +5,7 @@ Authors: Oliver Nash -/ import Mathlib.Algebra.Lie.Weights.Basic import Mathlib.LinearAlgebra.Trace +import Mathlib.LinearAlgebra.FreeModule.PID /-! # Lie modules with linear weights diff --git a/Mathlib/Algebra/LinearRecurrence.lean b/Mathlib/Algebra/LinearRecurrence.lean index ed53e229ba9a7..d8a9751d524c8 100644 --- a/Mathlib/Algebra/LinearRecurrence.lean +++ b/Mathlib/Algebra/LinearRecurrence.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedecker -/ import Mathlib.Data.Polynomial.Eval -import Mathlib.LinearAlgebra.Dimension +import Mathlib.LinearAlgebra.Dimension.Constructions #align_import algebra.linear_recurrence from "leanprover-community/mathlib"@"039a089d2a4b93c761b234f3e5f5aeb752bac60f" diff --git a/Mathlib/Algebra/Quaternion.lean b/Mathlib/Algebra/Quaternion.lean index e6978519610c4..e8bce655f49d2 100644 --- a/Mathlib/Algebra/Quaternion.lean +++ b/Mathlib/Algebra/Quaternion.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.Algebra.Equiv -import Mathlib.LinearAlgebra.Finrank +import Mathlib.LinearAlgebra.Dimension.StrongRankCondition import Mathlib.LinearAlgebra.FreeModule.Basic import Mathlib.LinearAlgebra.FreeModule.Finite.Basic import Mathlib.SetTheory.Cardinal.Ordinal diff --git a/Mathlib/Analysis/NormedSpace/Connected.lean b/Mathlib/Analysis/NormedSpace/Connected.lean index f3281222be9d1..12d7c52c6a70f 100644 --- a/Mathlib/Analysis/NormedSpace/Connected.lean +++ b/Mathlib/Analysis/NormedSpace/Connected.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ import Mathlib.Analysis.Convex.Topology -import Mathlib.LinearAlgebra.Dimension +import Mathlib.LinearAlgebra.Dimension.DivisionRing import Mathlib.Topology.Algebra.Module.Cardinality /-! diff --git a/Mathlib/Data/Matrix/Rank.lean b/Mathlib/Data/Matrix/Rank.lean index 3f5f2fd3dc6e8..3907b84acc1b5 100644 --- a/Mathlib/Data/Matrix/Rank.lean +++ b/Mathlib/Data/Matrix/Rank.lean @@ -3,13 +3,9 @@ Copyright (c) 2021 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Eric Wieser -/ -import Mathlib.LinearAlgebra.FreeModule.Finite.Rank -import Mathlib.LinearAlgebra.Matrix.ToLin -import Mathlib.LinearAlgebra.FiniteDimensional import Mathlib.LinearAlgebra.Matrix.DotProduct import Mathlib.LinearAlgebra.Determinant import Mathlib.LinearAlgebra.Matrix.Diagonal -import Mathlib.Data.Complex.Module #align_import data.matrix.rank from "leanprover-community/mathlib"@"17219820a8aa8abe85adf5dfde19af1dd1bd8ae7" diff --git a/Mathlib/FieldTheory/Finiteness.lean b/Mathlib/FieldTheory/Finiteness.lean index c0b87f5efd188..7d6b1bae0c928 100644 --- a/Mathlib/FieldTheory/Finiteness.lean +++ b/Mathlib/FieldTheory/Finiteness.lean @@ -3,8 +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 Mathlib.RingTheory.Finiteness -import Mathlib.LinearAlgebra.Dimension +import Mathlib.LinearAlgebra.Dimension.DivisionRing #align_import field_theory.finiteness from "leanprover-community/mathlib"@"039a089d2a4b93c761b234f3e5f5aeb752bac60f" @@ -43,11 +42,8 @@ theorem iff_rank_lt_aleph0 : IsNoetherian K V ↔ Module.rank K V < ℵ₀ := by variable (K V) -/-- The dimension of a noetherian module over a division ring, as a cardinal, -is strictly less than the first infinite cardinal `ℵ₀`. -/ -theorem rank_lt_aleph0 : ∀ [IsNoetherian K V], Module.rank K V < ℵ₀ := - @IsNoetherian.iff_rank_lt_aleph0.1 -#align is_noetherian.rank_lt_aleph_0 IsNoetherian.rank_lt_aleph0 +@[deprecated] protected alias rank_lt_aleph0 := _root_.rank_lt_aleph0 +#align is_noetherian.rank_lt_aleph_0 rank_lt_aleph0 variable {K V} diff --git a/Mathlib/FieldTheory/MvPolynomial.lean b/Mathlib/FieldTheory/MvPolynomial.lean index 0c2ce16a031bb..26cc54021d74d 100644 --- a/Mathlib/FieldTheory/MvPolynomial.lean +++ b/Mathlib/FieldTheory/MvPolynomial.lean @@ -3,9 +3,7 @@ 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 -/ -import Mathlib.Data.MvPolynomial.CommRing -import Mathlib.LinearAlgebra.Dimension -import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.LinearAlgebra.Dimension.StrongRankCondition import Mathlib.RingTheory.MvPolynomial.Basic #align_import field_theory.mv_polynomial from "leanprover-community/mathlib"@"039a089d2a4b93c761b234f3e5f5aeb752bac60f" diff --git a/Mathlib/GroupTheory/FreeAbelianGroupFinsupp.lean b/Mathlib/GroupTheory/FreeAbelianGroupFinsupp.lean index 4d4404e57d6ce..1f32da53d5e0a 100644 --- a/Mathlib/GroupTheory/FreeAbelianGroupFinsupp.lean +++ b/Mathlib/GroupTheory/FreeAbelianGroupFinsupp.lean @@ -4,11 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ import Mathlib.Algebra.Group.Equiv.TypeTags -import Mathlib.Algebra.Module.Equiv -import Mathlib.Data.Finsupp.Defs import Mathlib.GroupTheory.FreeAbelianGroup import Mathlib.GroupTheory.FreeGroup.IsFreeGroup -import Mathlib.LinearAlgebra.Dimension +import Mathlib.LinearAlgebra.Dimension.StrongRankCondition #align_import group_theory.free_abelian_group_finsupp from "leanprover-community/mathlib"@"47b51515e69f59bca5cf34ef456e6000fe205a69" diff --git a/Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean b/Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean index 6e43a7308660a..e1ee558c5b153 100644 --- a/Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean +++ b/Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean @@ -36,6 +36,11 @@ namespace LinearMap section Basic +attribute [-instance] instCoeOut + +attribute [local instance 2000] RingHomClass.toNonUnitalRingHomClass +attribute [local instance 2000] NonUnitalRingHomClass.toMulHomClass MulHomClass.toFunLike + /-- `charpoly f` is the characteristic polynomial of the matrix of `f` in any basis. -/ @[simp] theorem charpoly_toMatrix {ι : Type w} [DecidableEq ι] [Fintype ι] (b : Basis ι R M) : diff --git a/Mathlib/LinearAlgebra/Dimension.lean b/Mathlib/LinearAlgebra/Dimension.lean deleted file mode 100644 index 88b62d39a7e7e..0000000000000 --- a/Mathlib/LinearAlgebra/Dimension.lean +++ /dev/null @@ -1,1558 +0,0 @@ -/- -Copyright (c) 2018 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison --/ -import Mathlib.Algebra.Module.BigOperators -import Mathlib.LinearAlgebra.Basis.VectorSpace -import Mathlib.Algebra.Module.Torsion -import Mathlib.LinearAlgebra.DFinsupp -import Mathlib.LinearAlgebra.FreeModule.Basic -import Mathlib.LinearAlgebra.InvariantBasisNumber -import Mathlib.LinearAlgebra.Isomorphisms -import Mathlib.LinearAlgebra.StdBasis -import Mathlib.SetTheory.Cardinal.Cofinality - -#align_import linear_algebra.dimension from "leanprover-community/mathlib"@"47a5f8186becdbc826190ced4312f8199f9db6a5" - -/-! -# Dimension of modules and vector spaces - -## Main definitions - -* The rank of a module is defined as `Module.rank : Cardinal`. - This is defined as the supremum of the cardinalities of linearly independent subsets. - -* The rank of a linear map is defined as the rank of its range. - -## Main statements - -* `LinearMap.rank_le_of_injective`: the source of an injective linear map has dimension - at most that of the target. -* `LinearMap.rank_le_of_surjective`: the target of a surjective linear map has dimension - at most that of that source. -* `basis_finite_of_finite_spans`: - the existence of a finite spanning set implies that any basis is finite. -* `infinite_basis_le_maximal_linearIndependent`: - if `b` is an infinite basis for a module `M`, - and `s` is a maximal linearly independent set, - then the cardinality of `b` is bounded by the cardinality of `s`. - -For modules over rings satisfying the rank condition - -* `Basis.le_span`: - the cardinality of a basis is bounded by the cardinality of any spanning set - -For modules over rings satisfying the strong rank condition - -* `linearIndependent_le_span`: - For any linearly independent family `v : ι → M` - and any finite spanning set `w : Set M`, - the cardinality of `ι` is bounded by the cardinality of `w`. -* `linearIndependent_le_basis`: - If `b` is a basis for a module `M`, - and `s` is a linearly independent set, - then the cardinality of `s` is bounded by the cardinality of `b`. - -For modules over rings with invariant basis number -(including all commutative rings and all noetherian rings) - -* `mk_eq_mk_of_basis`: the dimension theorem, any two bases of the same vector space have the same - cardinality. - -For vector spaces (i.e. modules over a field), we have - -* `rank_quotient_add_rank`: if `V₁` is a submodule of `V`, then - `Module.rank (V/V₁) + Module.rank V₁ = Module.rank V`. -* `rank_range_add_rank_ker`: the rank-nullity theorem. - -## Implementation notes - -Many theorems in this file are not universe-generic when they relate dimensions -in different universes. They should be as general as they can be without -inserting `lift`s. The types `V`, `V'`, ... all live in different universes, -and `V₁`, `V₂`, ... all live in the same universe. --/ - - -noncomputable section - -universe u v v' v'' u₁' w w' - -variable {K R : Type u} {V V₁ V₂ V₃ : Type v} {V' V'₁ : Type v'} {V'' : Type v''} - -variable {ι : Type w} {ι' : Type w'} {η : Type u₁'} {φ : η → Type*} - -open BigOperators Cardinal Basis Submodule Function Set - -section Module - -section - -variable [Semiring K] [AddCommMonoid V] [Module K V] - -variable (K V) - -/-- The rank of a module, defined as a term of type `Cardinal`. - -We define this as the supremum of the cardinalities of linearly independent subsets. - -For a free module over any ring satisfying the strong rank condition -(e.g. left-noetherian rings, commutative rings, and in particular division rings and fields), -this is the same as the dimension of the space (i.e. the cardinality of any basis). - -In particular this agrees with the usual notion of the dimension of a vector space. - --/ -protected irreducible_def Module.rank : Cardinal := - ⨆ ι : { s : Set V // LinearIndependent K ((↑) : s → V) }, (#ι.1) -#align module.rank Module.rank - -theorem rank_le_card : Module.rank K V ≤ #V := - (Module.rank_def _ _).trans_le (ciSup_le' fun _ ↦ mk_set_le _) - -lemma nonempty_linearIndependent_set : Nonempty {s : Set V // LinearIndependent K ((↑) : s → V)} := - ⟨⟨∅, linearIndependent_empty _ _⟩⟩ - -end - -section - -variable [Ring R] - -variable {M : Type v} [AddCommGroup M] [Module R M] - -variable {M' : Type v'} [AddCommGroup M'] [Module R M'] - -variable {M₁ : Type v} [AddCommGroup M₁] [Module R M₁] - -theorem LinearMap.lift_rank_le_of_injective (f : M →ₗ[R] M') (i : Injective f) : - Cardinal.lift.{v'} (Module.rank R M) ≤ Cardinal.lift.{v} (Module.rank R M') := by - simp only [Module.rank_def] - rw [Cardinal.lift_iSup (Cardinal.bddAbove_range.{v', v'} _), - Cardinal.lift_iSup (Cardinal.bddAbove_range.{v, v} _)] - apply ciSup_mono' (Cardinal.bddAbove_range.{v', v} _) - rintro ⟨s, li⟩ - refine' ⟨⟨f '' s, _⟩, Cardinal.lift_mk_le'.mpr ⟨(Equiv.Set.image f s i).toEmbedding⟩⟩ - exact (li.map' _ <| LinearMap.ker_eq_bot_of_injective i).image -#align linear_map.lift_rank_le_of_injective LinearMap.lift_rank_le_of_injective - -theorem LinearMap.rank_le_of_injective (f : M →ₗ[R] M₁) (i : Injective f) : - Module.rank R M ≤ Module.rank R M₁ := - Cardinal.lift_le.1 (f.lift_rank_le_of_injective i) -#align linear_map.rank_le_of_injective LinearMap.rank_le_of_injective - -theorem rank_le {n : ℕ} - (H : ∀ s : Finset M, (LinearIndependent R fun i : s => (i : M)) → s.card ≤ n) : - Module.rank R M ≤ n := by - rw [Module.rank_def] - apply ciSup_le' - rintro ⟨s, li⟩ - exact linearIndependent_bounded_of_finset_linearIndependent_bounded H _ li -#align rank_le rank_le - -theorem rank_quotient_add_rank_le [Nontrivial R] (M' : Submodule R M) : - Module.rank R (M ⧸ M') + Module.rank R M' ≤ Module.rank R M := by - simp_rw [Module.rank_def] - have := nonempty_linearIndependent_set R (M ⧸ M') - have := nonempty_linearIndependent_set R M' - rw [Cardinal.ciSup_add_ciSup _ (bddAbove_range.{v, v} _) _ (bddAbove_range.{v, v} _)] - refine ciSup_le fun ⟨s, hs⟩ ↦ ciSup_le fun ⟨t, ht⟩ ↦ ?_ - choose f hf using Quotient.mk_surjective M' - let g : s ⊕ t → M := Sum.elim (f ·) (·) - suffices : LinearIndependent R g - · refine le_trans ?_ (le_ciSup (bddAbove_range.{v, v} _) ⟨_, this.to_subtype_range⟩) - rw [mk_range_eq _ this.injective, mk_sum, lift_id, lift_id] - refine .sum_type (.of_comp M'.mkQ ?_) (ht.map' M'.subtype M'.ker_subtype) ?_ - · convert hs; ext x; exact hf x - refine disjoint_def.mpr fun x h₁ h₂ ↦ ?_ - have : x ∈ M' := span_le.mpr (Set.range_subset_iff.mpr fun i ↦ i.1.2) h₂ - obtain ⟨c, rfl⟩ := Finsupp.mem_span_range_iff_exists_finsupp.mp h₁ - simp_rw [← Quotient.mk_eq_zero, ← mkQ_apply, map_finsupp_sum, map_smul, mkQ_apply, hf] at this - rw [linearIndependent_iff.mp hs _ this, Finsupp.sum_zero_index] - -/-- The rank of the range of a linear map is at most the rank of the source. -/ --- The proof is: a free submodule of the range lifts to a free submodule of the --- source, by arbitrarily lifting a basis. -theorem lift_rank_range_le (f : M →ₗ[R] M') : Cardinal.lift.{v} - (Module.rank R (LinearMap.range f)) ≤ Cardinal.lift.{v'} (Module.rank R M) := by - simp only [Module.rank_def] - rw [Cardinal.lift_iSup (Cardinal.bddAbove_range.{v', v'} _)] - apply ciSup_le' - rintro ⟨s, li⟩ - apply le_trans - swap - · apply Cardinal.lift_le.mpr - refine' le_ciSup (Cardinal.bddAbove_range.{v, v} _) ⟨rangeSplitting f '' s, _⟩ - apply LinearIndependent.of_comp f.rangeRestrict - convert li.comp (Equiv.Set.rangeSplittingImageEquiv f s) (Equiv.injective _) using 1 - · exact (Cardinal.lift_mk_eq'.mpr ⟨Equiv.Set.rangeSplittingImageEquiv f s⟩).ge -#align lift_rank_range_le lift_rank_range_le - -theorem rank_range_le (f : M →ₗ[R] M₁) : Module.rank R (LinearMap.range f) ≤ Module.rank R M := by - simpa using lift_rank_range_le f -#align rank_range_le rank_range_le - -theorem lift_rank_map_le (f : M →ₗ[R] M') (p : Submodule R M) : - Cardinal.lift.{v} (Module.rank R (p.map f)) ≤ Cardinal.lift.{v'} (Module.rank R p) := by - have h := lift_rank_range_le (f.comp (Submodule.subtype p)) - rwa [LinearMap.range_comp, range_subtype] at h -#align lift_rank_map_le lift_rank_map_le - -theorem rank_map_le (f : M →ₗ[R] M₁) (p : Submodule R M) : - Module.rank R (p.map f) ≤ Module.rank R p := by simpa using lift_rank_map_le f p -#align rank_map_le rank_map_le - -theorem rank_le_of_submodule (s t : Submodule R M) (h : s ≤ t) : - Module.rank R s ≤ Module.rank R t := - (Submodule.inclusion h).rank_le_of_injective fun ⟨x, _⟩ ⟨y, _⟩ eq => - Subtype.eq <| show x = y from Subtype.ext_iff_val.1 eq -#align rank_le_of_submodule rank_le_of_submodule - -/-- Two linearly equivalent vector spaces have the same dimension, a version with different -universes. -/ -theorem LinearEquiv.lift_rank_eq (f : M ≃ₗ[R] M') : - Cardinal.lift.{v'} (Module.rank R M) = Cardinal.lift.{v} (Module.rank R M') := by - apply le_antisymm - · exact f.toLinearMap.lift_rank_le_of_injective f.injective - · exact f.symm.toLinearMap.lift_rank_le_of_injective f.symm.injective -#align linear_equiv.lift_rank_eq LinearEquiv.lift_rank_eq - -/-- Two linearly equivalent vector spaces have the same dimension. -/ -theorem LinearEquiv.rank_eq (f : M ≃ₗ[R] M₁) : Module.rank R M = Module.rank R M₁ := - Cardinal.lift_inj.1 f.lift_rank_eq -#align linear_equiv.rank_eq LinearEquiv.rank_eq - -theorem rank_range_of_injective (f : M →ₗ[R] M₁) (h : Injective f) : - Module.rank R (LinearMap.range f) = Module.rank R M := - (LinearEquiv.ofInjective f h).rank_eq.symm -#align rank_eq_of_injective rank_range_of_injective - -/-- Pushforwards of submodules along a `LinearEquiv` have the same dimension. -/ -theorem LinearEquiv.rank_map_eq (f : M ≃ₗ[R] M₁) (p : Submodule R M) : - Module.rank R (p.map (f : M →ₗ[R] M₁)) = Module.rank R p := - (f.submoduleMap p).rank_eq.symm -#align linear_equiv.rank_map_eq LinearEquiv.rank_map_eq - -variable (R M) - -@[simp] -theorem rank_top : Module.rank R (⊤ : Submodule R M) = Module.rank R M := by - have : (⊤ : Submodule R M) ≃ₗ[R] M := LinearEquiv.ofTop ⊤ rfl - rw [this.rank_eq] -#align rank_top rank_top - -variable {R M} - -theorem rank_range_of_surjective (f : M →ₗ[R] M') (h : Surjective f) : - Module.rank R (LinearMap.range f) = Module.rank R M' := - by rw [LinearMap.range_eq_top.2 h, rank_top] -#align rank_range_of_surjective rank_range_of_surjective - -theorem rank_submodule_le (s : Submodule R M) : Module.rank R s ≤ Module.rank R M := by - rw [← rank_top R M] - exact rank_le_of_submodule _ _ le_top -#align rank_submodule_le rank_submodule_le - -theorem LinearMap.rank_le_of_surjective (f : M →ₗ[R] M₁) (h : Surjective f) : - Module.rank R M₁ ≤ Module.rank R M := by - rw [← rank_range_of_surjective f h] - apply rank_range_le -#align linear_map.rank_le_of_surjective LinearMap.rank_le_of_surjective - -theorem rank_quotient_le (p : Submodule R M) : Module.rank R (M ⧸ p) ≤ Module.rank R M := - (mkQ p).rank_le_of_surjective (surjective_quot_mk _) -#align rank_quotient_le rank_quotient_le - -variable [Nontrivial R] - -variable (R M M') - -open LinearMap in -theorem lift_rank_add_lift_rank_le_rank_prod : - lift.{v'} (Module.rank R M) + lift.{v} (Module.rank R M') ≤ Module.rank R (M × M') := by - convert rank_quotient_add_rank_le (ker <| LinearMap.fst R M M') - · refine Eq.trans ?_ (lift_id'.{v, v'} _) - rw [(quotKerEquivRange _).lift_rank_eq, - rank_range_of_surjective _ fst_surjective, lift_umax.{v, v'}] - · refine Eq.trans ?_ (lift_id'.{v', v} _) - rw [ker_fst, ← (LinearEquiv.ofInjective _ <| inr_injective (M := M) (M₂ := M')).lift_rank_eq, - lift_umax.{v', v}] - -theorem rank_add_rank_le_rank_prod : - Module.rank R M + Module.rank R M₁ ≤ Module.rank R (M × M₁) := by - convert ← lift_rank_add_lift_rank_le_rank_prod R M M₁ <;> apply lift_id - -variable {R M M'} - -namespace LinearIndependent - -theorem cardinal_lift_le_rank {ι : Type w} {v : ι → M} - (hv : LinearIndependent R v) : - Cardinal.lift.{v} #ι ≤ Cardinal.lift.{w} (Module.rank R M) := by - rw [Module.rank] - refine le_trans ?_ (lift_le.mpr <| le_ciSup (bddAbove_range.{v, v} _) ⟨_, hv.coe_range⟩) - exact lift_mk_le'.mpr ⟨(Equiv.ofInjective _ hv.injective).toEmbedding⟩ -#align cardinal_lift_le_rank_of_linear_independent LinearIndependent.cardinal_lift_le_rank -#align cardinal_lift_le_rank_of_linear_independent' LinearIndependent.cardinal_lift_le_rank - -lemma aleph0_le_rank {ι : Type w} [Infinite ι] {v : ι → M} - (hv : LinearIndependent R v) : ℵ₀ ≤ Module.rank R M := - aleph0_le_lift.mp <| (aleph0_le_lift.mpr <| aleph0_le_mk ι).trans hv.cardinal_lift_le_rank - -theorem cardinal_le_rank {ι : Type v} {v : ι → M} - (hv : LinearIndependent R v) : #ι ≤ Module.rank R M := by - simpa using hv.cardinal_lift_le_rank -#align cardinal_le_rank_of_linear_independent LinearIndependent.cardinal_le_rank - -theorem cardinal_le_rank' {s : Set M} - (hs : LinearIndependent R (fun x => x : s → M)) : #s ≤ Module.rank R M := - hs.cardinal_le_rank -#align cardinal_le_rank_of_linear_independent' LinearIndependent.cardinal_le_rank' - -end LinearIndependent - -@[deprecated] -alias cardinal_lift_le_rank_of_linearIndependent := LinearIndependent.cardinal_lift_le_rank -@[deprecated] -alias cardinal_lift_le_rank_of_linearIndependent' := LinearIndependent.cardinal_lift_le_rank -@[deprecated] alias cardinal_le_rank_of_linearIndependent := LinearIndependent.cardinal_le_rank -@[deprecated] alias cardinal_le_rank_of_linearIndependent' := LinearIndependent.cardinal_le_rank' - -variable (R M) - -@[simp] -theorem rank_punit : Module.rank R PUnit = 0 := by - rw [← bot_eq_zero, ← le_bot_iff, Module.rank_def] - apply ciSup_le' - rintro ⟨s, li⟩ - rw [le_bot_iff, bot_eq_zero, Cardinal.mk_emptyCollection_iff, Subtype.coe_mk] - by_contra h - obtain ⟨a, ha⟩ := nonempty_iff_ne_empty.2 h - simpa using LinearIndependent.ne_zero (⟨a, ha⟩ : s) li -#align rank_punit rank_punit - -@[simp] -theorem rank_bot : Module.rank R (⊥ : Submodule R M) = 0 := by - have : (⊥ : Submodule R M) ≃ₗ[R] PUnit := botEquivPUnit - rw [this.rank_eq, rank_punit] -#align rank_bot rank_bot - -variable {R M} - -theorem exists_mem_ne_zero_of_rank_pos {s : Submodule R M} (h : 0 < Module.rank R s) : - ∃ b : M, b ∈ s ∧ b ≠ 0 := - exists_mem_ne_zero_of_ne_bot fun eq => by rw [eq, rank_bot] at h; exact lt_irrefl _ h -#align exists_mem_ne_zero_of_rank_pos exists_mem_ne_zero_of_rank_pos - -theorem CompleteLattice.Independent.subtype_ne_bot_le_rank [NoZeroSMulDivisors R M] - {V : ι → Submodule R M} (hV : CompleteLattice.Independent V) : - Cardinal.lift.{v} #{ i : ι // V i ≠ ⊥ } ≤ Cardinal.lift.{w} (Module.rank R M) := by - set I := { i : ι // V i ≠ ⊥ } - have hI : ∀ i : I, ∃ v ∈ V i, v ≠ (0 : M) := by - intro i - rw [← Submodule.ne_bot_iff] - exact i.prop - choose v hvV hv using hI - have : LinearIndependent R v := (hV.comp Subtype.coe_injective).linearIndependent _ hvV hv - exact this.cardinal_lift_le_rank -#align complete_lattice.independent.subtype_ne_bot_le_rank CompleteLattice.Independent.subtype_ne_bot_le_rank - -end - -section RankZero - -variable {R : Type u} {M : Type v} - -variable [Ring R] [AddCommGroup M] [Module R M] - -@[nontriviality, simp] -theorem rank_subsingleton [Subsingleton R] : Module.rank R M = 1 := by - haveI := Module.subsingleton R M - have : Nonempty { s : Set M // LinearIndependent R ((↑) : s → M) } := - ⟨⟨∅, linearIndependent_empty _ _⟩⟩ - rw [Module.rank_def, ciSup_eq_of_forall_le_of_forall_lt_exists_gt] - · rintro ⟨s, hs⟩ - rw [Cardinal.mk_le_one_iff_set_subsingleton] - apply subsingleton_of_subsingleton - intro w hw - refine' ⟨⟨{0}, _⟩, _⟩ - · rw [linearIndependent_iff'] - intros - exact Subsingleton.elim _ _ - · exact hw.trans_eq (Cardinal.mk_singleton _).symm -#align rank_subsingleton rank_subsingleton - -variable [NoZeroSMulDivisors R M] - -theorem rank_pos [Nontrivial M] : 0 < Module.rank R M := by - obtain ⟨x, hx⟩ := exists_ne (0 : M) - suffices 1 ≤ Module.rank R M by exact zero_lt_one.trans_le this - letI := Module.nontrivial R M - suffices LinearIndependent R fun y : ({x} : Set M) => (y : M) by - simpa using this.cardinal_le_rank - exact linearIndependent_singleton hx -#align rank_pos rank_pos - -variable [Nontrivial R] - -/-- See `rank_zero_iff` for a stronger version with `NoZeroSMulDivisor R M`. -/ -lemma rank_eq_zero_iff {R M} [Ring R] [AddCommGroup M] [Module R M] : - Module.rank R M = 0 ↔ ∀ x : M, ∃ a : R, a ≠ 0 ∧ a • x = 0 := by - nontriviality R - constructor - · contrapose! - rintro ⟨x, hx⟩ - rw [← Cardinal.one_le_iff_ne_zero] - have : LinearIndependent R (fun _ : Unit ↦ x) - · exact linearIndependent_iff.mpr (fun l hl ↦ Finsupp.unique_ext <| not_not.mp fun H ↦ - hx _ H ((Finsupp.total_unique _ _ _).symm.trans hl)) - simpa using this.cardinal_lift_le_rank - · intro h - rw [← le_zero_iff, Module.rank_def] - apply ciSup_le' - intro ⟨s, hs⟩ - rw [nonpos_iff_eq_zero, Cardinal.mk_eq_zero_iff, ← not_nonempty_iff] - rintro ⟨i : s⟩ - obtain ⟨a, ha, ha'⟩ := h i - apply ha - simpa using FunLike.congr_fun (linearIndependent_iff.mp hs (Finsupp.single i a) (by simpa)) i - -theorem rank_zero_iff_forall_zero : Module.rank R M = 0 ↔ ∀ x : M, x = 0 := by - simp_rw [rank_eq_zero_iff, smul_eq_zero, and_or_left, not_and_self_iff, false_or, - exists_and_right, and_iff_right (exists_ne (0 : R))] -#align rank_zero_iff_forall_zero rank_zero_iff_forall_zero - -lemma rank_eq_zero_iff_isTorsion {R M} [CommRing R] [IsDomain R] [AddCommGroup M] [Module R M] : - Module.rank R M = 0 ↔ Module.IsTorsion R M := by - rw [Module.IsTorsion, rank_eq_zero_iff] - simp [mem_nonZeroDivisors_iff_ne_zero] - -theorem rank_quotient_eq_of_le_torsion {R M} [CommRing R] [AddCommGroup M] [Module R M] - {N : Submodule R M} (hN : N ≤ torsion R M) : Module.rank R (M ⧸ N) = Module.rank R M := - (rank_quotient_le N).antisymm <| by - nontriviality R - rw [Module.rank] - have := nonempty_linearIndependent_set R M - refine ciSup_le fun ⟨s, hs⟩ ↦ LinearIndependent.cardinal_le_rank (v := (N.mkQ ·)) ?_ - rw [linearIndependent_iff'] at hs ⊢ - simp_rw [← map_smul, ← map_sum, mkQ_apply, Quotient.mk_eq_zero] - intro t g hg i hi - obtain ⟨r, hg⟩ := hN hg - simp_rw [Finset.smul_sum, Submonoid.smul_def, smul_smul] at hg - exact r.prop _ (mul_comm (g i) r ▸ hs t _ hg i hi) - -/-- See `rank_subsingleton` for the reason that `Nontrivial R` is needed. -Also see `rank_eq_zero_iff` for the version without `NoZeroSMulDivisor R M`. -/ -theorem rank_zero_iff : Module.rank R M = 0 ↔ Subsingleton M := - rank_zero_iff_forall_zero.trans (subsingleton_iff_forall_eq 0).symm -#align rank_zero_iff rank_zero_iff - -theorem rank_pos_iff_exists_ne_zero : 0 < Module.rank R M ↔ ∃ x : M, x ≠ 0 := by - rw [← not_iff_not] - simpa using rank_zero_iff_forall_zero -#align rank_pos_iff_exists_ne_zero rank_pos_iff_exists_ne_zero - -theorem rank_pos_iff_nontrivial : 0 < Module.rank R M ↔ Nontrivial M := - rank_pos_iff_exists_ne_zero.trans (nontrivial_iff_exists_ne 0).symm -#align rank_pos_iff_nontrivial rank_pos_iff_nontrivial - -end RankZero - -section SurjectiveInjective - -section Module - -variable {R : Type w} {M : Type v} [Ring R] [AddCommGroup M] [Module R M] - {R' : Type w'} {M' : Type v'} [Ring R'] [AddCommGroup M'] [Module R' M'] - -/-- If `M / R` and `M' / R'` are modules, `i : R' → R` is a map which sends non-zero elements to -non-zero elements, `j : M →+ M'` is an injective group homomorphism, such that the scalar -multiplications on `M` and `M'` are compatible, then the rank of `M / R` is smaller than or equal to -the rank of `M' / R'`. As a special case, taking `R = R'` it is -`LinearMap.lift_rank_le_of_injective`. -/ -theorem lift_rank_le_of_injective_injective (i : R' → R) (j : M →+ M') - (hi : ∀ r, i r = 0 → r = 0) (hj : Injective j) - (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : - lift.{v'} (Module.rank R M) ≤ lift.{v} (Module.rank R' M') := by - simp_rw [Module.rank, lift_iSup (bddAbove_range.{v', v'} _), lift_iSup (bddAbove_range.{v, v} _)] - exact ciSup_mono' (bddAbove_range.{v', v} _) fun ⟨s, h⟩ ↦ ⟨⟨j '' s, - (h.map_of_injective_injective i j hi (fun _ _ ↦ hj <| by rwa [j.map_zero]) hc).image⟩, - lift_mk_le'.mpr ⟨(Equiv.Set.image j s hj).toEmbedding⟩⟩ - -/-- If `M / R` and `M' / R'` are modules, `i : R → R'` is a surjective map which maps zero to zero, -`j : M →+ M'` is an injective group homomorphism, such that the scalar multiplications on `M` and -`M'` are compatible, then the rank of `M / R` is smaller than or equal to the rank of `M' / R'`. -As a special case, taking `R = R'` it is `LinearMap.lift_rank_le_of_injective`. -/ -theorem lift_rank_le_of_surjective_injective (i : ZeroHom R R') (j : M →+ M') - (hi : Surjective i) (hj : Injective j) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : - lift.{v'} (Module.rank R M) ≤ lift.{v} (Module.rank R' M') := by - obtain ⟨i', hi'⟩ := hi.hasRightInverse - refine lift_rank_le_of_injective_injective i' j (fun _ h ↦ ?_) hj fun r m ↦ ?_ - · apply_fun i at h - rwa [hi', i.map_zero] at h - rw [hc (i' r) m, hi'] - -/-- If `M / R` and `M' / R'` are modules, `i : R → R'` is a bijective map which maps zero to zero, -`j : M ≃+ M'` is a group isomorphism, such that the scalar multiplications on `M` and `M'` are -compatible, then the rank of `M / R` is equal to the rank of `M' / R'`. -As a special case, taking `R = R'` it is `LinearEquiv.lift_rank_eq`. -/ -theorem lift_rank_eq_of_equiv_equiv (i : ZeroHom R R') (j : M ≃+ M') - (hi : Bijective i) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : - lift.{v'} (Module.rank R M) = lift.{v} (Module.rank R' M') := - (lift_rank_le_of_surjective_injective i j hi.2 j.injective hc).antisymm <| - lift_rank_le_of_injective_injective i j.symm (fun _ _ ↦ hi.1 <| by rwa [i.map_zero]) - j.symm.injective fun _ _ ↦ j.symm_apply_eq.2 <| by erw [hc, j.apply_symm_apply] - -variable {M' : Type v} [Ring R'] [AddCommGroup M'] [Module R' M'] - -/-- The same-universe version of `lift_rank_le_of_injective_injective`. -/ -theorem rank_le_of_injective_injective (i : R' → R) (j : M →+ M') - (hi : ∀ r, i r = 0 → r = 0) (hj : Injective j) - (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : - Module.rank R M ≤ Module.rank R' M' := by - simpa only [lift_id] using lift_rank_le_of_injective_injective i j hi hj hc - -/-- The same-universe version of `lift_rank_le_of_surjective_injective`. -/ -theorem rank_le_of_surjective_injective (i : ZeroHom R R') (j : M →+ M') - (hi : Surjective i) (hj : Injective j) - (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : - Module.rank R M ≤ Module.rank R' M' := by - simpa only [lift_id] using lift_rank_le_of_surjective_injective i j hi hj hc - -/-- The same-universe version of `lift_rank_eq_of_equiv_equiv`. -/ -theorem rank_eq_of_equiv_equiv (i : ZeroHom R R') (j : M ≃+ M') - (hi : Bijective i) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : - Module.rank R M = Module.rank R' M' := by - simpa only [lift_id] using lift_rank_eq_of_equiv_equiv i j hi hc - -end Module - -namespace Algebra - -variable {R : Type w} {S : Type v} [CommRing R] [Ring S] [Algebra R S] - {R' : Type w'} {S' : Type v'} [CommRing R'] [Ring S'] [Algebra R' S'] - -/-- If `S / R` and `S' / R'` are algebras, `i : R' →+* R` and `j : S →+* S'` are injective ring -homorphisms, such that `R' → R → S → S'` and `R' → S'` commute, then the rank of `S / R` is -smaller than or equal to the rank of `S' / R'`. -/ -theorem lift_rank_le_of_injective_injective - (i : R' →+* R) (j : S →+* S') (hi : Injective i) (hj : Injective j) - (hc : (j.comp (algebraMap R S)).comp i = algebraMap R' S') : - lift.{v'} (Module.rank R S) ≤ lift.{v} (Module.rank R' S') := by - refine _root_.lift_rank_le_of_injective_injective i j - (fun _ _ ↦ hi <| by rwa [i.map_zero]) hj fun r _ ↦ ?_ - have := congr($hc r) - simp only [RingHom.coe_comp, comp_apply] at this - simp_rw [smul_def, AddMonoidHom.coe_coe, map_mul, this] - -/-- If `S / R` and `S' / R'` are algebras, `i : R →+* R'` is a surjective ring homomorphism, -`j : S →+* S'` is an injective ring homorphism, such that `R → R' → S'` and `R → S → S'` commute, -then the rank of `S / R` is smaller than or equal to the rank of `S' / R'`. -/ -theorem lift_rank_le_of_surjective_injective - (i : R →+* R') (j : S →+* S') (hi : Surjective i) (hj : Injective j) - (hc : (algebraMap R' S').comp i = j.comp (algebraMap R S)) : - lift.{v'} (Module.rank R S) ≤ lift.{v} (Module.rank R' S') := by - refine _root_.lift_rank_le_of_surjective_injective i j hi hj fun r _ ↦ ?_ - have := congr($hc r) - simp only [RingHom.coe_comp, comp_apply] at this - simp only [smul_def, AddMonoidHom.coe_coe, map_mul, ZeroHom.coe_coe, this] - -/-- If `S / R` and `S' / R'` are algebras, `i : R ≃+* R'` and `j : S ≃+* S'` are -ring isomorphisms, such that `R → R' → S'` and `R → S → S'` commute, -then the rank of `S / R` is equal to the rank of `S' / R'`. -/ -theorem lift_rank_eq_of_equiv_equiv (i : R ≃+* R') (j : S ≃+* S') - (hc : (algebraMap R' S').comp i.toRingHom = j.toRingHom.comp (algebraMap R S)) : - lift.{v'} (Module.rank R S) = lift.{v} (Module.rank R' S') := by - refine _root_.lift_rank_eq_of_equiv_equiv i j i.bijective fun r _ ↦ ?_ - have := congr($hc r) - simp only [RingEquiv.toRingHom_eq_coe, RingHom.coe_comp, RingHom.coe_coe, comp_apply] at this - simp only [smul_def, RingEquiv.coe_toAddEquiv, map_mul, ZeroHom.coe_coe, this] - -variable {S' : Type v} [CommRing R'] [Ring S'] [Algebra R' S'] - -/-- The same-universe version of `Algebra.lift_rank_le_of_injective_injective`. -/ -theorem rank_le_of_injective_injective - (i : R' →+* R) (j : S →+* S') (hi : Injective i) (hj : Injective j) - (hc : (j.comp (algebraMap R S)).comp i = algebraMap R' S') : - Module.rank R S ≤ Module.rank R' S' := by - simpa only [lift_id] using lift_rank_le_of_injective_injective i j hi hj hc - -/-- The same-universe version of `Algebra.lift_rank_le_of_surjective_injective`. -/ -theorem rank_le_of_surjective_injective - (i : R →+* R') (j : S →+* S') (hi : Surjective i) (hj : Injective j) - (hc : (algebraMap R' S').comp i = j.comp (algebraMap R S)) : - Module.rank R S ≤ Module.rank R' S' := by - simpa only [lift_id] using lift_rank_le_of_surjective_injective i j hi hj hc - -/-- The same-universe version of `Algebra.lift_rank_eq_of_equiv_equiv`. -/ -theorem rank_eq_of_equiv_equiv (i : R ≃+* R') (j : S ≃+* S') - (hc : (algebraMap R' S').comp i.toRingHom = j.toRingHom.comp (algebraMap R S)) : - Module.rank R S = Module.rank R' S' := by - simpa only [lift_id] using lift_rank_eq_of_equiv_equiv i j hc - -end Algebra - -end SurjectiveInjective - -section InvariantBasisNumber - -variable {R : Type u} [Ring R] [InvariantBasisNumber R] - -variable {M : Type v} [AddCommGroup M] [Module R M] - -/-- The dimension theorem: if `v` and `v'` are two bases, their index types -have the same cardinalities. -/ -theorem mk_eq_mk_of_basis (v : Basis ι R M) (v' : Basis ι' R M) : - Cardinal.lift.{w'} #ι = Cardinal.lift.{w} #ι' := by - classical - haveI := nontrivial_of_invariantBasisNumber R - cases fintypeOrInfinite ι - · -- `v` is a finite basis, so by `basis_finite_of_finite_spans` so is `v'`. - -- haveI : Finite (range v) := Set.finite_range v - haveI := basis_finite_of_finite_spans _ (Set.finite_range v) v.span_eq v' - cases nonempty_fintype ι' - -- We clean up a little: - rw [Cardinal.mk_fintype, Cardinal.mk_fintype] - simp only [Cardinal.lift_natCast, Cardinal.natCast_inj] - -- Now we can use invariant basis number to show they have the same cardinality. - apply card_eq_of_linearEquiv R - exact - (Finsupp.linearEquivFunOnFinite R R ι).symm.trans v.repr.symm ≪≫ₗ v'.repr ≪≫ₗ - Finsupp.linearEquivFunOnFinite R R ι' - · -- `v` is an infinite basis, - -- so by `infinite_basis_le_maximal_linearIndependent`, `v'` is at least as big, - -- and then applying `infinite_basis_le_maximal_linearIndependent` again - -- we see they have the same cardinality. - have w₁ := infinite_basis_le_maximal_linearIndependent' v _ v'.linearIndependent v'.maximal - rcases Cardinal.lift_mk_le'.mp w₁ with ⟨f⟩ - haveI : Infinite ι' := Infinite.of_injective f f.2 - have w₂ := infinite_basis_le_maximal_linearIndependent' v' _ v.linearIndependent v.maximal - exact le_antisymm w₁ w₂ -#align mk_eq_mk_of_basis mk_eq_mk_of_basis - -/-- Given two bases indexed by `ι` and `ι'` of an `R`-module, where `R` satisfies the invariant -basis number property, an equiv `ι ≃ ι'`. -/ -def Basis.indexEquiv (v : Basis ι R M) (v' : Basis ι' R M) : ι ≃ ι' := - (Cardinal.lift_mk_eq'.1 <| mk_eq_mk_of_basis v v').some -#align basis.index_equiv Basis.indexEquiv - -theorem mk_eq_mk_of_basis' {ι' : Type w} (v : Basis ι R M) (v' : Basis ι' R M) : #ι = #ι' := - Cardinal.lift_inj.1 <| mk_eq_mk_of_basis v v' -#align mk_eq_mk_of_basis' mk_eq_mk_of_basis' - -end InvariantBasisNumber - -section RankCondition - -variable {R : Type u} [Ring R] [RankCondition R] - -variable {M : Type v} [AddCommGroup M] [Module R M] - -/-- An auxiliary lemma for `Basis.le_span`. - -If `R` satisfies the rank condition, -then for any finite basis `b : Basis ι R M`, -and any finite spanning set `w : Set M`, -the cardinality of `ι` is bounded by the cardinality of `w`. --/ -theorem Basis.le_span'' {ι : Type*} [Fintype ι] (b : Basis ι R M) {w : Set M} [Fintype w] - (s : span R w = ⊤) : Fintype.card ι ≤ Fintype.card w := by - -- We construct a surjective linear map `(w → R) →ₗ[R] (ι → R)`, - -- by expressing a linear combination in `w` as a linear combination in `ι`. - fapply card_le_of_surjective' R - · exact b.repr.toLinearMap.comp (Finsupp.total w M R (↑)) - · apply Surjective.comp (g := b.repr.toLinearMap) - apply LinearEquiv.surjective - rw [← LinearMap.range_eq_top, Finsupp.range_total] - simpa using s -#align basis.le_span'' Basis.le_span'' - -/-- -Another auxiliary lemma for `Basis.le_span`, which does not require assuming the basis is finite, -but still assumes we have a finite spanning set. --/ -theorem basis_le_span' {ι : Type*} (b : Basis ι R M) {w : Set M} [Fintype w] (s : span R w = ⊤) : - #ι ≤ Fintype.card w := by - haveI := nontrivial_of_invariantBasisNumber R - haveI := basis_finite_of_finite_spans w (toFinite _) s b - cases nonempty_fintype ι - rw [Cardinal.mk_fintype ι] - simp only [Cardinal.natCast_le] - exact Basis.le_span'' b s -#align basis_le_span' basis_le_span' - --- Note that if `R` satisfies the strong rank condition, --- this also follows from `linearIndependent_le_span` below. -/-- If `R` satisfies the rank condition, -then the cardinality of any basis is bounded by the cardinality of any spanning set. --/ -theorem Basis.le_span {J : Set M} (v : Basis ι R M) (hJ : span R J = ⊤) : #(range v) ≤ #J := by - haveI := nontrivial_of_invariantBasisNumber R - cases fintypeOrInfinite J - · rw [← Cardinal.lift_le, Cardinal.mk_range_eq_of_injective v.injective, Cardinal.mk_fintype J] - convert Cardinal.lift_le.{v}.2 (basis_le_span' v hJ) - simp - · let S : J → Set ι := fun j => ↑(v.repr j).support - let S' : J → Set M := fun j => v '' S j - have hs : range v ⊆ ⋃ j, S' j := by - intro b hb - rcases mem_range.1 hb with ⟨i, hi⟩ - have : span R J ≤ comap v.repr.toLinearMap (Finsupp.supported R R (⋃ j, S j)) := - span_le.2 fun j hj x hx => ⟨_, ⟨⟨j, hj⟩, rfl⟩, hx⟩ - rw [hJ] at this - replace : v.repr (v i) ∈ Finsupp.supported R R (⋃ j, S j) := this trivial - rw [v.repr_self, Finsupp.mem_supported, Finsupp.support_single_ne_zero _ one_ne_zero] at this - · subst b - rcases mem_iUnion.1 (this (Finset.mem_singleton_self _)) with ⟨j, hj⟩ - exact mem_iUnion.2 ⟨j, (mem_image _ _ _).2 ⟨i, hj, rfl⟩⟩ - refine' le_of_not_lt fun IJ => _ - suffices #(⋃ j, S' j) < #(range v) by exact not_le_of_lt this ⟨Set.embeddingOfSubset _ _ hs⟩ - refine' lt_of_le_of_lt (le_trans Cardinal.mk_iUnion_le_sum_mk - (Cardinal.sum_le_sum _ (fun _ => ℵ₀) _)) _ - · exact fun j => (Cardinal.lt_aleph0_of_finite _).le - · simpa -#align basis.le_span Basis.le_span - -end RankCondition - -section StrongRankCondition - -variable {R : Type u} [Ring R] [StrongRankCondition R] - -variable {M : Type v} [AddCommGroup M] [Module R M] - -open Submodule - --- An auxiliary lemma for `linearIndependent_le_span'`, --- with the additional assumption that the linearly independent family is finite. -theorem linearIndependent_le_span_aux' {ι : Type*} [Fintype ι] (v : ι → M) - (i : LinearIndependent R v) (w : Set M) [Fintype w] (s : range v ≤ span R w) : - Fintype.card ι ≤ Fintype.card w := by - -- We construct an injective linear map `(ι → R) →ₗ[R] (w → R)`, - -- by thinking of `f : ι → R` as a linear combination of the finite family `v`, - -- and expressing that (using the axiom of choice) as a linear combination over `w`. - -- We can do this linearly by constructing the map on a basis. - fapply card_le_of_injective' R - · apply Finsupp.total - exact fun i => Span.repr R w ⟨v i, s (mem_range_self i)⟩ - · intro f g h - apply_fun Finsupp.total w M R (↑) at h - simp only [Finsupp.total_total, Submodule.coe_mk, Span.finsupp_total_repr] at h - rw [← sub_eq_zero, ← LinearMap.map_sub] at h - exact sub_eq_zero.mp (linearIndependent_iff.mp i _ h) -#align linear_independent_le_span_aux' linearIndependent_le_span_aux' - -/-- If `R` satisfies the strong rank condition, -then any linearly independent family `v : ι → M` -contained in the span of some finite `w : Set M`, -is itself finite. --/ -lemma LinearIndependent.finite_of_le_span_finite {ι : Type*} (v : ι → M) (i : LinearIndependent R v) - (w : Set M) [Finite w] (s : range v ≤ span R w) : Finite ι := - letI := Fintype.ofFinite w - Fintype.finite <| fintypeOfFinsetCardLe (Fintype.card w) fun t => by - let v' := fun x : (t : Set ι) => v x - have i' : LinearIndependent R v' := i.comp _ Subtype.val_injective - have s' : range v' ≤ span R w := (range_comp_subset_range _ _).trans s - simpa using linearIndependent_le_span_aux' v' i' w s' -#align linear_independent_fintype_of_le_span_fintype LinearIndependent.finite_of_le_span_finite - -/-- If `R` satisfies the strong rank condition, -then for any linearly independent family `v : ι → M` -contained in the span of some finite `w : Set M`, -the cardinality of `ι` is bounded by the cardinality of `w`. --/ -theorem linearIndependent_le_span' {ι : Type*} (v : ι → M) (i : LinearIndependent R v) (w : Set M) - [Fintype w] (s : range v ≤ span R w) : #ι ≤ Fintype.card w := by - haveI : Finite ι := i.finite_of_le_span_finite v w s - letI := Fintype.ofFinite ι - rw [Cardinal.mk_fintype] - simp only [Cardinal.natCast_le] - exact linearIndependent_le_span_aux' v i w s -#align linear_independent_le_span' linearIndependent_le_span' - -/-- If `R` satisfies the strong rank condition, -then for any linearly independent family `v : ι → M` -and any finite spanning set `w : Set M`, -the cardinality of `ι` is bounded by the cardinality of `w`. --/ -theorem linearIndependent_le_span {ι : Type*} (v : ι → M) (i : LinearIndependent R v) (w : Set M) - [Fintype w] (s : span R w = ⊤) : #ι ≤ Fintype.card w := by - apply linearIndependent_le_span' v i w - rw [s] - exact le_top -#align linear_independent_le_span linearIndependent_le_span - -/-- A version of `linearIndependent_le_span` for `Finset`. -/ -theorem linearIndependent_le_span_finset {ι : Type*} (v : ι → M) (i : LinearIndependent R v) - (w : Finset M) (s : span R (w : Set M) = ⊤) : #ι ≤ w.card := by - simpa only [Finset.coe_sort_coe, Fintype.card_coe] using linearIndependent_le_span v i w s -#align linear_independent_le_span_finset linearIndependent_le_span_finset - -/-- An auxiliary lemma for `linearIndependent_le_basis`: -we handle the case where the basis `b` is infinite. --/ -theorem linearIndependent_le_infinite_basis {ι : Type w} (b : Basis ι R M) [Infinite ι] {κ : Type w} - (v : κ → M) (i : LinearIndependent R v) : #κ ≤ #ι := by - classical - by_contra h - rw [not_le, ← Cardinal.mk_finset_of_infinite ι] at h - let Φ := fun k : κ => (b.repr (v k)).support - obtain ⟨s, w : Infinite ↑(Φ ⁻¹' {s})⟩ := Cardinal.exists_infinite_fiber Φ h (by infer_instance) - let v' := fun k : Φ ⁻¹' {s} => v k - have i' : LinearIndependent R v' := i.comp _ Subtype.val_injective - have w' : Finite (Φ ⁻¹' {s}) := by - apply i'.finite_of_le_span_finite v' (s.image b) - rintro m ⟨⟨p, ⟨rfl⟩⟩, rfl⟩ - simp only [SetLike.mem_coe, Subtype.coe_mk, Finset.coe_image] - apply Basis.mem_span_repr_support - exact w.false -#align linear_independent_le_infinite_basis linearIndependent_le_infinite_basis - -/-- Over any ring `R` satisfying the strong rank condition, -if `b` is a basis for a module `M`, -and `s` is a linearly independent set, -then the cardinality of `s` is bounded by the cardinality of `b`. --/ -theorem linearIndependent_le_basis {ι : Type w} (b : Basis ι R M) {κ : Type w} (v : κ → M) - (i : LinearIndependent R v) : #κ ≤ #ι := by - classical - -- We split into cases depending on whether `ι` is infinite. - cases fintypeOrInfinite ι - · rw [Cardinal.mk_fintype ι] -- When `ι` is finite, we have `linearIndependent_le_span`, - haveI : Nontrivial R := nontrivial_of_invariantBasisNumber R - rw [Fintype.card_congr (Equiv.ofInjective b b.injective)] - exact linearIndependent_le_span v i (range b) b.span_eq - · -- and otherwise we have `linearIndependent_le_infinite_basis`. - exact linearIndependent_le_infinite_basis b v i -#align linear_independent_le_basis linearIndependent_le_basis - -/-- Let `R` satisfy the strong rank condition. If `m` elements of a free rank `n` `R`-module are -linearly independent, then `m ≤ n`. -/ -theorem Basis.card_le_card_of_linearIndependent_aux {R : Type*} [Ring R] [StrongRankCondition R] - (n : ℕ) {m : ℕ} (v : Fin m → Fin n → R) : LinearIndependent R v → m ≤ n := fun h => by - simpa using linearIndependent_le_basis (Pi.basisFun R (Fin n)) v h -#align basis.card_le_card_of_linear_independent_aux Basis.card_le_card_of_linearIndependent_aux - --- When the basis is not infinite this need not be true! -/-- Over any ring `R` satisfying the strong rank condition, -if `b` is an infinite basis for a module `M`, -then every maximal linearly independent set has the same cardinality as `b`. - -This proof (along with some of the lemmas above) comes from -[Les familles libres maximales d'un module ont-elles le meme cardinal?][lazarus1973] --/ -theorem maximal_linearIndependent_eq_infinite_basis {ι : Type w} (b : Basis ι R M) [Infinite ι] - {κ : Type w} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : #κ = #ι := by - apply le_antisymm - · exact linearIndependent_le_basis b v i - · haveI : Nontrivial R := nontrivial_of_invariantBasisNumber R - exact infinite_basis_le_maximal_linearIndependent b v i m -#align maximal_linear_independent_eq_infinite_basis maximal_linearIndependent_eq_infinite_basis - -theorem Basis.mk_eq_rank'' {ι : Type v} (v : Basis ι R M) : #ι = Module.rank R M := by - haveI := nontrivial_of_invariantBasisNumber R - rw [Module.rank_def] - apply le_antisymm - · trans - swap - · apply le_ciSup (Cardinal.bddAbove_range.{v, v} _) - exact - ⟨Set.range v, by - convert v.reindexRange.linearIndependent - ext - simp⟩ - · exact (Cardinal.mk_range_eq v v.injective).ge - · apply ciSup_le' - rintro ⟨s, li⟩ - apply linearIndependent_le_basis v _ li -#align basis.mk_eq_rank'' Basis.mk_eq_rank'' - -theorem Basis.mk_range_eq_rank (v : Basis ι R M) : #(range v) = Module.rank R M := - v.reindexRange.mk_eq_rank'' -#align basis.mk_range_eq_rank Basis.mk_range_eq_rank - -/-- If a vector space has a finite basis, then its dimension (seen as a cardinal) is equal to the -cardinality of the basis. -/ -theorem rank_eq_card_basis {ι : Type w} [Fintype ι] (h : Basis ι R M) : - Module.rank R M = Fintype.card ι := by - classical - haveI := nontrivial_of_invariantBasisNumber R - rw [← h.mk_range_eq_rank, Cardinal.mk_fintype, Set.card_range_of_injective h.injective] -#align rank_eq_card_basis rank_eq_card_basis - -theorem Basis.card_le_card_of_linearIndependent {ι : Type*} [Fintype ι] (b : Basis ι R M) - {ι' : Type*} [Fintype ι'] {v : ι' → M} (hv : LinearIndependent R v) : - Fintype.card ι' ≤ Fintype.card ι := by - letI := nontrivial_of_invariantBasisNumber R - simpa [rank_eq_card_basis b, Cardinal.mk_fintype] using hv.cardinal_lift_le_rank -#align basis.card_le_card_of_linear_independent Basis.card_le_card_of_linearIndependent - -theorem Basis.card_le_card_of_submodule (N : Submodule R M) [Fintype ι] (b : Basis ι R M) - [Fintype ι'] (b' : Basis ι' R N) : Fintype.card ι' ≤ Fintype.card ι := - b.card_le_card_of_linearIndependent (b'.linearIndependent.map' N.subtype N.ker_subtype) -#align basis.card_le_card_of_submodule Basis.card_le_card_of_submodule - -theorem Basis.card_le_card_of_le {N O : Submodule R M} (hNO : N ≤ O) [Fintype ι] (b : Basis ι R O) - [Fintype ι'] (b' : Basis ι' R N) : Fintype.card ι' ≤ Fintype.card ι := - b.card_le_card_of_linearIndependent - (b'.linearIndependent.map' (Submodule.inclusion hNO) (N.ker_inclusion O _)) -#align basis.card_le_card_of_le Basis.card_le_card_of_le - -theorem Basis.mk_eq_rank (v : Basis ι R M) : - Cardinal.lift.{v} #ι = Cardinal.lift.{w} (Module.rank R M) := by - haveI := nontrivial_of_invariantBasisNumber R - rw [← v.mk_range_eq_rank, Cardinal.mk_range_eq_of_injective v.injective] -#align basis.mk_eq_rank Basis.mk_eq_rank - -theorem Basis.mk_eq_rank'.{m} (v : Basis ι R M) : - Cardinal.lift.{max v m} #ι = Cardinal.lift.{max w m} (Module.rank R M) := - Cardinal.lift_umax_eq.{w, v, m}.mpr v.mk_eq_rank -#align basis.mk_eq_rank' Basis.mk_eq_rank' - -/-- If a module has a finite dimension, all bases are indexed by a finite type. -/ -theorem Basis.nonempty_fintype_index_of_rank_lt_aleph0 {ι : Type*} (b : Basis ι R M) - (h : Module.rank R M < ℵ₀) : Nonempty (Fintype ι) := by - rwa [← Cardinal.lift_lt, ← b.mk_eq_rank, Cardinal.lift_aleph0, Cardinal.lift_lt_aleph0, - Cardinal.lt_aleph0_iff_fintype] at h -#align basis.nonempty_fintype_index_of_rank_lt_aleph_0 Basis.nonempty_fintype_index_of_rank_lt_aleph0 - -/-- If a module has a finite dimension, all bases are indexed by a finite type. -/ -noncomputable def Basis.fintypeIndexOfRankLtAleph0 {ι : Type*} (b : Basis ι R M) - (h : Module.rank R M < ℵ₀) : Fintype ι := - Classical.choice (b.nonempty_fintype_index_of_rank_lt_aleph0 h) -#align basis.fintype_index_of_rank_lt_aleph_0 Basis.fintypeIndexOfRankLtAleph0 - -/-- If a module has a finite dimension, all bases are indexed by a finite set. -/ -theorem Basis.finite_index_of_rank_lt_aleph0 {ι : Type*} {s : Set ι} (b : Basis s R M) - (h : Module.rank R M < ℵ₀) : s.Finite := - finite_def.2 (b.nonempty_fintype_index_of_rank_lt_aleph0 h) -#align basis.finite_index_of_rank_lt_aleph_0 Basis.finite_index_of_rank_lt_aleph0 - -theorem rank_span {v : ι → M} (hv : LinearIndependent R v) : - Module.rank R ↑(span R (range v)) = #(range v) := by - haveI := nontrivial_of_invariantBasisNumber R - rw [← Cardinal.lift_inj, ← (Basis.span hv).mk_eq_rank, - Cardinal.mk_range_eq_of_injective (@LinearIndependent.injective ι R M v _ _ _ _ hv)] -#align rank_span rank_span - -theorem rank_span_set {s : Set M} (hs : LinearIndependent R (fun x => x : s → M)) : - Module.rank R ↑(span R s) = #s := by - rw [← @setOf_mem_eq _ s, ← Subtype.range_coe_subtype] - exact rank_span hs -#align rank_span_set rank_span_set - -/-- An induction (and recursion) principle for proving results about all submodules of a fixed -finite free module `M`. A property is true for all submodules of `M` if it satisfies the following -"inductive step": the property is true for a submodule `N` if it's true for all submodules `N'` -of `N` with the property that there exists `0 ≠ x ∈ N` such that the sum `N' + Rx` is direct. -/ -def Submodule.inductionOnRank [IsDomain R] [Finite ι] (b : Basis ι R M) - (P : Submodule R M → Sort*) (ih : ∀ N : Submodule R M, - (∀ N' ≤ N, ∀ x ∈ N, (∀ (c : R), ∀ y ∈ N', c • x + y = (0 : M) → c = 0) → P N') → P N) - (N : Submodule R M) : P N := - letI := Fintype.ofFinite ι - Submodule.inductionOnRankAux b P ih (Fintype.card ι) N fun hs hli => by - simpa using b.card_le_card_of_linearIndependent hli -#align submodule.induction_on_rank Submodule.inductionOnRank - -/-- If `S` a module-finite free `R`-algebra, then the `R`-rank of a nonzero `R`-free -ideal `I` of `S` is the same as the rank of `S`. -/ -theorem Ideal.rank_eq {R S : Type*} [CommRing R] [StrongRankCondition R] [Ring S] [IsDomain S] - [Algebra R S] {n m : Type*} [Fintype n] [Fintype m] (b : Basis n R S) {I : Ideal S} - (hI : I ≠ ⊥) (c : Basis m R I) : Fintype.card m = Fintype.card n := by - obtain ⟨a, ha⟩ := Submodule.nonzero_mem_of_bot_lt (bot_lt_iff_ne_bot.mpr hI) - have : LinearIndependent R fun i => b i • a := by - have hb := b.linearIndependent - rw [Fintype.linearIndependent_iff] at hb ⊢ - intro g hg - apply hb g - simp only [← smul_assoc, ← Finset.sum_smul, smul_eq_zero] at hg - exact hg.resolve_right ha - exact le_antisymm - (b.card_le_card_of_linearIndependent (c.linearIndependent.map' (Submodule.subtype I) - ((LinearMap.ker_eq_bot (f := (Submodule.subtype I : I →ₗ[R] S))).mpr Subtype.coe_injective))) - (c.card_le_card_of_linearIndependent this) -#align ideal.rank_eq Ideal.rank_eq - -variable (R) - -@[simp] -theorem rank_self : Module.rank R R = 1 := by - rw [← Cardinal.lift_inj, ← (Basis.singleton PUnit R).mk_eq_rank, Cardinal.mk_punit] -#align rank_self rank_self - -end StrongRankCondition - -section Free - -variable [Ring K] [StrongRankCondition K] - -variable [AddCommGroup V] [Module K V] [Module.Free K V] - -variable [AddCommGroup V'] [Module K V'] [Module.Free K V'] - -variable [AddCommGroup V₁] [Module K V₁] [Module.Free K V₁] - -namespace Module.Free - -variable (K V) - -/-- The rank of a free module `M` over `R` is the cardinality of `ChooseBasisIndex R M`. -/ -theorem rank_eq_card_chooseBasisIndex : Module.rank K V = #(ChooseBasisIndex K V) := - (chooseBasis K V).mk_eq_rank''.symm -#align module.free.rank_eq_card_choose_basis_index Module.Free.rank_eq_card_chooseBasisIndex - -/-- The rank of a free module `V` over an infinite scalar ring `K` is the cardinality of `V` -whenever `#R < #V`. -/ -lemma rank_eq_mk_of_infinite_lt [Infinite K] (h_lt : lift.{v} #K < lift.{u} #V) : - Module.rank K V = #V := by - have : Infinite V := infinite_iff.mpr <| lift_le.mp <| le_trans (by simp) h_lt.le - have h : lift #V = lift #(ChooseBasisIndex K V →₀ K) := lift_mk_eq'.mpr ⟨(chooseBasis K V).repr⟩ - simp only [mk_finsupp_lift_of_infinite', lift_id', ← rank_eq_card_chooseBasisIndex, lift_max, - lift_lift] at h - refine lift_inj.mp ((max_eq_iff.mp h.symm).resolve_right <| not_and_of_not_left _ ?_).left - exact (lift_umax.{v, u}.symm ▸ h_lt).ne - -end Module.Free - -open Module.Free - -open Cardinal - -/-- Two vector spaces are isomorphic if they have the same dimension. -/ -theorem nonempty_linearEquiv_of_lift_rank_eq - (cnd : Cardinal.lift.{v'} (Module.rank K V) = Cardinal.lift.{v} (Module.rank K V')) : - Nonempty (V ≃ₗ[K] V') := by - obtain ⟨⟨_, B⟩⟩ := Module.Free.exists_basis (R := K) (M := V) - obtain ⟨⟨_, B'⟩⟩ := Module.Free.exists_basis (R := K) (M := V') - have : Cardinal.lift.{v', v} #_ = Cardinal.lift.{v, v'} #_ := by - rw [B.mk_eq_rank'', cnd, B'.mk_eq_rank''] - exact (Cardinal.lift_mk_eq.{v, v', 0}.1 this).map (B.equiv B') -#align nonempty_linear_equiv_of_lift_rank_eq nonempty_linearEquiv_of_lift_rank_eq - -/-- Two vector spaces are isomorphic if they have the same dimension. -/ -theorem nonempty_linearEquiv_of_rank_eq (cond : Module.rank K V = Module.rank K V₁) : - Nonempty (V ≃ₗ[K] V₁) := - nonempty_linearEquiv_of_lift_rank_eq <| congr_arg _ cond -#align nonempty_linear_equiv_of_rank_eq nonempty_linearEquiv_of_rank_eq - -section - -variable (V V' V₁) - -/-- Two vector spaces are isomorphic if they have the same dimension. -/ -def LinearEquiv.ofLiftRankEq - (cond : Cardinal.lift.{v'} (Module.rank K V) = Cardinal.lift.{v} (Module.rank K V')) : - V ≃ₗ[K] V' := - Classical.choice (nonempty_linearEquiv_of_lift_rank_eq cond) -#align linear_equiv.of_lift_rank_eq LinearEquiv.ofLiftRankEq - -/-- Two vector spaces are isomorphic if they have the same dimension. -/ -def LinearEquiv.ofRankEq (cond : Module.rank K V = Module.rank K V₁) : V ≃ₗ[K] V₁ := - Classical.choice (nonempty_linearEquiv_of_rank_eq cond) -#align linear_equiv.of_rank_eq LinearEquiv.ofRankEq - -end - -/-- Two vector spaces are isomorphic if and only if they have the same dimension. -/ -theorem LinearEquiv.nonempty_equiv_iff_lift_rank_eq : Nonempty (V ≃ₗ[K] V') ↔ - Cardinal.lift.{v'} (Module.rank K V) = Cardinal.lift.{v} (Module.rank K V') := - ⟨fun ⟨h⟩ => LinearEquiv.lift_rank_eq h, fun h => nonempty_linearEquiv_of_lift_rank_eq h⟩ -#align linear_equiv.nonempty_equiv_iff_lift_rank_eq LinearEquiv.nonempty_equiv_iff_lift_rank_eq - -/-- Two vector spaces are isomorphic if and only if they have the same dimension. -/ -theorem LinearEquiv.nonempty_equiv_iff_rank_eq : - Nonempty (V ≃ₗ[K] V₁) ↔ Module.rank K V = Module.rank K V₁ := - ⟨fun ⟨h⟩ => LinearEquiv.rank_eq h, fun h => nonempty_linearEquiv_of_rank_eq h⟩ -#align linear_equiv.nonempty_equiv_iff_rank_eq LinearEquiv.nonempty_equiv_iff_rank_eq - -/-- If `M` and `N` are free, then the rank of `M × N` is -`(Module.rank R M).lift + (Module.rank R N).lift`. -/ -@[simp] -theorem rank_prod : Module.rank K (V × V') = - Cardinal.lift.{v'} (Module.rank K V) + Cardinal.lift.{v, v'} (Module.rank K V') := by - simpa [rank_eq_card_chooseBasisIndex K V, rank_eq_card_chooseBasisIndex K V', lift_umax, - lift_umax'] using ((chooseBasis K V).prod (chooseBasis K V')).mk_eq_rank.symm -#align rank_prod rank_prod - -/-- If `M` and `N` are free (and lie in the same universe), the rank of `M × N` is - `(Module.rank R M) + (Module.rank R N)`. -/ -theorem rank_prod' : Module.rank K (V × V₁) = Module.rank K V + Module.rank K V₁ := by simp -#align rank_prod' rank_prod' - -@[simp] -theorem rank_ulift : Module.rank K (ULift.{w} V) = Cardinal.lift.{w} (Module.rank K V) := - Cardinal.lift_injective.{v} <| Eq.symm <| (lift_lift _).trans ULift.moduleEquiv.symm.lift_rank_eq - -section Fintype - -variable [∀ i, AddCommGroup (φ i)] [∀ i, Module K (φ i)] [∀ i, Module.Free K (φ i)] - -open LinearMap - -/-- The rank of a finite product of free modules is the sum of the ranks. -/ --- this result is not true without the freeness assumption -@[simp] -theorem rank_pi [Finite η] : Module.rank K (∀ i, φ i) = - Cardinal.sum fun i => Module.rank K (φ i) := by - cases nonempty_fintype η - let B i := chooseBasis K (φ i) - let b : Basis _ K (∀ i, φ i) := Pi.basis fun i => B i - simp [← b.mk_eq_rank'', fun i => (B i).mk_eq_rank''] -#align rank_pi rank_pi - -variable [Fintype η] - -theorem rank_fun {V η : Type u} [Fintype η] [AddCommGroup V] [Module K V] [Module.Free K V] : - Module.rank K (η → V) = Fintype.card η * Module.rank K V := by - rw [rank_pi, Cardinal.sum_const', Cardinal.mk_fintype] -#align rank_fun rank_fun - -theorem rank_fun_eq_lift_mul : Module.rank K (η → V) = - (Fintype.card η : Cardinal.{max u₁' v}) * Cardinal.lift.{u₁'} (Module.rank K V) := - by rw [rank_pi, Cardinal.sum_const, Cardinal.mk_fintype, Cardinal.lift_natCast] -#align rank_fun_eq_lift_mul rank_fun_eq_lift_mul - -theorem rank_fun' : Module.rank K (η → K) = Fintype.card η := by - rw [rank_fun_eq_lift_mul, rank_self, Cardinal.lift_one, mul_one, Cardinal.natCast_inj] -#align rank_fun' rank_fun' - -theorem rank_fin_fun (n : ℕ) : Module.rank K (Fin n → K) = n := by simp [rank_fun'] -#align rank_fin_fun rank_fin_fun - -end Fintype - --- TODO: merge with the `Finrank` content -/-- An `n`-dimensional `K`-vector space is equivalent to `Fin n → K`. -/ -def finDimVectorspaceEquiv (n : ℕ) (hn : Module.rank K V = n) : V ≃ₗ[K] Fin n → K := by - haveI := nontrivial_of_invariantBasisNumber K - have : Cardinal.lift.{u} (n : Cardinal.{v}) = Cardinal.lift.{v} (n : Cardinal.{u}) := by simp - have hn := Cardinal.lift_inj.{v, u}.2 hn - rw [this] at hn - rw [← @rank_fin_fun K _ _ n] at hn - haveI : Module.Free K (Fin n → K) := Module.Free.pi _ _ - exact Classical.choice (nonempty_linearEquiv_of_lift_rank_eq hn) -#align fin_dim_vectorspace_equiv finDimVectorspaceEquiv - -end Free - -section DivisionRing - -variable [DivisionRing K] [Ring R] [StrongRankCondition R] - -variable [AddCommGroup V] [Module K V] [Module R V] - -variable [AddCommGroup V'] [Module K V'] - -variable [AddCommGroup V₁] [Module K V₁] - -/-- If a vector space has a finite dimension, the index set of `Basis.ofVectorSpace` is finite. -/ -theorem Basis.finite_ofVectorSpaceIndex_of_rank_lt_aleph0 (h : Module.rank K V < ℵ₀) : - (Basis.ofVectorSpaceIndex K V).Finite := - finite_def.2 <| (Basis.ofVectorSpace K V).nonempty_fintype_index_of_rank_lt_aleph0 h -#align basis.finite_of_vector_space_index_of_rank_lt_aleph_0 Basis.finite_ofVectorSpaceIndex_of_rank_lt_aleph0 - --- TODO how far can we generalise this? -theorem rank_span_le (s : Set V) : Module.rank K (span K s) ≤ #s := by - obtain ⟨b, hb, hsab, hlib⟩ := exists_linearIndependent K s - convert Cardinal.mk_le_mk_of_subset hb - rw [← hsab, rank_span_set hlib] -#align rank_span_le rank_span_le - -theorem rank_span_le_of_finite {s : Set V} (hs : s.Finite) : Module.rank R (span R s) ≤ #s := by - rw [Module.rank_def] - apply ciSup_le' - rintro ⟨t, ht⟩ - letI := hs.fintype - simpa [Cardinal.mk_image_eq Subtype.val_injective] using linearIndependent_le_span' _ - (ht.map (f := Submodule.subtype _) (by simp)).image s (fun x ↦ by aesop) - -theorem rank_span_finset_le (s : Finset V) : Module.rank R (span R (s : Set V)) ≤ s.card := by - simpa using rank_span_le_of_finite s.finite_toSet - -theorem rank_span_of_finset (s : Finset V) : Module.rank R (span R (s : Set V)) < ℵ₀ := - (rank_span_finset_le s).trans_lt (Cardinal.nat_lt_aleph0 _) -#align rank_span_of_finset rank_span_of_finset - -theorem rank_quotient_add_rank (p : Submodule K V) : - Module.rank K (V ⧸ p) + Module.rank K p = Module.rank K V := by - classical - let ⟨f⟩ := quotient_prod_linearEquiv p - exact rank_prod'.symm.trans f.rank_eq -#align rank_quotient_add_rank rank_quotient_add_rank - -/-- The **rank-nullity theorem** -/ -theorem rank_range_add_rank_ker (f : V →ₗ[K] V₁) : - Module.rank K (LinearMap.range f) + Module.rank K (LinearMap.ker f) = Module.rank K V := by - haveI := fun p : Submodule K V => Classical.decEq (V ⧸ p) - rw [← f.quotKerEquivRange.rank_eq, rank_quotient_add_rank] -#align rank_range_add_rank_ker rank_range_add_rank_ker - -theorem rank_eq_of_surjective (f : V →ₗ[K] V₁) (h : Surjective f) : - Module.rank K V = Module.rank K V₁ + Module.rank K (LinearMap.ker f) := by - rw [← rank_range_add_rank_ker f, ← rank_range_of_surjective f h] -#align rank_eq_of_surjective rank_eq_of_surjective - -/-- Given a family of `n` linearly independent vectors in a space of dimension `> n`, one may extend -the family by another vector while retaining linear independence. -/ -theorem exists_linearIndependent_cons_of_lt_rank {n : ℕ} {v : Fin n → V} - (hv : LinearIndependent K v) (h : n < Module.rank K V) : - ∃ (x : V), LinearIndependent K (Fin.cons x v) := by - have A : Submodule.span K (range v) ≠ ⊤ := by - intro H - rw [← rank_top, ← H] at h - have : Module.rank K (Submodule.span K (range v)) ≤ n := by - have := Cardinal.mk_range_le_lift (f := v) - simp only [Cardinal.lift_id'] at this - exact (rank_span_le _).trans (this.trans (by simp)) - exact lt_irrefl _ (h.trans_le this) - obtain ⟨x, hx⟩ : ∃ x, x ∉ Submodule.span K (range v) := by - contrapose! A - exact Iff.mpr Submodule.eq_top_iff' A - exact ⟨x, linearIndependent_fin_cons.2 ⟨hv, hx⟩⟩ - -/-- Given a family of `n` linearly independent vectors in a space of dimension `> n`, one may extend -the family by another vector while retaining linear independence. -/ -theorem exists_linearIndependent_snoc_of_lt_rank {n : ℕ} {v : Fin n → V} - (hv : LinearIndependent K v) (h : n < Module.rank K V) : - ∃ (x : V), LinearIndependent K (Fin.snoc v x) := by - simpa [linearIndependent_fin_cons, ← linearIndependent_fin_snoc] - using exists_linearIndependent_cons_of_lt_rank hv h - -/-- Given a nonzero vector in a space of dimension `> 1`, one may find another vector linearly -independent of the first one. -/ -theorem exists_linearIndependent_pair_of_one_lt_rank - (h : 1 < Module.rank K V) {x : V} (hx : x ≠ 0) : - ∃ y, LinearIndependent K ![x, y] := by - obtain ⟨y, hy⟩ := exists_linearIndependent_snoc_of_lt_rank (linearIndependent_unique ![x] hx) h - have : Fin.snoc ![x] y = ![x, y] := Iff.mp List.ofFn_inj rfl - rw [this] at hy - exact ⟨y, hy⟩ - -section - -variable [AddCommGroup V₂] [Module K V₂] - -variable [AddCommGroup V₃] [Module K V₃] - -open LinearMap - -/-- This is mostly an auxiliary lemma for `Submodule.rank_sup_add_rank_inf_eq`. -/ -theorem rank_add_rank_split (db : V₂ →ₗ[K] V) (eb : V₃ →ₗ[K] V) (cd : V₁ →ₗ[K] V₂) - (ce : V₁ →ₗ[K] V₃) (hde : ⊤ ≤ LinearMap.range db ⊔ LinearMap.range eb) (hgd : ker cd = ⊥) - (eq : db.comp cd = eb.comp ce) (eq₂ : ∀ d e, db d = eb e → ∃ c, cd c = d ∧ ce c = e) : - Module.rank K V + Module.rank K V₁ = Module.rank K V₂ + Module.rank K V₃ := by - have hf : Surjective (coprod db eb) := by rwa [← range_eq_top, range_coprod, eq_top_iff] - conv => - rhs - rw [← rank_prod', rank_eq_of_surjective _ hf] - congr 1 - apply LinearEquiv.rank_eq - let L : V₁ →ₗ[K] ker (coprod db eb) := by -- Porting note: this is needed to avoid a timeout - refine' LinearMap.codRestrict _ (prod cd (-ce)) _ - · intro c - simp only [add_eq_zero_iff_eq_neg, LinearMap.prod_apply, mem_ker, Pi.prod, coprod_apply, - neg_neg, map_neg, neg_apply] - exact LinearMap.ext_iff.1 eq c - refine' LinearEquiv.ofBijective L ⟨_, _⟩ - · rw [← ker_eq_bot, ker_codRestrict, ker_prod, hgd, bot_inf_eq] - · rw [← range_eq_top, eq_top_iff, range_codRestrict, ← map_le_iff_le_comap, Submodule.map_top, - range_subtype] - rintro ⟨d, e⟩ - have h := eq₂ d (-e) - simp only [add_eq_zero_iff_eq_neg, LinearMap.prod_apply, mem_ker, SetLike.mem_coe, - Prod.mk.inj_iff, coprod_apply, map_neg, neg_apply, LinearMap.mem_range, Pi.prod] at h ⊢ - intro hde - rcases h hde with ⟨c, h₁, h₂⟩ - refine' ⟨c, h₁, _⟩ - rw [h₂, _root_.neg_neg] -#align rank_add_rank_split rank_add_rank_split - -theorem Submodule.rank_sup_add_rank_inf_eq (s t : Submodule K V) : - Module.rank K (s ⊔ t : Submodule K V) + Module.rank K (s ⊓ t : Submodule K V) = - Module.rank K s + Module.rank K t := - rank_add_rank_split - (inclusion le_sup_left) (inclusion le_sup_right) - (inclusion inf_le_left) (inclusion inf_le_right) - (by - rw [← map_le_map_iff' (ker_subtype <| s ⊔ t), Submodule.map_sup, Submodule.map_top, ← - LinearMap.range_comp, ← LinearMap.range_comp, subtype_comp_inclusion, - subtype_comp_inclusion, range_subtype, range_subtype, range_subtype]) - (ker_inclusion _ _ _) (by ext ⟨x, hx⟩; rfl) - (by - rintro ⟨b₁, hb₁⟩ ⟨b₂, hb₂⟩ eq - obtain rfl : b₁ = b₂ := congr_arg Subtype.val eq - exact ⟨⟨b₁, hb₁, hb₂⟩, rfl, rfl⟩) -#align submodule.rank_sup_add_rank_inf_eq Submodule.rank_sup_add_rank_inf_eq - -theorem Submodule.rank_add_le_rank_add_rank (s t : Submodule K V) : - Module.rank K (s ⊔ t : Submodule K V) ≤ Module.rank K s + Module.rank K t := by - rw [← Submodule.rank_sup_add_rank_inf_eq] - exact self_le_add_right _ _ -#align submodule.rank_add_le_rank_add_rank Submodule.rank_add_le_rank_add_rank - -end - -end DivisionRing - -section DivisionRing - -variable [DivisionRing K] [AddCommGroup V] [Module K V] [AddCommGroup V₁] [Module K V₁] - -variable [AddCommGroup V'] [Module K V'] - -/-- The `ι` indexed basis on `V`, where `ι` is an empty type and `V` is zero-dimensional. - -See also `FiniteDimensional.finBasis`. --/ -def Basis.ofRankEqZero {ι : Type*} [IsEmpty ι] (hV : Module.rank K V = 0) : Basis ι K V := - haveI : Subsingleton V := rank_zero_iff.1 hV - Basis.empty _ -#align basis.of_rank_eq_zero Basis.ofRankEqZero - -@[simp] -theorem Basis.ofRankEqZero_apply {ι : Type*} [IsEmpty ι] (hV : Module.rank K V = 0) (i : ι) : - Basis.ofRankEqZero hV i = 0 := - rfl -#align basis.of_rank_eq_zero_apply Basis.ofRankEqZero_apply - -theorem le_rank_iff_exists_linearIndependent {c : Cardinal} : - c ≤ Module.rank K V ↔ ∃ s : Set V, #s = c ∧ LinearIndependent K ((↑) : s → V) := by - constructor - · intro h - let t := Basis.ofVectorSpace K V - rw [← t.mk_eq_rank'', Cardinal.le_mk_iff_exists_subset] at h - rcases h with ⟨s, hst, hsc⟩ - exact ⟨s, hsc, (ofVectorSpaceIndex.linearIndependent K V).mono hst⟩ - · rintro ⟨s, rfl, si⟩ - exact si.cardinal_le_rank -#align le_rank_iff_exists_linear_independent le_rank_iff_exists_linearIndependent - -theorem le_rank_iff_exists_linearIndependent_finset {n : ℕ} : ↑n ≤ Module.rank K V ↔ - ∃ s : Finset V, s.card = n ∧ LinearIndependent K ((↑) : ↥(s : Set V) → V) := by - simp only [le_rank_iff_exists_linearIndependent, Cardinal.mk_set_eq_nat_iff_finset] - constructor - · rintro ⟨s, ⟨t, rfl, rfl⟩, si⟩ - exact ⟨t, rfl, si⟩ - · rintro ⟨s, rfl, si⟩ - exact ⟨s, ⟨s, rfl, rfl⟩, si⟩ -#align le_rank_iff_exists_linear_independent_finset le_rank_iff_exists_linearIndependent_finset - -/-- A vector space has dimension at most `1` if and only if there is a -single vector of which all vectors are multiples. -/ -theorem rank_le_one_iff : Module.rank K V ≤ 1 ↔ ∃ v₀ : V, ∀ v, ∃ r : K, r • v₀ = v := by - let b := Basis.ofVectorSpace K V - constructor - · intro hd - rw [← b.mk_eq_rank'', Cardinal.le_one_iff_subsingleton, subsingleton_coe] at hd - rcases eq_empty_or_nonempty (ofVectorSpaceIndex K V) with (hb | ⟨⟨v₀, hv₀⟩⟩) - · use 0 - have h' : ∀ v : V, v = 0 := by simpa [hb, Submodule.eq_bot_iff] using b.span_eq.symm - intro v - simp [h' v] - · use v₀ - have h' : (K ∙ v₀) = ⊤ := by simpa [hd.eq_singleton_of_mem hv₀] using b.span_eq - intro v - have hv : v ∈ (⊤ : Submodule K V) := mem_top - rwa [← h', mem_span_singleton] at hv - · rintro ⟨v₀, hv₀⟩ - have h : (K ∙ v₀) = ⊤ := by - ext - simp [mem_span_singleton, hv₀] - rw [← rank_top, ← h] - refine' (rank_span_le _).trans_eq _ - simp -#align rank_le_one_iff rank_le_one_iff - -/-- A submodule has dimension at most `1` if and only if there is a -single vector in the submodule such that the submodule is contained in -its span. -/ -theorem rank_submodule_le_one_iff (s : Submodule K V) : - Module.rank K s ≤ 1 ↔ ∃ v₀ ∈ s, s ≤ K ∙ v₀ := by - simp_rw [rank_le_one_iff, le_span_singleton_iff] - constructor - · rintro ⟨⟨v₀, hv₀⟩, h⟩ - use v₀, hv₀ - intro v hv - obtain ⟨r, hr⟩ := h ⟨v, hv⟩ - use r - simp_rw [Subtype.ext_iff, coe_smul] at hr - exact hr - · rintro ⟨v₀, hv₀, h⟩ - use ⟨v₀, hv₀⟩ - rintro ⟨v, hv⟩ - obtain ⟨r, hr⟩ := h v hv - use r - simp_rw [Subtype.ext_iff, coe_smul] - exact hr -#align rank_submodule_le_one_iff rank_submodule_le_one_iff - -/-- A submodule has dimension at most `1` if and only if there is a -single vector, not necessarily in the submodule, such that the -submodule is contained in its span. -/ -theorem rank_submodule_le_one_iff' (s : Submodule K V) : - Module.rank K s ≤ 1 ↔ ∃ v₀, s ≤ K ∙ v₀ := by - rw [rank_submodule_le_one_iff] - constructor - · rintro ⟨v₀, _, h⟩ - exact ⟨v₀, h⟩ - · rintro ⟨v₀, h⟩ - by_cases hw : ∃ w : V, w ∈ s ∧ w ≠ 0 - · rcases hw with ⟨w, hw, hw0⟩ - use w, hw - rcases mem_span_singleton.1 (h hw) with ⟨r', rfl⟩ - have h0 : r' ≠ 0 := by - rintro rfl - simp at hw0 - rwa [span_singleton_smul_eq (IsUnit.mk0 _ h0) _] - · push_neg at hw - rw [← Submodule.eq_bot_iff] at hw - simp [hw] -#align rank_submodule_le_one_iff' rank_submodule_le_one_iff' - -theorem Submodule.rank_le_one_iff_isPrincipal (W : Submodule K V) : - Module.rank K W ≤ 1 ↔ W.IsPrincipal := by - simp only [rank_le_one_iff, Submodule.IsPrincipal_iff, le_antisymm_iff, le_span_singleton_iff, - span_singleton_le_iff_mem] - constructor - · rintro ⟨⟨m, hm⟩, hm'⟩ - choose f hf using hm' - exact ⟨m, ⟨fun v hv => ⟨f ⟨v, hv⟩, congr_arg ((↑) : W → V) (hf ⟨v, hv⟩)⟩, hm⟩⟩ - · rintro ⟨a, ⟨h, ha⟩⟩ - choose f hf using h - exact ⟨⟨a, ha⟩, fun v => ⟨f v.1 v.2, Subtype.ext (hf v.1 v.2)⟩⟩ -#align submodule.rank_le_one_iff_is_principal Submodule.rank_le_one_iff_isPrincipal - -theorem Module.rank_le_one_iff_top_isPrincipal : - Module.rank K V ≤ 1 ↔ (⊤ : Submodule K V).IsPrincipal := by - rw [← Submodule.rank_le_one_iff_isPrincipal, rank_top] -#align module.rank_le_one_iff_top_is_principal Module.rank_le_one_iff_top_isPrincipal - -end DivisionRing - -end Module - -/-! ### The rank of a linear map -/ - - -namespace LinearMap - -section Ring - -variable [Ring K] [AddCommGroup V] [Module K V] [AddCommGroup V₁] [Module K V₁] - -variable [AddCommGroup V'] [Module K V'] - -/-- `rank f` is the rank of a `LinearMap` `f`, defined as the dimension of `f.range`. -/ -abbrev rank (f : V →ₗ[K] V') : Cardinal := - Module.rank K (LinearMap.range f) -#align linear_map.rank LinearMap.rank - -theorem rank_le_range (f : V →ₗ[K] V') : rank f ≤ Module.rank K V' := - rank_submodule_le _ -#align linear_map.rank_le_range LinearMap.rank_le_range - -theorem rank_le_domain (f : V →ₗ[K] V₁) : rank f ≤ Module.rank K V := - rank_range_le _ -#align linear_map.rank_le_domain LinearMap.rank_le_domain - -@[simp] -theorem rank_zero [Nontrivial K] : rank (0 : V →ₗ[K] V') = 0 := by - rw [rank, LinearMap.range_zero, rank_bot] -#align linear_map.rank_zero LinearMap.rank_zero - -variable [AddCommGroup V''] [Module K V''] - -theorem rank_comp_le_left (g : V →ₗ[K] V') (f : V' →ₗ[K] V'') : rank (f.comp g) ≤ rank f := by - refine' rank_le_of_submodule _ _ _ - rw [LinearMap.range_comp] - exact LinearMap.map_le_range -#align linear_map.rank_comp_le_left LinearMap.rank_comp_le_left - -theorem lift_rank_comp_le_right (g : V →ₗ[K] V') (f : V' →ₗ[K] V'') : - Cardinal.lift.{v'} (rank (f.comp g)) ≤ Cardinal.lift.{v''} (rank g) := by - rw [rank, rank, LinearMap.range_comp]; exact lift_rank_map_le _ _ -#align linear_map.lift_rank_comp_le_right LinearMap.lift_rank_comp_le_right - -/-- The rank of the composition of two maps is less than the minimum of their ranks. -/ -theorem lift_rank_comp_le (g : V →ₗ[K] V') (f : V' →ₗ[K] V'') : - Cardinal.lift.{v'} (rank (f.comp g)) ≤ - min (Cardinal.lift.{v'} (rank f)) (Cardinal.lift.{v''} (rank g)) := - le_min (Cardinal.lift_le.mpr <| rank_comp_le_left _ _) (lift_rank_comp_le_right _ _) -#align linear_map.lift_rank_comp_le LinearMap.lift_rank_comp_le - -variable [AddCommGroup V'₁] [Module K V'₁] - -theorem rank_comp_le_right (g : V →ₗ[K] V') (f : V' →ₗ[K] V'₁) : rank (f.comp g) ≤ rank g := by - simpa only [Cardinal.lift_id] using lift_rank_comp_le_right g f -#align linear_map.rank_comp_le_right LinearMap.rank_comp_le_right - -/-- The rank of the composition of two maps is less than the minimum of their ranks. - -See `lift_rank_comp_le` for the universe-polymorphic version. -/ -theorem rank_comp_le (g : V →ₗ[K] V') (f : V' →ₗ[K] V'₁) : - rank (f.comp g) ≤ min (rank f) (rank g) := by - simpa only [Cardinal.lift_id] using lift_rank_comp_le g f -#align linear_map.rank_comp_le LinearMap.rank_comp_le - -end Ring - -section DivisionRing - -variable [DivisionRing K] [AddCommGroup V] [Module K V] [AddCommGroup V₁] [Module K V₁] - -variable [AddCommGroup V'] [Module K V'] - -theorem rank_add_le (f g : V →ₗ[K] V') : rank (f + g) ≤ rank f + rank g := - calc - rank (f + g) ≤ Module.rank K (LinearMap.range f ⊔ LinearMap.range g : Submodule K V') := by - refine' rank_le_of_submodule _ _ _ - exact LinearMap.range_le_iff_comap.2 <| eq_top_iff'.2 fun x => - show f x + g x ∈ (LinearMap.range f ⊔ LinearMap.range g : Submodule K V') from - mem_sup.2 ⟨_, ⟨x, rfl⟩, _, ⟨x, rfl⟩, rfl⟩ - _ ≤ rank f + rank g := Submodule.rank_add_le_rank_add_rank _ _ -#align linear_map.rank_add_le LinearMap.rank_add_le - -theorem 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 _ _ _ _ _ (fun a b => rank a ≤ b) f (fun d => rank (f d)) s - (le_of_eq rank_zero) fun _ _ _ h => le_trans (rank_add_le _ _) (add_le_add_left h _) -#align linear_map.rank_finset_sum_le LinearMap.rank_finset_sum_le - -theorem le_rank_iff_exists_linearIndependent {c : Cardinal} {f : V →ₗ[K] V'} : - c ≤ rank f ↔ ∃ s : Set V, - Cardinal.lift.{v'} #s = Cardinal.lift.{v} c ∧ LinearIndependent K (fun x : s => f x) := by - rcases f.rangeRestrict.exists_rightInverse_of_surjective f.range_rangeRestrict with ⟨g, hg⟩ - have fg : LeftInverse f.rangeRestrict g := LinearMap.congr_fun hg - refine' ⟨fun h => _, _⟩ - · rcases _root_.le_rank_iff_exists_linearIndependent.1 h with ⟨s, rfl, si⟩ - refine' ⟨g '' s, Cardinal.mk_image_eq_lift _ _ fg.injective, _⟩ - replace fg : ∀ x, f (g x) = x - · intro x - convert congr_arg Subtype.val (fg x) - replace si : LinearIndependent K fun x : s => f (g x) - · simpa only [fg] using si.map' _ (ker_subtype _) - exact si.image_of_comp s g f - · rintro ⟨s, hsc, si⟩ - have : LinearIndependent K fun x : s => f.rangeRestrict x := - LinearIndependent.of_comp f.range.subtype (by convert si) - convert this.image.cardinal_le_rank - rw [← Cardinal.lift_inj, ← hsc, Cardinal.mk_image_eq_of_injOn_lift] - exact injOn_iff_injective.2 this.injective -#align linear_map.le_rank_iff_exists_linear_independent LinearMap.le_rank_iff_exists_linearIndependent - -theorem le_rank_iff_exists_linearIndependent_finset {n : ℕ} {f : V →ₗ[K] V'} : - ↑n ≤ rank f ↔ ∃ s : Finset V, s.card = n ∧ LinearIndependent K fun x : (s : Set V) => f x := by - simp only [le_rank_iff_exists_linearIndependent, Cardinal.lift_natCast, Cardinal.lift_eq_nat_iff, - Cardinal.mk_set_eq_nat_iff_finset] - constructor - · rintro ⟨s, ⟨t, rfl, rfl⟩, si⟩ - exact ⟨t, rfl, si⟩ - · rintro ⟨s, rfl, si⟩ - exact ⟨s, ⟨s, rfl, rfl⟩, si⟩ -#align linear_map.le_rank_iff_exists_linear_independent_finset LinearMap.le_rank_iff_exists_linearIndependent_finset - -end DivisionRing - -end LinearMap diff --git a/Mathlib/LinearAlgebra/Dimension/Basic.lean b/Mathlib/LinearAlgebra/Dimension/Basic.lean new file mode 100644 index 0000000000000..b5d29c77c519f --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/Basic.lean @@ -0,0 +1,375 @@ +/- +Copyright (c) 2018 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison +-/ +import Mathlib.LinearAlgebra.DFinsupp +import Mathlib.LinearAlgebra.Quotient +import Mathlib.SetTheory.Cardinal.Ordinal + +#align_import linear_algebra.dimension from "leanprover-community/mathlib"@"47a5f8186becdbc826190ced4312f8199f9db6a5" + +/-! +# Dimension of modules and vector spaces + +## Main definitions + +* The rank of a module is defined as `Module.rank : Cardinal`. + This is defined as the supremum of the cardinalities of linearly independent subsets. + +## Main statements + +* `LinearMap.rank_le_of_injective`: the source of an injective linear map has dimension + at most that of the target. +* `LinearMap.rank_le_of_surjective`: the target of a surjective linear map has dimension + at most that of that source. + +## Implementation notes + +Many theorems in this file are not universe-generic when they relate dimensions +in different universes. They should be as general as they can be without +inserting `lift`s. The types `M`, `M'`, ... all live in different universes, +and `M₁`, `M₂`, ... all live in the same universe. +-/ + + +noncomputable section + +universe w w' u u' v v' + +variable {R : Type u} {R' : Type u'} {M M₁ : Type v} {M' : Type v'} + +open BigOperators Cardinal Submodule Function Set + +section Module + +section + +variable [Semiring R] [AddCommMonoid M] [Module R M] + +variable (R M) + +/-- The rank of a module, defined as a term of type `Cardinal`. + +We define this as the supremum of the cardinalities of linearly independent subsets. + +For a free module over any ring satisfying the strong rank condition +(e.g. left-noetherian rings, commutative rings, and in particular division rings and fields), +this is the same as the dimension of the space (i.e. the cardinality of any basis). + +In particular this agrees with the usual notion of the dimension of a vector space. + +-/ +protected irreducible_def Module.rank : Cardinal := + ⨆ ι : { s : Set M // LinearIndependent R ((↑) : s → M) }, (#ι.1) +#align module.rank Module.rank + +theorem rank_le_card : Module.rank R M ≤ #M := + (Module.rank_def _ _).trans_le (ciSup_le' fun _ ↦ mk_set_le _) + +lemma nonempty_linearIndependent_set : Nonempty {s : Set M // LinearIndependent R ((↑) : s → M)} := + ⟨⟨∅, linearIndependent_empty _ _⟩⟩ + +end + +variable [Ring R] [Ring R'] [AddCommGroup M] [AddCommGroup M'] [AddCommGroup M₁] +variable [Module R M] [Module R M'] [Module R M₁] [Module R' M'] [Module R' M₁] + +namespace LinearIndependent + +variable [Nontrivial R] + +theorem cardinal_lift_le_rank {ι : Type w} {v : ι → M} + (hv : LinearIndependent R v) : + Cardinal.lift.{v} #ι ≤ Cardinal.lift.{w} (Module.rank R M) := by + rw [Module.rank] + refine le_trans ?_ (lift_le.mpr <| le_ciSup (bddAbove_range.{v, v} _) ⟨_, hv.coe_range⟩) + exact lift_mk_le'.mpr ⟨(Equiv.ofInjective _ hv.injective).toEmbedding⟩ +#align cardinal_lift_le_rank_of_linear_independent LinearIndependent.cardinal_lift_le_rank +#align cardinal_lift_le_rank_of_linear_independent' LinearIndependent.cardinal_lift_le_rank + +lemma aleph0_le_rank {ι : Type w} [Infinite ι] {v : ι → M} + (hv : LinearIndependent R v) : ℵ₀ ≤ Module.rank R M := + aleph0_le_lift.mp <| (aleph0_le_lift.mpr <| aleph0_le_mk ι).trans hv.cardinal_lift_le_rank + +theorem cardinal_le_rank {ι : Type v} {v : ι → M} + (hv : LinearIndependent R v) : #ι ≤ Module.rank R M := by + simpa using hv.cardinal_lift_le_rank +#align cardinal_le_rank_of_linear_independent LinearIndependent.cardinal_le_rank + +theorem cardinal_le_rank' {s : Set M} + (hs : LinearIndependent R (fun x => x : s → M)) : #s ≤ Module.rank R M := + hs.cardinal_le_rank +#align cardinal_le_rank_of_linear_independent' LinearIndependent.cardinal_le_rank' + +end LinearIndependent + +@[deprecated] +alias cardinal_lift_le_rank_of_linearIndependent := LinearIndependent.cardinal_lift_le_rank +@[deprecated] +alias cardinal_lift_le_rank_of_linearIndependent' := LinearIndependent.cardinal_lift_le_rank +@[deprecated] alias cardinal_le_rank_of_linearIndependent := LinearIndependent.cardinal_le_rank +@[deprecated] alias cardinal_le_rank_of_linearIndependent' := LinearIndependent.cardinal_le_rank' + +section SurjectiveInjective + +section Module + +/-- If `M / R` and `M' / R'` are modules, `i : R' → R` is a map which sends non-zero elements to +non-zero elements, `j : M →+ M'` is an injective group homomorphism, such that the scalar +multiplications on `M` and `M'` are compatible, then the rank of `M / R` is smaller than or equal to +the rank of `M' / R'`. As a special case, taking `R = R'` it is +`LinearMap.lift_rank_le_of_injective`. -/ +theorem lift_rank_le_of_injective_injective (i : R' → R) (j : M →+ M') + (hi : ∀ r, i r = 0 → r = 0) (hj : Injective j) + (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : + lift.{v'} (Module.rank R M) ≤ lift.{v} (Module.rank R' M') := by + simp_rw [Module.rank, lift_iSup (bddAbove_range.{v', v'} _), lift_iSup (bddAbove_range.{v, v} _)] + exact ciSup_mono' (bddAbove_range.{v', v} _) fun ⟨s, h⟩ ↦ ⟨⟨j '' s, + (h.map_of_injective_injective i j hi (fun _ _ ↦ hj <| by rwa [j.map_zero]) hc).image⟩, + lift_mk_le'.mpr ⟨(Equiv.Set.image j s hj).toEmbedding⟩⟩ + +/-- If `M / R` and `M' / R'` are modules, `i : R → R'` is a surjective map which maps zero to zero, +`j : M →+ M'` is an injective group homomorphism, such that the scalar multiplications on `M` and +`M'` are compatible, then the rank of `M / R` is smaller than or equal to the rank of `M' / R'`. +As a special case, taking `R = R'` it is `LinearMap.lift_rank_le_of_injective`. -/ +theorem lift_rank_le_of_surjective_injective (i : ZeroHom R R') (j : M →+ M') + (hi : Surjective i) (hj : Injective j) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : + lift.{v'} (Module.rank R M) ≤ lift.{v} (Module.rank R' M') := by + obtain ⟨i', hi'⟩ := hi.hasRightInverse + refine lift_rank_le_of_injective_injective i' j (fun _ h ↦ ?_) hj fun r m ↦ ?_ + · apply_fun i at h + rwa [hi', i.map_zero] at h + rw [hc (i' r) m, hi'] + +/-- If `M / R` and `M' / R'` are modules, `i : R → R'` is a bijective map which maps zero to zero, +`j : M ≃+ M'` is a group isomorphism, such that the scalar multiplications on `M` and `M'` are +compatible, then the rank of `M / R` is equal to the rank of `M' / R'`. +As a special case, taking `R = R'` it is `LinearEquiv.lift_rank_eq`. -/ +theorem lift_rank_eq_of_equiv_equiv (i : ZeroHom R R') (j : M ≃+ M') + (hi : Bijective i) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : + lift.{v'} (Module.rank R M) = lift.{v} (Module.rank R' M') := + (lift_rank_le_of_surjective_injective i j hi.2 j.injective hc).antisymm <| + lift_rank_le_of_injective_injective i j.symm (fun _ _ ↦ hi.1 <| by rwa [i.map_zero]) + j.symm.injective fun _ _ ↦ j.symm_apply_eq.2 <| by erw [hc, j.apply_symm_apply] + +/-- The same-universe version of `lift_rank_le_of_injective_injective`. -/ +theorem rank_le_of_injective_injective (i : R' → R) (j : M →+ M₁) + (hi : ∀ r, i r = 0 → r = 0) (hj : Injective j) + (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : + Module.rank R M ≤ Module.rank R' M₁ := by + simpa only [lift_id] using lift_rank_le_of_injective_injective i j hi hj hc + +/-- The same-universe version of `lift_rank_le_of_surjective_injective`. -/ +theorem rank_le_of_surjective_injective (i : ZeroHom R R') (j : M →+ M₁) + (hi : Surjective i) (hj : Injective j) + (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : + Module.rank R M ≤ Module.rank R' M₁ := by + simpa only [lift_id] using lift_rank_le_of_surjective_injective i j hi hj hc + +/-- The same-universe version of `lift_rank_eq_of_equiv_equiv`. -/ +theorem rank_eq_of_equiv_equiv (i : ZeroHom R R') (j : M ≃+ M₁) + (hi : Bijective i) (hc : ∀ (r : R) (m : M), j (r • m) = i r • j m) : + Module.rank R M = Module.rank R' M₁ := by + simpa only [lift_id] using lift_rank_eq_of_equiv_equiv i j hi hc + +end Module + +namespace Algebra + +variable {R : Type w} {S : Type v} [CommRing R] [Ring S] [Algebra R S] + {R' : Type w'} {S' : Type v'} [CommRing R'] [Ring S'] [Algebra R' S'] + +/-- If `S / R` and `S' / R'` are algebras, `i : R' →+* R` and `j : S →+* S'` are injective ring +homorphisms, such that `R' → R → S → S'` and `R' → S'` commute, then the rank of `S / R` is +smaller than or equal to the rank of `S' / R'`. -/ +theorem lift_rank_le_of_injective_injective + (i : R' →+* R) (j : S →+* S') (hi : Injective i) (hj : Injective j) + (hc : (j.comp (algebraMap R S)).comp i = algebraMap R' S') : + lift.{v'} (Module.rank R S) ≤ lift.{v} (Module.rank R' S') := by + refine _root_.lift_rank_le_of_injective_injective i j + (fun _ _ ↦ hi <| by rwa [i.map_zero]) hj fun r _ ↦ ?_ + have := congr($hc r) + simp only [RingHom.coe_comp, comp_apply] at this + simp_rw [smul_def, AddMonoidHom.coe_coe, map_mul, this] + +/-- If `S / R` and `S' / R'` are algebras, `i : R →+* R'` is a surjective ring homomorphism, +`j : S →+* S'` is an injective ring homorphism, such that `R → R' → S'` and `R → S → S'` commute, +then the rank of `S / R` is smaller than or equal to the rank of `S' / R'`. -/ +theorem lift_rank_le_of_surjective_injective + (i : R →+* R') (j : S →+* S') (hi : Surjective i) (hj : Injective j) + (hc : (algebraMap R' S').comp i = j.comp (algebraMap R S)) : + lift.{v'} (Module.rank R S) ≤ lift.{v} (Module.rank R' S') := by + refine _root_.lift_rank_le_of_surjective_injective i j hi hj fun r _ ↦ ?_ + have := congr($hc r) + simp only [RingHom.coe_comp, comp_apply] at this + simp only [smul_def, AddMonoidHom.coe_coe, map_mul, ZeroHom.coe_coe, this] + +/-- If `S / R` and `S' / R'` are algebras, `i : R ≃+* R'` and `j : S ≃+* S'` are +ring isomorphisms, such that `R → R' → S'` and `R → S → S'` commute, +then the rank of `S / R` is equal to the rank of `S' / R'`. -/ +theorem lift_rank_eq_of_equiv_equiv (i : R ≃+* R') (j : S ≃+* S') + (hc : (algebraMap R' S').comp i.toRingHom = j.toRingHom.comp (algebraMap R S)) : + lift.{v'} (Module.rank R S) = lift.{v} (Module.rank R' S') := by + refine _root_.lift_rank_eq_of_equiv_equiv i j i.bijective fun r _ ↦ ?_ + have := congr($hc r) + simp only [RingEquiv.toRingHom_eq_coe, RingHom.coe_comp, RingHom.coe_coe, comp_apply] at this + simp only [smul_def, RingEquiv.coe_toAddEquiv, map_mul, ZeroHom.coe_coe, this] + +variable {S' : Type v} [CommRing R'] [Ring S'] [Algebra R' S'] + +/-- The same-universe version of `Algebra.lift_rank_le_of_injective_injective`. -/ +theorem rank_le_of_injective_injective + (i : R' →+* R) (j : S →+* S') (hi : Injective i) (hj : Injective j) + (hc : (j.comp (algebraMap R S)).comp i = algebraMap R' S') : + Module.rank R S ≤ Module.rank R' S' := by + simpa only [lift_id] using lift_rank_le_of_injective_injective i j hi hj hc + +/-- The same-universe version of `Algebra.lift_rank_le_of_surjective_injective`. -/ +theorem rank_le_of_surjective_injective + (i : R →+* R') (j : S →+* S') (hi : Surjective i) (hj : Injective j) + (hc : (algebraMap R' S').comp i = j.comp (algebraMap R S)) : + Module.rank R S ≤ Module.rank R' S' := by + simpa only [lift_id] using lift_rank_le_of_surjective_injective i j hi hj hc + +/-- The same-universe version of `Algebra.lift_rank_eq_of_equiv_equiv`. -/ +theorem rank_eq_of_equiv_equiv (i : R ≃+* R') (j : S ≃+* S') + (hc : (algebraMap R' S').comp i.toRingHom = j.toRingHom.comp (algebraMap R S)) : + Module.rank R S = Module.rank R' S' := by + simpa only [lift_id] using lift_rank_eq_of_equiv_equiv i j hc + +end Algebra + +end SurjectiveInjective + +section + +theorem LinearMap.lift_rank_le_of_injective (f : M →ₗ[R] M') (i : Injective f) : + Cardinal.lift.{v'} (Module.rank R M) ≤ Cardinal.lift.{v} (Module.rank R M') := + lift_rank_le_of_injective_injective (RingHom.id R) f (fun _ h ↦ h) i f.map_smul +#align linear_map.lift_rank_le_of_injective LinearMap.lift_rank_le_of_injective + +theorem LinearMap.rank_le_of_injective (f : M →ₗ[R] M₁) (i : Injective f) : + Module.rank R M ≤ Module.rank R M₁ := + Cardinal.lift_le.1 (f.lift_rank_le_of_injective i) +#align linear_map.rank_le_of_injective LinearMap.rank_le_of_injective + +/-- The rank of the range of a linear map is at most the rank of the source. -/ +-- The proof is: a free submodule of the range lifts to a free submodule of the +-- source, by arbitrarily lifting a basis. +theorem lift_rank_range_le (f : M →ₗ[R] M') : Cardinal.lift.{v} + (Module.rank R (LinearMap.range f)) ≤ Cardinal.lift.{v'} (Module.rank R M) := by + simp only [Module.rank_def] + rw [Cardinal.lift_iSup (Cardinal.bddAbove_range.{v', v'} _)] + apply ciSup_le' + rintro ⟨s, li⟩ + apply le_trans + swap + · apply Cardinal.lift_le.mpr + refine' le_ciSup (Cardinal.bddAbove_range.{v, v} _) ⟨rangeSplitting f '' s, _⟩ + apply LinearIndependent.of_comp f.rangeRestrict + convert li.comp (Equiv.Set.rangeSplittingImageEquiv f s) (Equiv.injective _) using 1 + · exact (Cardinal.lift_mk_eq'.mpr ⟨Equiv.Set.rangeSplittingImageEquiv f s⟩).ge +#align lift_rank_range_le lift_rank_range_le + +theorem rank_range_le (f : M →ₗ[R] M₁) : Module.rank R (LinearMap.range f) ≤ Module.rank R M := by + simpa using lift_rank_range_le f +#align rank_range_le rank_range_le + +theorem lift_rank_map_le (f : M →ₗ[R] M') (p : Submodule R M) : + Cardinal.lift.{v} (Module.rank R (p.map f)) ≤ Cardinal.lift.{v'} (Module.rank R p) := by + have h := lift_rank_range_le (f.comp (Submodule.subtype p)) + rwa [LinearMap.range_comp, range_subtype] at h +#align lift_rank_map_le lift_rank_map_le + +theorem rank_map_le (f : M →ₗ[R] M₁) (p : Submodule R M) : + Module.rank R (p.map f) ≤ Module.rank R p := by simpa using lift_rank_map_le f p +#align rank_map_le rank_map_le + +theorem rank_le_of_submodule (s t : Submodule R M) (h : s ≤ t) : + Module.rank R s ≤ Module.rank R t := + (Submodule.inclusion h).rank_le_of_injective fun ⟨x, _⟩ ⟨y, _⟩ eq => + Subtype.eq <| show x = y from Subtype.ext_iff_val.1 eq +#align rank_le_of_submodule rank_le_of_submodule + +/-- Two linearly equivalent vector spaces have the same dimension, a version with different +universes. -/ +theorem LinearEquiv.lift_rank_eq (f : M ≃ₗ[R] M') : + Cardinal.lift.{v'} (Module.rank R M) = Cardinal.lift.{v} (Module.rank R M') := by + apply le_antisymm + · exact f.toLinearMap.lift_rank_le_of_injective f.injective + · exact f.symm.toLinearMap.lift_rank_le_of_injective f.symm.injective +#align linear_equiv.lift_rank_eq LinearEquiv.lift_rank_eq + +/-- Two linearly equivalent vector spaces have the same dimension. -/ +theorem LinearEquiv.rank_eq (f : M ≃ₗ[R] M₁) : Module.rank R M = Module.rank R M₁ := + Cardinal.lift_inj.1 f.lift_rank_eq +#align linear_equiv.rank_eq LinearEquiv.rank_eq + +theorem lift_rank_range_of_injective (f : M →ₗ[R] M') (h : Injective f) : + lift.{v} (Module.rank R (LinearMap.range f)) = lift.{v'} (Module.rank R M) := + (LinearEquiv.ofInjective f h).lift_rank_eq.symm + +theorem rank_range_of_injective (f : M →ₗ[R] M₁) (h : Injective f) : + Module.rank R (LinearMap.range f) = Module.rank R M := + (LinearEquiv.ofInjective f h).rank_eq.symm +#align rank_eq_of_injective rank_range_of_injective + +theorem LinearEquiv.lift_rank_map_eq (f : M ≃ₗ[R] M') (p : Submodule R M) : + lift.{v} (Module.rank R (p.map (f : M →ₗ[R] M'))) = lift.{v'} (Module.rank R p) := + (f.submoduleMap p).lift_rank_eq.symm + +/-- Pushforwards of submodules along a `LinearEquiv` have the same dimension. -/ +theorem LinearEquiv.rank_map_eq (f : M ≃ₗ[R] M₁) (p : Submodule R M) : + Module.rank R (p.map (f : M →ₗ[R] M₁)) = Module.rank R p := + (f.submoduleMap p).rank_eq.symm +#align linear_equiv.rank_map_eq LinearEquiv.rank_map_eq + +variable (R M) + +@[simp] +theorem rank_top : Module.rank R (⊤ : Submodule R M) = Module.rank R M := + (LinearEquiv.ofTop ⊤ rfl).rank_eq +#align rank_top rank_top + +variable {R M} + +theorem rank_range_of_surjective (f : M →ₗ[R] M') (h : Surjective f) : + Module.rank R (LinearMap.range f) = Module.rank R M' := + by rw [LinearMap.range_eq_top.2 h, rank_top] +#align rank_range_of_surjective rank_range_of_surjective + +theorem rank_submodule_le (s : Submodule R M) : Module.rank R s ≤ Module.rank R M := by + rw [← rank_top R M] + exact rank_le_of_submodule _ _ le_top +#align rank_submodule_le rank_submodule_le + +theorem LinearMap.lift_rank_le_of_surjective (f : M →ₗ[R] M') (h : Surjective f) : + lift.{v} (Module.rank R M') ≤ lift.{v'} (Module.rank R M) := by + rw [← rank_range_of_surjective f h] + apply lift_rank_range_le + +theorem LinearMap.rank_le_of_surjective (f : M →ₗ[R] M₁) (h : Surjective f) : + Module.rank R M₁ ≤ Module.rank R M := by + rw [← rank_range_of_surjective f h] + apply rank_range_le +#align linear_map.rank_le_of_surjective LinearMap.rank_le_of_surjective + +@[nontriviality, simp] +theorem rank_subsingleton [Subsingleton R] : Module.rank R M = 1 := by + haveI := Module.subsingleton R M + have : Nonempty { s : Set M // LinearIndependent R ((↑) : s → M) } := + ⟨⟨∅, linearIndependent_empty _ _⟩⟩ + rw [Module.rank_def, ciSup_eq_of_forall_le_of_forall_lt_exists_gt] + · rintro ⟨s, hs⟩ + rw [Cardinal.mk_le_one_iff_set_subsingleton] + apply subsingleton_of_subsingleton + intro w hw + refine' ⟨⟨{0}, _⟩, _⟩ + · rw [linearIndependent_iff'] + intros + exact Subsingleton.elim _ _ + · exact hw.trans_eq (Cardinal.mk_singleton _).symm +#align rank_subsingleton rank_subsingleton + +end diff --git a/Mathlib/LinearAlgebra/Dimension/Constructions.lean b/Mathlib/LinearAlgebra/Dimension/Constructions.lean new file mode 100644 index 0000000000000..6fb253c151ca6 --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/Constructions.lean @@ -0,0 +1,509 @@ +/- +Copyright (c) 2018 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison, Chris Hughes, Anne Baanen +-/ +import Mathlib.LinearAlgebra.Dimension.Finite +import Mathlib.Algebra.Module.Torsion + +#align_import linear_algebra.dimension from "leanprover-community/mathlib"@"47a5f8186becdbc826190ced4312f8199f9db6a5" + +/-! +# Rank of various constructions + +## Main statements + +- `rank_quotient_add_rank_le` : `rank M/N + rank N ≤ rank M`. +- `lift_rank_add_lift_rank_le_rank_prod`: `rank M × N ≤ rank M + rank N`. +- `rank_span_le_of_finite`: `rank (span s) ≤ #s` for finite `s`. + +For free modules, we have + +- `rank_prod` : `rank M × N = rank M + rank N`. +- `rank_finsupp` : `rank (ι →₀ M) = #ι * rank M` +- `rank_directSum`: `rank (⨁ Mᵢ) = ∑ rank Mᵢ` +- `rank_tensorProduct`: `rank (M ⊗ N) = rank M * rank N`. + +Lemmas for ranks of submodules and subalgebras are also provided. +We have finrank variants for most lemmas as well. + +-/ + + +noncomputable section + +universe u v v' u₁' w w' + +variable {R S : Type u} {M : Type v} {M' : Type v'} {M₁ : Type v} + +variable {ι : Type w} {ι' : Type w'} {η : Type u₁'} {φ : η → Type*} + +open BigOperators Cardinal Basis Submodule Function Set FiniteDimensional DirectSum + +variable [Ring R] [CommRing S] [AddCommGroup M] [AddCommGroup M'] [AddCommGroup M₁] + +variable [Module R M] [Module R M'] [Module R M₁] + +section Quotient + +theorem rank_quotient_add_rank_le [Nontrivial R] (M' : Submodule R M) : + Module.rank R (M ⧸ M') + Module.rank R M' ≤ Module.rank R M := by + simp_rw [Module.rank_def] + have := nonempty_linearIndependent_set R (M ⧸ M') + have := nonempty_linearIndependent_set R M' + rw [Cardinal.ciSup_add_ciSup _ (bddAbove_range.{v, v} _) _ (bddAbove_range.{v, v} _)] + refine ciSup_le fun ⟨s, hs⟩ ↦ ciSup_le fun ⟨t, ht⟩ ↦ ?_ + choose f hf using Quotient.mk_surjective M' + let g : s ⊕ t → M := Sum.elim (f ·) (·) + suffices : LinearIndependent R g + · refine le_trans ?_ (le_ciSup (bddAbove_range.{v, v} _) ⟨_, this.to_subtype_range⟩) + rw [mk_range_eq _ this.injective, mk_sum, lift_id, lift_id] + refine .sum_type (.of_comp M'.mkQ ?_) (ht.map' M'.subtype M'.ker_subtype) ?_ + · convert hs; ext x; exact hf x + refine disjoint_def.mpr fun x h₁ h₂ ↦ ?_ + have : x ∈ M' := span_le.mpr (Set.range_subset_iff.mpr fun i ↦ i.1.2) h₂ + obtain ⟨c, rfl⟩ := Finsupp.mem_span_range_iff_exists_finsupp.mp h₁ + simp_rw [← Quotient.mk_eq_zero, ← mkQ_apply, map_finsupp_sum, map_smul, mkQ_apply, hf] at this + rw [linearIndependent_iff.mp hs _ this, Finsupp.sum_zero_index] + +theorem rank_quotient_le (p : Submodule R M) : Module.rank R (M ⧸ p) ≤ Module.rank R M := + (mkQ p).rank_le_of_surjective (surjective_quot_mk _) +#align rank_quotient_le rank_quotient_le + +theorem rank_quotient_eq_of_le_torsion {R M} [CommRing R] [AddCommGroup M] [Module R M] + {M' : Submodule R M} (hN : M' ≤ torsion R M) : Module.rank R (M ⧸ M') = Module.rank R M := + (rank_quotient_le M').antisymm <| by + nontriviality R + rw [Module.rank] + have := nonempty_linearIndependent_set R M + refine ciSup_le fun ⟨s, hs⟩ ↦ LinearIndependent.cardinal_le_rank (v := (M'.mkQ ·)) ?_ + rw [linearIndependent_iff'] at hs ⊢ + simp_rw [← map_smul, ← map_sum, mkQ_apply, Quotient.mk_eq_zero] + intro t g hg i hi + obtain ⟨r, hg⟩ := hN hg + simp_rw [Finset.smul_sum, Submonoid.smul_def, smul_smul] at hg + exact r.prop _ (mul_comm (g i) r ▸ hs t _ hg i hi) + +end Quotient + +section ULift + +@[simp] +theorem rank_ulift : Module.rank R (ULift.{w} M) = Cardinal.lift.{w} (Module.rank R M) := + Cardinal.lift_injective.{v} <| Eq.symm <| (lift_lift _).trans ULift.moduleEquiv.symm.lift_rank_eq + +@[simp] +theorem finrank_ulift : finrank R (ULift M) = finrank R M := by + simp_rw [finrank, rank_ulift, toNat_lift] + +end ULift + +section Prod + +variable (R M M') + +open LinearMap in +theorem lift_rank_add_lift_rank_le_rank_prod [Nontrivial R] : + lift.{v'} (Module.rank R M) + lift.{v} (Module.rank R M') ≤ Module.rank R (M × M') := by + convert rank_quotient_add_rank_le (ker <| LinearMap.fst R M M') + · refine Eq.trans ?_ (lift_id'.{v, v'} _) + rw [(quotKerEquivRange _).lift_rank_eq, + rank_range_of_surjective _ fst_surjective, lift_umax.{v, v'}] + · refine Eq.trans ?_ (lift_id'.{v', v} _) + rw [ker_fst, ← (LinearEquiv.ofInjective _ <| inr_injective (M := M) (M₂ := M')).lift_rank_eq, + lift_umax.{v', v}] + +theorem rank_add_rank_le_rank_prod [Nontrivial R] : + Module.rank R M + Module.rank R M₁ ≤ Module.rank R (M × M₁) := by + convert ← lift_rank_add_lift_rank_le_rank_prod R M M₁ <;> apply lift_id + +variable {R M M'} + +variable [StrongRankCondition R] [Module.Free R M] [Module.Free R M'] [Module.Free R M₁] + +open Module.Free + +/-- If `M` and `M'` are free, then the rank of `M × M'` is +`(Module.rank R M).lift + (Module.rank R M').lift`. -/ +@[simp] +theorem rank_prod : Module.rank R (M × M') = + Cardinal.lift.{v'} (Module.rank R M) + Cardinal.lift.{v, v'} (Module.rank R M') := by + simpa [rank_eq_card_chooseBasisIndex R M, rank_eq_card_chooseBasisIndex R M', lift_umax, + lift_umax'] using ((chooseBasis R M).prod (chooseBasis R M')).mk_eq_rank.symm +#align rank_prod rank_prod + +/-- If `M` and `M'` are free (and lie in the same universe), the rank of `M × M'` is + `(Module.rank R M) + (Module.rank R M')`. -/ +theorem rank_prod' : Module.rank R (M × M₁) = Module.rank R M + Module.rank R M₁ := by simp +#align rank_prod' rank_prod' + +/-- The finrank of `M × M'` is `(finrank R M) + (finrank R M')`. -/ +@[simp] +theorem FiniteDimensional.finrank_prod [Module.Finite R M] [Module.Finite R M'] : + finrank R (M × M') = finrank R M + finrank R M' := by + simp [finrank, rank_lt_aleph0 R M, rank_lt_aleph0 R M'] +#align finite_dimensional.finrank_prod FiniteDimensional.finrank_prod + +end Prod + +section Finsupp + +variable (R M M') + +variable [StrongRankCondition R] [Module.Free R M] [Module.Free R M'] + +open Module.Free BigOperators + +@[simp] +theorem rank_finsupp (ι : Type w) : + Module.rank R (ι →₀ M) = Cardinal.lift.{v} #ι * Cardinal.lift.{w} (Module.rank R M) := by + obtain ⟨⟨_, bs⟩⟩ := Module.Free.exists_basis (R := R) (M := M) + rw [← bs.mk_eq_rank'', ← (Finsupp.basis fun _ : ι => bs).mk_eq_rank'', Cardinal.mk_sigma, + Cardinal.sum_const] +#align rank_finsupp rank_finsupp + +theorem rank_finsupp' (ι : Type v) : Module.rank R (ι →₀ M) = #ι * Module.rank R M := by + simp [rank_finsupp] +#align rank_finsupp' rank_finsupp' + +/-- The rank of `(ι →₀ R)` is `(#ι).lift`. -/ +-- Porting note, this should not be `@[simp]`, as simp can prove it. +-- @[simp] +theorem rank_finsupp_self (ι : Type w) : Module.rank R (ι →₀ R) = Cardinal.lift.{u} #ι := by + simp [rank_finsupp] +#align rank_finsupp_self rank_finsupp_self + +/-- If `R` and `ι` lie in the same universe, the rank of `(ι →₀ R)` is `# ι`. -/ +theorem rank_finsupp_self' {ι : Type u} : Module.rank R (ι →₀ R) = #ι := by simp +#align rank_finsupp_self' rank_finsupp_self' + +/-- The rank of the direct sum is the sum of the ranks. -/ +@[simp] +theorem rank_directSum {ι : Type v} (M : ι → Type w) [∀ i : ι, AddCommGroup (M i)] + [∀ i : ι, Module R (M i)] [∀ i : ι, Module.Free R (M i)] : + Module.rank R (⨁ i, M i) = Cardinal.sum fun i => Module.rank R (M i) := by + let B i := chooseBasis R (M i) + let b : Basis _ R (⨁ i, M i) := DFinsupp.basis fun i => B i + simp [← b.mk_eq_rank'', fun i => (B i).mk_eq_rank''] +#align rank_direct_sum rank_directSum + +/-- If `m` and `n` are `Fintype`, the rank of `m × n` matrices is `(#m).lift * (#n).lift`. -/ +@[simp] +theorem rank_matrix (m : Type v) (n : Type w) [Finite m] [Finite n] : + Module.rank R (Matrix m n R) = + Cardinal.lift.{max v w u, v} #m * Cardinal.lift.{max v w u, w} #n := by + cases nonempty_fintype m + cases nonempty_fintype n + have h := (Matrix.stdBasis R m n).mk_eq_rank + rw [← lift_lift.{max v w u, max v w}, lift_inj] at h + simpa using h.symm +#align rank_matrix rank_matrix + +/-- If `m` and `n` are `Fintype` that lie in the same universe, the rank of `m × n` matrices is + `(#n * #m).lift`. -/ +@[simp high] +theorem rank_matrix' (m n : Type v) [Finite m] [Finite n] : + Module.rank R (Matrix m n R) = Cardinal.lift.{u} (#m * #n) := by + rw [rank_matrix, lift_mul, lift_umax.{v, u}] +#align rank_matrix' rank_matrix' + +/-- If `m` and `n` are `Fintype` that lie in the same universe as `R`, the rank of `m × n` matrices + is `# m * # n`. -/ +-- @[simp] -- Porting note: simp can prove this +theorem rank_matrix'' (m n : Type u) [Finite m] [Finite n] : + Module.rank R (Matrix m n R) = #m * #n := by simp +#align rank_matrix'' rank_matrix'' + +variable [Module.Finite R M] [Module.Finite R M'] + +open Fintype + +namespace FiniteDimensional + +@[simp] +theorem finrank_finsupp {ι : Type v} [Fintype ι] : finrank R (ι →₀ M) = card ι * finrank R M := by + rw [finrank, finrank, rank_finsupp, ← mk_toNat_eq_card, toNat_mul, toNat_lift, toNat_lift] + +/-- The finrank of `(ι →₀ R)` is `Fintype.card ι`. -/ +@[simp] +theorem finrank_finsupp_self {ι : Type v} [Fintype ι] : finrank R (ι →₀ R) = card ι := by + rw [finrank, rank_finsupp_self, ← mk_toNat_eq_card, toNat_lift] +#align finite_dimensional.finrank_finsupp FiniteDimensional.finrank_finsupp_self + +/-- The finrank of the direct sum is the sum of the finranks. -/ +@[simp] +theorem finrank_directSum {ι : Type v} [Fintype ι] (M : ι → Type w) [∀ i : ι, AddCommGroup (M i)] + [∀ i : ι, Module R (M i)] [∀ i : ι, Module.Free R (M i)] [∀ i : ι, Module.Finite R (M i)] : + finrank R (⨁ i, M i) = ∑ i, finrank R (M i) := by + letI := nontrivial_of_invariantBasisNumber R + simp only [finrank, fun i => rank_eq_card_chooseBasisIndex R (M i), rank_directSum, ← mk_sigma, + mk_toNat_eq_card, card_sigma] +#align finite_dimensional.finrank_direct_sum FiniteDimensional.finrank_directSum + +/-- If `m` and `n` are `Fintype`, the finrank of `m × n` matrices is + `(Fintype.card m) * (Fintype.card n)`. -/ +theorem finrank_matrix (m n : Type*) [Fintype m] [Fintype n] : + finrank R (Matrix m n R) = card m * card n := by simp [finrank] +#align finite_dimensional.finrank_matrix FiniteDimensional.finrank_matrix + +end FiniteDimensional + +end Finsupp + +section Pi + +variable [StrongRankCondition R] [Module.Free R M] + +variable [∀ i, AddCommGroup (φ i)] [∀ i, Module R (φ i)] [∀ i, Module.Free R (φ i)] + +open Module.Free + +open LinearMap + +/-- The rank of a finite product of free modules is the sum of the ranks. -/ +-- this result is not true without the freeness assumption +@[simp] +theorem rank_pi [Finite η] : Module.rank R (∀ i, φ i) = + Cardinal.sum fun i => Module.rank R (φ i) := by + cases nonempty_fintype η + let B i := chooseBasis R (φ i) + let b : Basis _ R (∀ i, φ i) := Pi.basis fun i => B i + simp [← b.mk_eq_rank'', fun i => (B i).mk_eq_rank''] +#align rank_pi rank_pi + +variable (R) + +/-- The finrank of `(ι → R)` is `Fintype.card ι`. -/ +theorem FiniteDimensional.finrank_pi {ι : Type v} [Fintype ι] : + finrank R (ι → R) = Fintype.card ι := by + simp [finrank] +#align finite_dimensional.finrank_pi FiniteDimensional.finrank_pi + +--TODO: this should follow from `LinearEquiv.finrank_eq`, that is over a field. +/-- The finrank of a finite product is the sum of the finranks. -/ +theorem FiniteDimensional.finrank_pi_fintype + {ι : Type v} [Fintype ι] {M : ι → Type w} [∀ i : ι, AddCommGroup (M i)] + [∀ i : ι, Module R (M i)] [∀ i : ι, Module.Free R (M i)] [∀ i : ι, Module.Finite R (M i)] : + finrank R (∀ i, M i) = ∑ i, finrank R (M i) := by + letI := nontrivial_of_invariantBasisNumber R + simp only [finrank, fun i => rank_eq_card_chooseBasisIndex R (M i), rank_pi, ← mk_sigma, + mk_toNat_eq_card, Fintype.card_sigma] +#align finite_dimensional.finrank_pi_fintype FiniteDimensional.finrank_pi_fintype + +variable {R} +variable [Fintype η] + +theorem rank_fun {M η : Type u} [Fintype η] [AddCommGroup M] [Module R M] [Module.Free R M] : + Module.rank R (η → M) = Fintype.card η * Module.rank R M := by + rw [rank_pi, Cardinal.sum_const', Cardinal.mk_fintype] +#align rank_fun rank_fun + +theorem rank_fun_eq_lift_mul : Module.rank R (η → M) = + (Fintype.card η : Cardinal.{max u₁' v}) * Cardinal.lift.{u₁'} (Module.rank R M) := + by rw [rank_pi, Cardinal.sum_const, Cardinal.mk_fintype, Cardinal.lift_natCast] +#align rank_fun_eq_lift_mul rank_fun_eq_lift_mul + +theorem rank_fun' : Module.rank R (η → R) = Fintype.card η := by + rw [rank_fun_eq_lift_mul, rank_self, Cardinal.lift_one, mul_one, Cardinal.natCast_inj] +#align rank_fun' rank_fun' + +theorem rank_fin_fun (n : ℕ) : Module.rank R (Fin n → R) = n := by simp [rank_fun'] +#align rank_fin_fun rank_fin_fun + +variable (R) + +/-- The vector space of functions on a `Fintype ι` has finrank equal to the cardinality of `ι`. -/ +@[simp] +theorem FiniteDimensional.finrank_fintype_fun_eq_card : finrank R (η → R) = Fintype.card η := + finrank_eq_of_rank_eq rank_fun' +#align finite_dimensional.finrank_fintype_fun_eq_card FiniteDimensional.finrank_fintype_fun_eq_card + +/-- The vector space of functions on `Fin n` has finrank equal to `n`. -/ +-- @[simp] -- Porting note: simp already proves this +theorem FiniteDimensional.finrank_fin_fun {n : ℕ} : finrank R (Fin n → R) = n := by simp +#align finite_dimensional.finrank_fin_fun FiniteDimensional.finrank_fin_fun + +variable {R} + +-- TODO: merge with the `Finrank` content +/-- An `n`-dimensional `R`-vector space is equivalent to `Fin n → R`. -/ +def finDimVectorspaceEquiv (n : ℕ) (hn : Module.rank R M = n) : M ≃ₗ[R] Fin n → R := by + haveI := nontrivial_of_invariantBasisNumber R + have : Cardinal.lift.{u} (n : Cardinal.{v}) = Cardinal.lift.{v} (n : Cardinal.{u}) := by simp + have hn := Cardinal.lift_inj.{v, u}.2 hn + rw [this] at hn + rw [← @rank_fin_fun R _ _ n] at hn + haveI : Module.Free R (Fin n → R) := Module.Free.pi _ _ + exact Classical.choice (nonempty_linearEquiv_of_lift_rank_eq hn) +#align fin_dim_vectorspace_equiv finDimVectorspaceEquiv + +end Pi + +section TensorProduct + +open TensorProduct + +variable [StrongRankCondition S] + +variable [Module S M] [Module.Free S M] [Module S M'] [Module.Free S M'] +variable [Module S M₁] [Module.Free S M₁] + +open Module.Free + +/-- The rank of `M ⊗[R] M'` is `(Module.rank R M).lift * (Module.rank R M').lift`. -/ +@[simp] +theorem rank_tensorProduct : + Module.rank S (M ⊗[S] M') = + Cardinal.lift.{v'} (Module.rank S M) * Cardinal.lift.{v} (Module.rank S M') := by + obtain ⟨⟨_, bM⟩⟩ := Module.Free.exists_basis (R := S) (M := M) + obtain ⟨⟨_, bN⟩⟩ := Module.Free.exists_basis (R := S) (M := M') + rw [← bM.mk_eq_rank'', ← bN.mk_eq_rank'', ← (bM.tensorProduct bN).mk_eq_rank'', Cardinal.mk_prod] +#align rank_tensor_product rank_tensorProduct + +/-- If `M` and `M'` lie in the same universe, the rank of `M ⊗[R] M'` is + `(Module.rank R M) * (Module.rank R M')`. -/ +theorem rank_tensorProduct' : + Module.rank S (M ⊗[S] M₁) = Module.rank S M * Module.rank S M₁ := by simp +#align rank_tensor_product' rank_tensorProduct' + +/-- The finrank of `M ⊗[R] M'` is `(finrank R M) * (finrank R M')`. -/ +@[simp] +theorem FiniteDimensional.finrank_tensorProduct : + finrank S (M ⊗[S] M') = finrank S M * finrank S M' := by simp [finrank] +#align finite_dimensional.finrank_tensor_product FiniteDimensional.finrank_tensorProduct + +end TensorProduct + +section Span + +variable [StrongRankCondition R] + +theorem rank_span_le_of_finite {s : Set M} (hs : s.Finite) : Module.rank R (span R s) ≤ #s := by + rw [Module.rank_def] + apply ciSup_le' + rintro ⟨t, ht⟩ + letI := hs.fintype + simpa [Cardinal.mk_image_eq Subtype.val_injective] using linearIndependent_le_span' _ + (ht.map (f := Submodule.subtype _) (by simp)).image s (fun x ↦ by aesop) + +theorem rank_span_finset_le (s : Finset M) : Module.rank R (span R (s : Set M)) ≤ s.card := by + simpa using rank_span_le_of_finite s.finite_toSet + +theorem rank_span_of_finset (s : Finset M) : Module.rank R (span R (s : Set M)) < ℵ₀ := + (rank_span_finset_le s).trans_lt (Cardinal.nat_lt_aleph0 _) +#align rank_span_of_finset rank_span_of_finset + +end Span + +section SubmoduleRank + +section + +open FiniteDimensional + +namespace Submodule + +theorem lt_of_le_of_finrank_lt_finrank {s t : Submodule R M} (le : s ≤ t) + (lt : finrank R s < finrank R t) : s < t := + lt_of_le_of_ne le fun h => ne_of_lt lt (by rw [h]) +#align submodule.lt_of_le_of_finrank_lt_finrank Submodule.lt_of_le_of_finrank_lt_finrank + +theorem lt_top_of_finrank_lt_finrank {s : Submodule R M} (lt : finrank R s < finrank R M) : + s < ⊤ := by + rw [← finrank_top R M] at lt + exact lt_of_le_of_finrank_lt_finrank le_top lt +#align submodule.lt_top_of_finrank_lt_finrank Submodule.lt_top_of_finrank_lt_finrank + +end Submodule + +variable [StrongRankCondition R] + +/-- The dimension of a submodule is bounded by the dimension of the ambient space. -/ +theorem Submodule.finrank_le [Module.Finite R M] (s : Submodule R M) : + finrank R s ≤ finrank R M := by + simpa only [Cardinal.toNat_lift] using + toNat_le_of_le_of_lt_aleph0 (rank_lt_aleph0 _ _) (rank_submodule_le s) +#align submodule.finrank_le Submodule.finrank_le + +/-- The dimension of a quotient is bounded by the dimension of the ambient space. -/ +theorem Submodule.finrank_quotient_le [Module.Finite R M] (s : Submodule R M) : + finrank R (M ⧸ s) ≤ finrank R M := by + simpa only [Cardinal.toNat_lift] using + toNat_le_of_le_of_lt_aleph0 (rank_lt_aleph0 _ _) + ((Submodule.mkQ s).rank_le_of_surjective (surjective_quot_mk _)) +#align submodule.finrank_quotient_le Submodule.finrank_quotient_le + +/-- Pushforwards of finite submodules have a smaller finrank. -/ +theorem Submodule.finrank_map_le (f : M →ₗ[R] M') (p : Submodule R M) [Module.Finite R p] : + finrank R (p.map f) ≤ finrank R p := + finrank_le_finrank_of_rank_le_rank (lift_rank_map_le _ _) (rank_lt_aleph0 _ _) +#align submodule.finrank_map_le Submodule.finrank_map_le + +theorem Submodule.finrank_le_finrank_of_le {s t : Submodule R M} [Module.Finite R t] (hst : s ≤ t) : + finrank R s ≤ finrank R t := + calc + finrank R s = finrank R (s.comap t.subtype) := + (Submodule.comapSubtypeEquivOfLe hst).finrank_eq.symm + _ ≤ finrank R t := Submodule.finrank_le _ +#align submodule.finrank_le_finrank_of_le Submodule.finrank_le_finrank_of_le + +end + + +end SubmoduleRank + +section SubalgebraRank + +open Module + +variable {F E : Type*} [CommRing F] [Ring E] [Algebra F E] + +@[simp] +theorem Subalgebra.rank_toSubmodule (S : Subalgebra F E) : + Module.rank F (Subalgebra.toSubmodule S) = Module.rank F S := + rfl +#align subalgebra.rank_to_submodule Subalgebra.rank_toSubmodule + +@[simp] +theorem Subalgebra.finrank_toSubmodule (S : Subalgebra F E) : + finrank F (Subalgebra.toSubmodule S) = finrank F S := + rfl +#align subalgebra.finrank_to_submodule Subalgebra.finrank_toSubmodule + +theorem subalgebra_top_rank_eq_submodule_top_rank : + Module.rank F (⊤ : Subalgebra F E) = Module.rank F (⊤ : Submodule F E) := by + rw [← Algebra.top_toSubmodule] + rfl +#align subalgebra_top_rank_eq_submodule_top_rank subalgebra_top_rank_eq_submodule_top_rank + +theorem subalgebra_top_finrank_eq_submodule_top_finrank : + finrank F (⊤ : Subalgebra F E) = finrank F (⊤ : Submodule F E) := by + rw [← Algebra.top_toSubmodule] + rfl +#align subalgebra_top_finrank_eq_submodule_top_finrank subalgebra_top_finrank_eq_submodule_top_finrank + +theorem Subalgebra.rank_top : Module.rank F (⊤ : Subalgebra F E) = Module.rank F E := by + rw [subalgebra_top_rank_eq_submodule_top_rank] + exact _root_.rank_top F E +#align subalgebra.rank_top Subalgebra.rank_top + +section + +variable [StrongRankCondition F] [NoZeroSMulDivisors F E] [Nontrivial E] + +@[simp] +theorem Subalgebra.rank_bot : Module.rank F (⊥ : Subalgebra F E) = 1 := + (Subalgebra.toSubmoduleEquiv (⊥ : Subalgebra F E)).symm.rank_eq.trans <| by + rw [Algebra.toSubmodule_bot, one_eq_span, rank_span_set, mk_singleton _] + letI := Module.nontrivial F E + exact linearIndependent_singleton one_ne_zero +#align subalgebra.rank_bot Subalgebra.rank_bot + +@[simp] +theorem Subalgebra.finrank_bot : finrank F (⊥ : Subalgebra F E) = 1 := + finrank_eq_of_rank_eq (by simp) +#align subalgebra.finrank_bot Subalgebra.finrank_bot + +end + +end SubalgebraRank diff --git a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean new file mode 100644 index 0000000000000..89f7d68b6c890 --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean @@ -0,0 +1,644 @@ +/- +Copyright (c) 2018 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, +Scott Morrison, Chris Hughes, Anne Baanen, Junyan Xu +-/ +import Mathlib.LinearAlgebra.Basis.VectorSpace +import Mathlib.LinearAlgebra.Dimension.Finite +import Mathlib.SetTheory.Cardinal.Subfield +import Mathlib.LinearAlgebra.Dimension.Constructions + +#align_import linear_algebra.dimension from "leanprover-community/mathlib"@"47a5f8186becdbc826190ced4312f8199f9db6a5" + +/-! +# Dimension of vector spaces + +In this file we provide results about `Module.rank` and `FiniteDimensional.finrank` of vector spaces +over division rings. + +## Main statements + +For vector spaces (i.e. modules over a field), we have + +* `rank_quotient_add_rank`: if `V₁` is a submodule of `V`, then + `Module.rank (V/V₁) + Module.rank V₁ = Module.rank V`. +* `rank_range_add_rank_ker`: the rank-nullity theorem. +* `rank_dual_eq_card_dual_of_aleph0_le_rank`: The **Erdős-Kaplansky Theorem** which says that + the dimension of an infinite-dimensional dual space over a division ring has dimension + equal to its cardinality. + +-/ + + +noncomputable section + +universe u v v' v'' u₁' w w' + +variable {K R : Type u} {V V₁ V₂ V₃ : Type v} {V' V'₁ : Type v'} {V'' : Type v''} + +variable {ι : Type w} {ι' : Type w'} {η : Type u₁'} {φ : η → Type*} + +open BigOperators Cardinal Basis Submodule Function Set + +section Module + +section DivisionRing + +variable [DivisionRing K] + +variable [AddCommGroup V] [Module K V] + +variable [AddCommGroup V'] [Module K V'] + +variable [AddCommGroup V₁] [Module K V₁] + +/-- If a vector space has a finite dimension, the index set of `Basis.ofVectorSpace` is finite. -/ +theorem Basis.finite_ofVectorSpaceIndex_of_rank_lt_aleph0 (h : Module.rank K V < ℵ₀) : + (Basis.ofVectorSpaceIndex K V).Finite := + finite_def.2 <| (Basis.ofVectorSpace K V).nonempty_fintype_index_of_rank_lt_aleph0 h +#align basis.finite_of_vector_space_index_of_rank_lt_aleph_0 Basis.finite_ofVectorSpaceIndex_of_rank_lt_aleph0 + +-- TODO how far can we generalise this? +theorem rank_span_le (s : Set V) : Module.rank K (span K s) ≤ #s := by + obtain ⟨b, hb, hsab, hlib⟩ := exists_linearIndependent K s + convert Cardinal.mk_le_mk_of_subset hb + rw [← hsab, rank_span_set hlib] +#align rank_span_le rank_span_le + +theorem rank_quotient_add_rank (p : Submodule K V) : + Module.rank K (V ⧸ p) + Module.rank K p = Module.rank K V := by + classical + let ⟨f⟩ := quotient_prod_linearEquiv p + exact rank_prod'.symm.trans f.rank_eq +#align rank_quotient_add_rank rank_quotient_add_rank + +/-- The **rank-nullity theorem** -/ +theorem rank_range_add_rank_ker (f : V →ₗ[K] V₁) : + Module.rank K (LinearMap.range f) + Module.rank K (LinearMap.ker f) = Module.rank K V := by + haveI := fun p : Submodule K V => Classical.decEq (V ⧸ p) + rw [← f.quotKerEquivRange.rank_eq, rank_quotient_add_rank] +#align rank_range_add_rank_ker rank_range_add_rank_ker + +theorem rank_eq_of_surjective (f : V →ₗ[K] V₁) (h : Surjective f) : + Module.rank K V = Module.rank K V₁ + Module.rank K (LinearMap.ker f) := by + rw [← rank_range_add_rank_ker f, ← rank_range_of_surjective f h] +#align rank_eq_of_surjective rank_eq_of_surjective + +/-- Given a family of `n` linearly independent vectors in a space of dimension `> n`, one may extend +the family by another vector while retaining linear independence. -/ +theorem exists_linearIndependent_cons_of_lt_rank {n : ℕ} {v : Fin n → V} + (hv : LinearIndependent K v) (h : n < Module.rank K V) : + ∃ (x : V), LinearIndependent K (Fin.cons x v) := by + have A : Submodule.span K (range v) ≠ ⊤ := by + intro H + rw [← rank_top, ← H] at h + have : Module.rank K (Submodule.span K (range v)) ≤ n := by + have := Cardinal.mk_range_le_lift (f := v) + simp only [Cardinal.lift_id'] at this + exact (rank_span_le _).trans (this.trans (by simp)) + exact lt_irrefl _ (h.trans_le this) + obtain ⟨x, hx⟩ : ∃ x, x ∉ Submodule.span K (range v) := by + contrapose! A + exact Iff.mpr Submodule.eq_top_iff' A + exact ⟨x, linearIndependent_fin_cons.2 ⟨hv, hx⟩⟩ + +/-- Given a family of `n` linearly independent vectors in a space of dimension `> n`, one may extend +the family by another vector while retaining linear independence. -/ +theorem exists_linearIndependent_snoc_of_lt_rank {n : ℕ} {v : Fin n → V} + (hv : LinearIndependent K v) (h : n < Module.rank K V) : + ∃ (x : V), LinearIndependent K (Fin.snoc v x) := by + simpa [linearIndependent_fin_cons, ← linearIndependent_fin_snoc] + using exists_linearIndependent_cons_of_lt_rank hv h + +/-- Given a nonzero vector in a space of dimension `> 1`, one may find another vector linearly +independent of the first one. -/ +theorem exists_linearIndependent_pair_of_one_lt_rank + (h : 1 < Module.rank K V) {x : V} (hx : x ≠ 0) : + ∃ y, LinearIndependent K ![x, y] := by + obtain ⟨y, hy⟩ := exists_linearIndependent_snoc_of_lt_rank (linearIndependent_unique ![x] hx) h + have : Fin.snoc ![x] y = ![x, y] := Iff.mp List.ofFn_inj rfl + rw [this] at hy + exact ⟨y, hy⟩ + +section + +variable [AddCommGroup V₂] [Module K V₂] + +variable [AddCommGroup V₃] [Module K V₃] + +open LinearMap + +/-- This is mostly an auxiliary lemma for `Submodule.rank_sup_add_rank_inf_eq`. -/ +theorem rank_add_rank_split (db : V₂ →ₗ[K] V) (eb : V₃ →ₗ[K] V) (cd : V₁ →ₗ[K] V₂) + (ce : V₁ →ₗ[K] V₃) (hde : ⊤ ≤ LinearMap.range db ⊔ LinearMap.range eb) (hgd : ker cd = ⊥) + (eq : db.comp cd = eb.comp ce) (eq₂ : ∀ d e, db d = eb e → ∃ c, cd c = d ∧ ce c = e) : + Module.rank K V + Module.rank K V₁ = Module.rank K V₂ + Module.rank K V₃ := by + have hf : Surjective (coprod db eb) := by rwa [← range_eq_top, range_coprod, eq_top_iff] + conv => + rhs + rw [← rank_prod', rank_eq_of_surjective _ hf] + congr 1 + apply LinearEquiv.rank_eq + let L : V₁ →ₗ[K] ker (coprod db eb) := by -- Porting note: this is needed to avoid a timeout + refine' LinearMap.codRestrict _ (prod cd (-ce)) _ + · intro c + simp only [add_eq_zero_iff_eq_neg, LinearMap.prod_apply, mem_ker, Pi.prod, coprod_apply, + neg_neg, map_neg, neg_apply] + exact LinearMap.ext_iff.1 eq c + refine' LinearEquiv.ofBijective L ⟨_, _⟩ + · rw [← ker_eq_bot, ker_codRestrict, ker_prod, hgd, bot_inf_eq] + · rw [← range_eq_top, eq_top_iff, range_codRestrict, ← map_le_iff_le_comap, Submodule.map_top, + range_subtype] + rintro ⟨d, e⟩ + have h := eq₂ d (-e) + simp only [add_eq_zero_iff_eq_neg, LinearMap.prod_apply, mem_ker, SetLike.mem_coe, + Prod.mk.inj_iff, coprod_apply, map_neg, neg_apply, LinearMap.mem_range, Pi.prod] at h ⊢ + intro hde + rcases h hde with ⟨c, h₁, h₂⟩ + refine' ⟨c, h₁, _⟩ + rw [h₂, _root_.neg_neg] +#align rank_add_rank_split rank_add_rank_split + +theorem Submodule.rank_sup_add_rank_inf_eq (s t : Submodule K V) : + Module.rank K (s ⊔ t : Submodule K V) + Module.rank K (s ⊓ t : Submodule K V) = + Module.rank K s + Module.rank K t := + rank_add_rank_split + (inclusion le_sup_left) (inclusion le_sup_right) + (inclusion inf_le_left) (inclusion inf_le_right) + (by + rw [← map_le_map_iff' (ker_subtype <| s ⊔ t), Submodule.map_sup, Submodule.map_top, ← + LinearMap.range_comp, ← LinearMap.range_comp, subtype_comp_inclusion, + subtype_comp_inclusion, range_subtype, range_subtype, range_subtype]) + (ker_inclusion _ _ _) (by ext ⟨x, hx⟩; rfl) + (by + rintro ⟨b₁, hb₁⟩ ⟨b₂, hb₂⟩ eq + obtain rfl : b₁ = b₂ := congr_arg Subtype.val eq + exact ⟨⟨b₁, hb₁, hb₂⟩, rfl, rfl⟩) +#align submodule.rank_sup_add_rank_inf_eq Submodule.rank_sup_add_rank_inf_eq + +theorem Submodule.rank_add_le_rank_add_rank (s t : Submodule K V) : + Module.rank K (s ⊔ t : Submodule K V) ≤ Module.rank K s + Module.rank K t := by + rw [← Submodule.rank_sup_add_rank_inf_eq] + exact self_le_add_right _ _ +#align submodule.rank_add_le_rank_add_rank Submodule.rank_add_le_rank_add_rank + +end + +end DivisionRing + +variable [DivisionRing K] [AddCommGroup V] [Module K V] [AddCommGroup V₁] [Module K V₁] + +variable [AddCommGroup V'] [Module K V'] + +/-- The `ι` indexed basis on `V`, where `ι` is an empty type and `V` is zero-dimensional. + +See also `FiniteDimensional.finBasis`. +-/ +def Basis.ofRankEqZero {ι : Type*} [IsEmpty ι] (hV : Module.rank K V = 0) : Basis ι K V := + haveI : Subsingleton V := rank_zero_iff.1 hV + Basis.empty _ +#align basis.of_rank_eq_zero Basis.ofRankEqZero + +@[simp] +theorem Basis.ofRankEqZero_apply {ι : Type*} [IsEmpty ι] (hV : Module.rank K V = 0) (i : ι) : + Basis.ofRankEqZero hV i = 0 := + rfl +#align basis.of_rank_eq_zero_apply Basis.ofRankEqZero_apply + +theorem le_rank_iff_exists_linearIndependent {c : Cardinal} : + c ≤ Module.rank K V ↔ ∃ s : Set V, #s = c ∧ LinearIndependent K ((↑) : s → V) := by + constructor + · intro h + let t := Basis.ofVectorSpace K V + rw [← t.mk_eq_rank'', Cardinal.le_mk_iff_exists_subset] at h + rcases h with ⟨s, hst, hsc⟩ + exact ⟨s, hsc, (ofVectorSpaceIndex.linearIndependent K V).mono hst⟩ + · rintro ⟨s, rfl, si⟩ + exact si.cardinal_le_rank +#align le_rank_iff_exists_linear_independent le_rank_iff_exists_linearIndependent + +theorem le_rank_iff_exists_linearIndependent_finset {n : ℕ} : ↑n ≤ Module.rank K V ↔ + ∃ s : Finset V, s.card = n ∧ LinearIndependent K ((↑) : ↥(s : Set V) → V) := by + simp only [le_rank_iff_exists_linearIndependent, Cardinal.mk_set_eq_nat_iff_finset] + constructor + · rintro ⟨s, ⟨t, rfl, rfl⟩, si⟩ + exact ⟨t, rfl, si⟩ + · rintro ⟨s, rfl, si⟩ + exact ⟨s, ⟨s, rfl, rfl⟩, si⟩ +#align le_rank_iff_exists_linear_independent_finset le_rank_iff_exists_linearIndependent_finset + +/-- A vector space has dimension at most `1` if and only if there is a +single vector of which all vectors are multiples. -/ +theorem rank_le_one_iff : Module.rank K V ≤ 1 ↔ ∃ v₀ : V, ∀ v, ∃ r : K, r • v₀ = v := by + let b := Basis.ofVectorSpace K V + constructor + · intro hd + rw [← b.mk_eq_rank'', Cardinal.le_one_iff_subsingleton, subsingleton_coe] at hd + rcases eq_empty_or_nonempty (ofVectorSpaceIndex K V) with (hb | ⟨⟨v₀, hv₀⟩⟩) + · use 0 + have h' : ∀ v : V, v = 0 := by simpa [hb, Submodule.eq_bot_iff] using b.span_eq.symm + intro v + simp [h' v] + · use v₀ + have h' : (K ∙ v₀) = ⊤ := by simpa [hd.eq_singleton_of_mem hv₀] using b.span_eq + intro v + have hv : v ∈ (⊤ : Submodule K V) := mem_top + rwa [← h', mem_span_singleton] at hv + · rintro ⟨v₀, hv₀⟩ + have h : (K ∙ v₀) = ⊤ := by + ext + simp [mem_span_singleton, hv₀] + rw [← rank_top, ← h] + refine' (rank_span_le _).trans_eq _ + simp +#align rank_le_one_iff rank_le_one_iff + +/-- A submodule has dimension at most `1` if and only if there is a +single vector in the submodule such that the submodule is contained in +its span. -/ +theorem rank_submodule_le_one_iff (s : Submodule K V) : + Module.rank K s ≤ 1 ↔ ∃ v₀ ∈ s, s ≤ K ∙ v₀ := by + simp_rw [rank_le_one_iff, le_span_singleton_iff] + constructor + · rintro ⟨⟨v₀, hv₀⟩, h⟩ + use v₀, hv₀ + intro v hv + obtain ⟨r, hr⟩ := h ⟨v, hv⟩ + use r + simp_rw [Subtype.ext_iff, coe_smul] at hr + exact hr + · rintro ⟨v₀, hv₀, h⟩ + use ⟨v₀, hv₀⟩ + rintro ⟨v, hv⟩ + obtain ⟨r, hr⟩ := h v hv + use r + simp_rw [Subtype.ext_iff, coe_smul] + exact hr +#align rank_submodule_le_one_iff rank_submodule_le_one_iff + +/-- A submodule has dimension at most `1` if and only if there is a +single vector, not necessarily in the submodule, such that the +submodule is contained in its span. -/ +theorem rank_submodule_le_one_iff' (s : Submodule K V) : + Module.rank K s ≤ 1 ↔ ∃ v₀, s ≤ K ∙ v₀ := by + rw [rank_submodule_le_one_iff] + constructor + · rintro ⟨v₀, _, h⟩ + exact ⟨v₀, h⟩ + · rintro ⟨v₀, h⟩ + by_cases hw : ∃ w : V, w ∈ s ∧ w ≠ 0 + · rcases hw with ⟨w, hw, hw0⟩ + use w, hw + rcases mem_span_singleton.1 (h hw) with ⟨r', rfl⟩ + have h0 : r' ≠ 0 := by + rintro rfl + simp at hw0 + rwa [span_singleton_smul_eq (IsUnit.mk0 _ h0) _] + · push_neg at hw + rw [← Submodule.eq_bot_iff] at hw + simp [hw] +#align rank_submodule_le_one_iff' rank_submodule_le_one_iff' + +theorem Submodule.rank_le_one_iff_isPrincipal (W : Submodule K V) : + Module.rank K W ≤ 1 ↔ W.IsPrincipal := by + simp only [rank_le_one_iff, Submodule.IsPrincipal_iff, le_antisymm_iff, le_span_singleton_iff, + span_singleton_le_iff_mem] + constructor + · rintro ⟨⟨m, hm⟩, hm'⟩ + choose f hf using hm' + exact ⟨m, ⟨fun v hv => ⟨f ⟨v, hv⟩, congr_arg ((↑) : W → V) (hf ⟨v, hv⟩)⟩, hm⟩⟩ + · rintro ⟨a, ⟨h, ha⟩⟩ + choose f hf using h + exact ⟨⟨a, ha⟩, fun v => ⟨f v.1 v.2, Subtype.ext (hf v.1 v.2)⟩⟩ +#align submodule.rank_le_one_iff_is_principal Submodule.rank_le_one_iff_isPrincipal + +theorem Module.rank_le_one_iff_top_isPrincipal : + Module.rank K V ≤ 1 ↔ (⊤ : Submodule K V).IsPrincipal := by + rw [← Submodule.rank_le_one_iff_isPrincipal, rank_top] +#align module.rank_le_one_iff_top_is_principal Module.rank_le_one_iff_top_isPrincipal + +end Module + +section Span + +open Submodule FiniteDimensional + +variable [DivisionRing K] [AddCommGroup V] [Module K V] + +variable (K) + +/-- The rank of a set of vectors as a natural number. -/ +protected noncomputable def Set.finrank (s : Set V) : ℕ := + finrank K (span K s) +#align set.finrank Set.finrank + +variable {K} + +theorem finrank_span_le_card (s : Set V) [Fintype s] : finrank K (span K s) ≤ s.toFinset.card := + finrank_le_of_rank_le (by simpa using rank_span_le (K := K) s) +#align finrank_span_le_card finrank_span_le_card + +theorem finrank_span_finset_le_card (s : Finset V) : (s : Set V).finrank K ≤ s.card := + calc + (s : Set V).finrank K ≤ (s : Set V).toFinset.card := finrank_span_le_card (V := V) s + _ = s.card := by simp +#align finrank_span_finset_le_card finrank_span_finset_le_card + +theorem finrank_range_le_card {ι : Type*} [Fintype ι] {b : ι → V} : + (Set.range b).finrank K ≤ Fintype.card ι := by + classical + refine (finrank_span_le_card _).trans ?_ + rw [Set.toFinset_range] + exact Finset.card_image_le +#align finrank_range_le_card finrank_range_le_card + +theorem finrank_span_eq_card {ι : Type*} [Fintype ι] {b : ι → V} (hb : LinearIndependent K b) : + finrank K (span K (Set.range b)) = Fintype.card ι := + finrank_eq_of_rank_eq + (by + have : Module.rank K (span K (Set.range b)) = #(Set.range b) := rank_span hb + rwa [← lift_inj, mk_range_eq_of_injective hb.injective, Cardinal.mk_fintype, lift_natCast, + lift_eq_nat_iff] at this) +#align finrank_span_eq_card finrank_span_eq_card + +theorem finrank_span_set_eq_card (s : Set V) [Fintype s] (hs : LinearIndependent K ((↑) : s → V)) : + finrank K (span K s) = s.toFinset.card := + finrank_eq_of_rank_eq + (by + have : Module.rank K (span K s) = #s := rank_span_set hs + rwa [Cardinal.mk_fintype, ← Set.toFinset_card] at this) +#align finrank_span_set_eq_card finrank_span_set_eq_card + +theorem finrank_span_finset_eq_card (s : Finset V) (hs : LinearIndependent K ((↑) : s → V)) : + finrank K (span K (s : Set V)) = s.card := by + convert finrank_span_set_eq_card (s : Set V) hs + ext + simp +#align finrank_span_finset_eq_card finrank_span_finset_eq_card + +theorem span_lt_of_subset_of_card_lt_finrank {s : Set V} [Fintype s] {t : Submodule K V} + (subset : s ⊆ t) (card_lt : s.toFinset.card < finrank K t) : span K s < t := + lt_of_le_of_finrank_lt_finrank (span_le.mpr subset) + (lt_of_le_of_lt (finrank_span_le_card _) card_lt) +#align span_lt_of_subset_of_card_lt_finrank span_lt_of_subset_of_card_lt_finrank + +theorem span_lt_top_of_card_lt_finrank {s : Set V} [Fintype s] + (card_lt : s.toFinset.card < finrank K V) : span K s < ⊤ := + lt_top_of_finrank_lt_finrank (lt_of_le_of_lt (finrank_span_le_card _) card_lt) +#align span_lt_top_of_card_lt_finrank span_lt_top_of_card_lt_finrank + +/-- Given a family of `n` linearly independent vectors in a finite-dimensional space of +dimension `> n`, one may extend the family by another vector while retaining linear independence. -/ +theorem exists_linearIndependent_snoc_of_lt_finrank {n : ℕ} {v : Fin n → V} + (hv : LinearIndependent K v) (h : n < finrank K V) : + ∃ (x : V), LinearIndependent K (Fin.snoc v x) := + exists_linearIndependent_snoc_of_lt_rank hv (lt_rank_of_lt_finrank h) + +/-- Given a family of `n` linearly independent vectors in a finite-dimensional space of +dimension `> n`, one may extend the family by another vector while retaining linear independence. -/ +theorem exists_linearIndependent_cons_of_lt_finrank {n : ℕ} {v : Fin n → V} + (hv : LinearIndependent K v) (h : n < finrank K V) : + ∃ (x : V), LinearIndependent K (Fin.cons x v) := + exists_linearIndependent_cons_of_lt_rank hv (lt_rank_of_lt_finrank h) + +/-- Given a nonzero vector in a finite-dimensional space of dimension `> 1`, one may find another +vector linearly independent of the first one. -/ +theorem exists_linearIndependent_pair_of_one_lt_finrank + (h : 1 < finrank K V) {x : V} (hx : x ≠ 0) : + ∃ y, LinearIndependent K ![x, y] := + exists_linearIndependent_pair_of_one_lt_rank (one_lt_rank_of_one_lt_finrank h) hx + +end Span + +section Basis + +open FiniteDimensional + +variable [DivisionRing K] [AddCommGroup V] [Module K V] + +theorem linearIndependent_of_top_le_span_of_card_eq_finrank {ι : Type*} [Fintype ι] {b : ι → V} + (spans : ⊤ ≤ span K (Set.range b)) (card_eq : Fintype.card ι = finrank K V) : + LinearIndependent K b := + linearIndependent_iff'.mpr fun s g dependent i i_mem_s => by + classical + by_contra gx_ne_zero + -- We'll derive a contradiction by showing `b '' (univ \ {i})` of cardinality `n - 1` + -- spans a vector space of dimension `n`. + refine' not_le_of_gt (span_lt_top_of_card_lt_finrank + (show (b '' (Set.univ \ {i})).toFinset.card < finrank K V from _)) _ + · calc + (b '' (Set.univ \ {i})).toFinset.card = ((Set.univ \ {i}).toFinset.image b).card := by + rw [Set.toFinset_card, Fintype.card_ofFinset] + _ ≤ (Set.univ \ {i}).toFinset.card := Finset.card_image_le + _ = (Finset.univ.erase i).card := (congr_arg Finset.card (Finset.ext (by simp [and_comm]))) + _ < Finset.univ.card := (Finset.card_erase_lt_of_mem (Finset.mem_univ i)) + _ = finrank K V := card_eq + -- We already have that `b '' univ` spans the whole space, + -- so we only need to show that the span of `b '' (univ \ {i})` contains each `b j`. + refine' spans.trans (span_le.mpr _) + rintro _ ⟨j, rfl, rfl⟩ + -- The case that `j ≠ i` is easy because `b j ∈ b '' (univ \ {i})`. + by_cases j_eq : j = i + swap + · refine' subset_span ⟨j, (Set.mem_diff _).mpr ⟨Set.mem_univ _, _⟩, rfl⟩ + exact mt Set.mem_singleton_iff.mp j_eq + -- To show `b i ∈ span (b '' (univ \ {i}))`, we use that it's a weighted sum + -- of the other `b j`s. + rw [j_eq, SetLike.mem_coe, show b i = -((g i)⁻¹ • (s.erase i).sum fun j => g j • b j) from _] + · refine' neg_mem (smul_mem _ _ (sum_mem fun k hk => _)) + obtain ⟨k_ne_i, _⟩ := Finset.mem_erase.mp hk + refine' smul_mem _ _ (subset_span ⟨k, _, rfl⟩) + simp_all only [Set.mem_univ, Set.mem_diff, Set.mem_singleton_iff, and_self, not_false_eq_true] + -- To show `b i` is a weighted sum of the other `b j`s, we'll rewrite this sum + -- to have the form of the assumption `dependent`. + apply eq_neg_of_add_eq_zero_left + calc + (b i + (g i)⁻¹ • (s.erase i).sum fun j => g j • b j) = + (g i)⁻¹ • (g i • b i + (s.erase i).sum fun j => g j • b j) := + by rw [smul_add, ← mul_smul, inv_mul_cancel gx_ne_zero, one_smul] + _ = (g i)⁻¹ • (0 : V) := (congr_arg _ ?_) + _ = 0 := smul_zero _ + -- And then it's just a bit of manipulation with finite sums. + rwa [← Finset.insert_erase i_mem_s, Finset.sum_insert (Finset.not_mem_erase _ _)] at dependent +#align linear_independent_of_top_le_span_of_card_eq_finrank linearIndependent_of_top_le_span_of_card_eq_finrank + +/-- A finite family of vectors is linearly independent if and only if +its cardinality equals the dimension of its span. -/ +theorem linearIndependent_iff_card_eq_finrank_span {ι : Type*} [Fintype ι] {b : ι → V} : + LinearIndependent K b ↔ Fintype.card ι = (Set.range b).finrank K := by + constructor + · intro h + exact (finrank_span_eq_card h).symm + · intro hc + let f := Submodule.subtype (span K (Set.range b)) + let b' : ι → span K (Set.range b) := fun i => + ⟨b i, mem_span.2 fun p hp => hp (Set.mem_range_self _)⟩ + have hs : ⊤ ≤ span K (Set.range b') := by + intro x + have h : span K (f '' Set.range b') = map f (span K (Set.range b')) := span_image f + have hf : f '' Set.range b' = Set.range b := by + ext x + simp [Set.mem_image, Set.mem_range] + rw [hf] at h + have hx : (x : V) ∈ span K (Set.range b) := x.property + conv at hx => + arg 2 + rw [h] + simpa [mem_map] using hx + have hi : LinearMap.ker f = ⊥ := ker_subtype _ + convert (linearIndependent_of_top_le_span_of_card_eq_finrank hs hc).map' _ hi +#align linear_independent_iff_card_eq_finrank_span linearIndependent_iff_card_eq_finrank_span + +theorem linearIndependent_iff_card_le_finrank_span {ι : Type*} [Fintype ι] {b : ι → V} : + LinearIndependent K b ↔ Fintype.card ι ≤ (Set.range b).finrank K := by + rw [linearIndependent_iff_card_eq_finrank_span, finrank_range_le_card.le_iff_eq] +#align linear_independent_iff_card_le_finrank_span linearIndependent_iff_card_le_finrank_span + +/-- A family of `finrank K V` vectors forms a basis if they span the whole space. -/ +noncomputable def basisOfTopLeSpanOfCardEqFinrank {ι : Type*} [Fintype ι] (b : ι → V) + (le_span : ⊤ ≤ span K (Set.range b)) (card_eq : Fintype.card ι = finrank K V) : Basis ι K V := + Basis.mk (linearIndependent_of_top_le_span_of_card_eq_finrank le_span card_eq) le_span +#align basis_of_top_le_span_of_card_eq_finrank basisOfTopLeSpanOfCardEqFinrank + +@[simp] +theorem coe_basisOfTopLeSpanOfCardEqFinrank {ι : Type*} [Fintype ι] (b : ι → V) + (le_span : ⊤ ≤ span K (Set.range b)) (card_eq : Fintype.card ι = finrank K V) : + ⇑(basisOfTopLeSpanOfCardEqFinrank b le_span card_eq) = b := + Basis.coe_mk _ _ +#align coe_basis_of_top_le_span_of_card_eq_finrank coe_basisOfTopLeSpanOfCardEqFinrank + +/-- A finset of `finrank K V` vectors forms a basis if they span the whole space. -/ +@[simps! repr_apply] +noncomputable def finsetBasisOfTopLeSpanOfCardEqFinrank {s : Finset V} + (le_span : ⊤ ≤ span K (s : Set V)) (card_eq : s.card = finrank K V) : Basis {x // x ∈ s} K V := + basisOfTopLeSpanOfCardEqFinrank ((↑) : ↥(s : Set V) → V) + ((@Subtype.range_coe_subtype _ fun x => x ∈ s).symm ▸ le_span) + (_root_.trans (Fintype.card_coe _) card_eq) +#align finset_basis_of_top_le_span_of_card_eq_finrank finsetBasisOfTopLeSpanOfCardEqFinrank + +/-- A set of `finrank K V` vectors forms a basis if they span the whole space. -/ +@[simps! repr_apply] +noncomputable def setBasisOfTopLeSpanOfCardEqFinrank {s : Set V} [Fintype s] + (le_span : ⊤ ≤ span K s) (card_eq : s.toFinset.card = finrank K V) : Basis s K V := + basisOfTopLeSpanOfCardEqFinrank ((↑) : s → V) ((@Subtype.range_coe_subtype _ s).symm ▸ le_span) + (_root_.trans s.toFinset_card.symm card_eq) +#align set_basis_of_top_le_span_of_card_eq_finrank setBasisOfTopLeSpanOfCardEqFinrank + +end Basis + +section Cardinal + +variable (K) + +variable [DivisionRing K] + +/-- Key lemma towards the Erdős-Kaplansky theorem from https://mathoverflow.net/a/168624 -/ +theorem max_aleph0_card_le_rank_fun_nat : max ℵ₀ #K ≤ Module.rank K (ℕ → K) := by + have aleph0_le : ℵ₀ ≤ Module.rank K (ℕ → K) := (rank_finsupp_self K ℕ).symm.trans_le + (Finsupp.lcoeFun.rank_le_of_injective <| by exact FunLike.coe_injective) + refine max_le aleph0_le ?_ + obtain card_K | card_K := le_or_lt #K ℵ₀ + · exact card_K.trans aleph0_le + by_contra! + obtain ⟨⟨ιK, bK⟩⟩ := Module.Free.exists_basis (R := K) (M := ℕ → K) + let L := Subfield.closure (Set.range (fun i : ιK × ℕ ↦ bK i.1 i.2)) + have hLK : #L < #K + · refine (Subfield.cardinal_mk_closure_le_max _).trans_lt + (max_lt_iff.mpr ⟨mk_range_le.trans_lt ?_, card_K⟩) + rwa [mk_prod, ← aleph0, lift_uzero, bK.mk_eq_rank'', mul_aleph0_eq aleph0_le] + letI := Module.compHom K (RingHom.op L.subtype) + obtain ⟨⟨ιL, bL⟩⟩ := Module.Free.exists_basis (R := Lᵐᵒᵖ) (M := K) + have card_ιL : ℵ₀ ≤ #ιL + · contrapose! hLK + haveI := @Fintype.ofFinite _ (lt_aleph0_iff_finite.mp hLK) + rw [bL.repr.toEquiv.cardinal_eq, mk_finsupp_of_fintype, + ← MulOpposite.opEquiv.cardinal_eq] at card_K ⊢ + apply power_nat_le + contrapose! card_K + exact (power_lt_aleph0 card_K <| nat_lt_aleph0 _).le + obtain ⟨e⟩ := lift_mk_le'.mp (card_ιL.trans_eq (lift_uzero #ιL).symm) + have rep_e := bK.total_repr (bL ∘ e) + rw [Finsupp.total_apply, Finsupp.sum] at rep_e + set c := bK.repr (bL ∘ e) + set s := c.support + let f i (j : s) : L := ⟨bK j i, Subfield.subset_closure ⟨(j, i), rfl⟩⟩ + have : ¬LinearIndependent Lᵐᵒᵖ f := fun h ↦ by + have := h.cardinal_lift_le_rank + rw [lift_uzero, (LinearEquiv.piCongrRight fun _ ↦ MulOpposite.opLinearEquiv Lᵐᵒᵖ).rank_eq, + rank_fun'] at this + exact (nat_lt_aleph0 _).not_le this + obtain ⟨t, g, eq0, i, hi, hgi⟩ := not_linearIndependent_iff.mp this + refine hgi (linearIndependent_iff'.mp (bL.linearIndependent.comp e e.injective) t g ?_ i hi) + clear_value c s + simp_rw [← rep_e, Finset.sum_apply, Pi.smul_apply, Finset.smul_sum] + rw [Finset.sum_comm] + refine Finset.sum_eq_zero fun i hi ↦ ?_ + replace eq0 := congr_arg L.subtype (congr_fun eq0 ⟨i, hi⟩) + rw [Finset.sum_apply, map_sum] at eq0 + have : SMulCommClass Lᵐᵒᵖ K K := ⟨fun _ _ _ ↦ mul_assoc _ _ _⟩ + simp_rw [smul_comm _ (c i), ← Finset.smul_sum] + erw [eq0, smul_zero] + +variable {K} + +open Function in +theorem rank_fun_infinite {ι : Type v} [hι : Infinite ι] : Module.rank K (ι → K) = #(ι → K) := by + obtain ⟨⟨ιK, bK⟩⟩ := Module.Free.exists_basis (R := K) (M := ι → K) + obtain ⟨e⟩ := lift_mk_le'.mp ((aleph0_le_mk_iff.mpr hι).trans_eq (lift_uzero #ι).symm) + have := LinearMap.lift_rank_le_of_injective _ <| + LinearMap.funLeft_injective_of_surjective K K _ (invFun_surjective e.injective) + rw [lift_umax.{u,v}, lift_id'.{u,v}] at this + have key := (lift_le.{v}.mpr <| max_aleph0_card_le_rank_fun_nat K).trans this + rw [lift_max, lift_aleph0, max_le_iff] at key + haveI : Infinite ιK := by + rw [← aleph0_le_mk_iff, bK.mk_eq_rank'']; exact key.1 + rw [bK.repr.toEquiv.cardinal_eq, mk_finsupp_lift_of_infinite, + lift_umax.{u,v}, lift_id'.{u,v}, bK.mk_eq_rank'', eq_comm, max_eq_left] + exact key.2 + +/-- The **Erdős-Kaplansky Theorem**: the dual of an infinite-dimensional vector space + over a division ring has dimension equal to its cardinality. -/ +theorem rank_dual_eq_card_dual_of_aleph0_le_rank' {V : Type*} [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : Module.rank Kᵐᵒᵖ (V →ₗ[K] K) = #(V →ₗ[K] K) := by + obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) + rw [← b.mk_eq_rank'', aleph0_le_mk_iff] at h + have e := (b.constr Kᵐᵒᵖ (M' := K)).symm.trans + (LinearEquiv.piCongrRight fun _ ↦ MulOpposite.opLinearEquiv Kᵐᵒᵖ) + rw [e.rank_eq, e.toEquiv.cardinal_eq] + apply rank_fun_infinite + +/-- The **Erdős-Kaplansky Theorem** over a field. -/ +theorem rank_dual_eq_card_dual_of_aleph0_le_rank {K V} [Field K] [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : Module.rank K (V →ₗ[K] K) = #(V →ₗ[K] K) := by + obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) + rw [← b.mk_eq_rank'', aleph0_le_mk_iff] at h + have e := (b.constr K (M' := K)).symm + rw [e.rank_eq, e.toEquiv.cardinal_eq] + apply rank_fun_infinite + +theorem lift_rank_lt_rank_dual' {V : Type v} [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : + Cardinal.lift.{u} (Module.rank K V) < Module.rank Kᵐᵒᵖ (V →ₗ[K] K) := by + obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) + rw [← b.mk_eq_rank'', rank_dual_eq_card_dual_of_aleph0_le_rank' h, + ← (b.constr ℕ (M' := K)).toEquiv.cardinal_eq, mk_arrow] + apply cantor' + erw [nat_lt_lift_iff, one_lt_iff_nontrivial] + infer_instance + +theorem lift_rank_lt_rank_dual {K : Type u} {V : Type v} [Field K] [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : + Cardinal.lift.{u} (Module.rank K V) < Module.rank K (V →ₗ[K] K) := by + rw [rank_dual_eq_card_dual_of_aleph0_le_rank h, ← rank_dual_eq_card_dual_of_aleph0_le_rank' h] + exact lift_rank_lt_rank_dual' h + +theorem rank_lt_rank_dual' {V : Type u} [AddCommGroup V] [Module K V] (h : ℵ₀ ≤ Module.rank K V) : + Module.rank K V < Module.rank Kᵐᵒᵖ (V →ₗ[K] K) := by + convert lift_rank_lt_rank_dual' h; rw [lift_id] + +theorem rank_lt_rank_dual {K V : Type u} [Field K] [AddCommGroup V] [Module K V] + (h : ℵ₀ ≤ Module.rank K V) : Module.rank K V < Module.rank K (V →ₗ[K] K) := by + convert lift_rank_lt_rank_dual h; rw [lift_id] + +end Cardinal diff --git a/Mathlib/LinearAlgebra/Dimension/Finite.lean b/Mathlib/LinearAlgebra/Dimension/Finite.lean new file mode 100644 index 0000000000000..dfd6dbd4c9189 --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/Finite.lean @@ -0,0 +1,518 @@ +/- +Copyright (c) 2018 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison +-/ +import Mathlib.LinearAlgebra.Dimension.Free +import Mathlib.Algebra.Module.Torsion +import Mathlib.SetTheory.Cardinal.Cofinality +import Mathlib.LinearAlgebra.FreeModule.Finite.Basic + + +#align_import linear_algebra.dimension from "leanprover-community/mathlib"@"47a5f8186becdbc826190ced4312f8199f9db6a5" + +/-! +# Conditions for rank to be finite + +Also contains characterization for when rank equals zero or rank equals one. + +-/ + + +noncomputable section + +universe u v v' w + +variable {R : Type u} {M M₁ : Type v} {M' : Type v'} {ι : Type w} + +variable [Ring R] [AddCommGroup M] [AddCommGroup M'] [AddCommGroup M₁] + +variable [Module R M] [Module R M'] [Module R M₁] + +attribute [local instance] nontrivial_of_invariantBasisNumber + +open BigOperators Cardinal Basis Submodule Function Set FiniteDimensional + +theorem rank_le {n : ℕ} + (H : ∀ s : Finset M, (LinearIndependent R fun i : s => (i : M)) → s.card ≤ n) : + Module.rank R M ≤ n := by + rw [Module.rank_def] + apply ciSup_le' + rintro ⟨s, li⟩ + exact linearIndependent_bounded_of_finset_linearIndependent_bounded H _ li +#align rank_le rank_le + +section RankZero + +/-- See `rank_zero_iff` for a stronger version with `NoZeroSMulDivisor R M`. -/ +lemma rank_eq_zero_iff : + Module.rank R M = 0 ↔ ∀ x : M, ∃ a : R, a ≠ 0 ∧ a • x = 0 := by + nontriviality R + constructor + · contrapose! + rintro ⟨x, hx⟩ + rw [← Cardinal.one_le_iff_ne_zero] + have : LinearIndependent R (fun _ : Unit ↦ x) + · exact linearIndependent_iff.mpr (fun l hl ↦ Finsupp.unique_ext <| not_not.mp fun H ↦ + hx _ H ((Finsupp.total_unique _ _ _).symm.trans hl)) + simpa using this.cardinal_lift_le_rank + · intro h + rw [← le_zero_iff, Module.rank_def] + apply ciSup_le' + intro ⟨s, hs⟩ + rw [nonpos_iff_eq_zero, Cardinal.mk_eq_zero_iff, ← not_nonempty_iff] + rintro ⟨i : s⟩ + obtain ⟨a, ha, ha'⟩ := h i + apply ha + simpa using FunLike.congr_fun (linearIndependent_iff.mp hs (Finsupp.single i a) (by simpa)) i + +variable [Nontrivial R] + +variable [NoZeroSMulDivisors R M] + +theorem rank_zero_iff_forall_zero [NoZeroSMulDivisors R M] : + Module.rank R M = 0 ↔ ∀ x : M, x = 0 := by + simp_rw [rank_eq_zero_iff, smul_eq_zero, and_or_left, not_and_self_iff, false_or, + exists_and_right, and_iff_right (exists_ne (0 : R))] +#align rank_zero_iff_forall_zero rank_zero_iff_forall_zero + +/-- See `rank_subsingleton` for the reason that `Nontrivial R` is needed. +Also see `rank_eq_zero_iff` for the version without `NoZeroSMulDivisor R M`. -/ +theorem rank_zero_iff : Module.rank R M = 0 ↔ Subsingleton M := + rank_zero_iff_forall_zero.trans (subsingleton_iff_forall_eq 0).symm +#align rank_zero_iff rank_zero_iff + +theorem rank_pos_iff_exists_ne_zero : 0 < Module.rank R M ↔ ∃ x : M, x ≠ 0 := by + rw [← not_iff_not] + simpa using rank_zero_iff_forall_zero +#align rank_pos_iff_exists_ne_zero rank_pos_iff_exists_ne_zero + +theorem rank_pos_iff_nontrivial : 0 < Module.rank R M ↔ Nontrivial M := + rank_pos_iff_exists_ne_zero.trans (nontrivial_iff_exists_ne 0).symm +#align rank_pos_iff_nontrivial rank_pos_iff_nontrivial + +lemma rank_eq_zero_iff_isTorsion {R M} [CommRing R] [IsDomain R] [AddCommGroup M] [Module R M] : + Module.rank R M = 0 ↔ Module.IsTorsion R M := by + rw [Module.IsTorsion, rank_eq_zero_iff] + simp [mem_nonZeroDivisors_iff_ne_zero] + +theorem rank_pos [NoZeroSMulDivisors R M] [Nontrivial M] : 0 < Module.rank R M := + rank_pos_iff_nontrivial.mpr ‹_› +#align rank_pos rank_pos + +variable (R M) + +/-- See `rank_subsingleton` that assumes `Subsingleton R` instead. -/ +theorem rank_subsingleton' [Subsingleton M] : Module.rank R M = 0 := + rank_eq_zero_iff.mpr fun _ ↦ ⟨1, one_ne_zero, Subsingleton.elim _ _⟩ + +@[simp] +theorem rank_punit : Module.rank R PUnit = 0 := rank_subsingleton' _ _ +#align rank_punit rank_punit + +@[simp] +theorem rank_bot : Module.rank R (⊥ : Submodule R M) = 0 := rank_subsingleton' _ _ +#align rank_bot rank_bot + +variable {R M} + +theorem exists_mem_ne_zero_of_rank_pos {s : Submodule R M} (h : 0 < Module.rank R s) : + ∃ b : M, b ∈ s ∧ b ≠ 0 := + exists_mem_ne_zero_of_ne_bot fun eq => by rw [eq, rank_bot] at h; exact lt_irrefl _ h +#align exists_mem_ne_zero_of_rank_pos exists_mem_ne_zero_of_rank_pos + +end RankZero + +section Finite + +theorem Module.finite_of_rank_eq_nat [Module.Free R M] {n : ℕ} (h : Module.rank R M = n) : + Module.Finite R M := by + nontriviality R + obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := R) (M := M) + have := mk_lt_aleph0_iff.mp <| + b.linearIndependent.cardinal_le_rank |>.trans_eq h |>.trans_lt <| nat_lt_aleph0 n + exact Module.Finite.of_basis b + +theorem Module.finite_of_rank_eq_zero [NoZeroSMulDivisors R M] + (h : Module.rank R M = 0) : + Module.Finite R M := by + nontriviality R + rw [rank_zero_iff] at h + infer_instance + +theorem Module.finite_of_rank_eq_one [Module.Free R M] (h : Module.rank R M = 1) : + Module.Finite R M := + Module.finite_of_rank_eq_nat <| h.trans Nat.cast_one.symm + +variable [StrongRankCondition R] + +/-- If a module has a finite dimension, all bases are indexed by a finite type. -/ +theorem Basis.nonempty_fintype_index_of_rank_lt_aleph0 {ι : Type*} (b : Basis ι R M) + (h : Module.rank R M < ℵ₀) : Nonempty (Fintype ι) := by + rwa [← Cardinal.lift_lt, ← b.mk_eq_rank, Cardinal.lift_aleph0, Cardinal.lift_lt_aleph0, + Cardinal.lt_aleph0_iff_fintype] at h +#align basis.nonempty_fintype_index_of_rank_lt_aleph_0 Basis.nonempty_fintype_index_of_rank_lt_aleph0 + +/-- If a module has a finite dimension, all bases are indexed by a finite type. -/ +noncomputable def Basis.fintypeIndexOfRankLtAleph0 {ι : Type*} (b : Basis ι R M) + (h : Module.rank R M < ℵ₀) : Fintype ι := + Classical.choice (b.nonempty_fintype_index_of_rank_lt_aleph0 h) +#align basis.fintype_index_of_rank_lt_aleph_0 Basis.fintypeIndexOfRankLtAleph0 + +/-- If a module has a finite dimension, all bases are indexed by a finite set. -/ +theorem Basis.finite_index_of_rank_lt_aleph0 {ι : Type*} {s : Set ι} (b : Basis s R M) + (h : Module.rank R M < ℵ₀) : s.Finite := + finite_def.2 (b.nonempty_fintype_index_of_rank_lt_aleph0 h) +#align basis.finite_index_of_rank_lt_aleph_0 Basis.finite_index_of_rank_lt_aleph0 + +namespace LinearIndependent + +theorem cardinal_mk_le_finrank [Module.Finite R M] + {ι : Type w} {b : ι → M} (h : LinearIndependent R b) : #ι ≤ finrank R M := by + rw [← lift_le.{max v w}] + simpa only [← finrank_eq_rank, lift_natCast, lift_le_nat_iff] using h.cardinal_lift_le_rank +#align finite_dimensional.cardinal_mk_le_finrank_of_linear_independent LinearIndependent.cardinal_mk_le_finrank + +theorem fintype_card_le_finrank [Module.Finite R M] + {ι : Type*} [Fintype ι] {b : ι → M} (h : LinearIndependent R b) : + Fintype.card ι ≤ finrank R M := by + simpa using h.cardinal_mk_le_finrank +#align finite_dimensional.fintype_card_le_finrank_of_linear_independent LinearIndependent.fintype_card_le_finrank + +theorem finset_card_le_finrank [Module.Finite R M] + {b : Finset M} (h : LinearIndependent R (fun x => x : b → M)) : + b.card ≤ finrank R M := by + rw [← Fintype.card_coe] + exact h.fintype_card_le_finrank +#align finite_dimensional.finset_card_le_finrank_of_linear_independent LinearIndependent.finset_card_le_finrank + +theorem lt_aleph0_of_finite {ι : Type w} + [Module.Finite R M] {v : ι → M} (h : LinearIndependent R v) : #ι < ℵ₀ := by + apply Cardinal.lift_lt.1 + apply lt_of_le_of_lt + apply h.cardinal_lift_le_rank + rw [← finrank_eq_rank, Cardinal.lift_aleph0, Cardinal.lift_natCast] + apply Cardinal.nat_lt_aleph0 + +theorem finite [Module.Finite R M] {ι : Type*} {f : ι → M} + (h : LinearIndependent R f) : Finite ι := + Cardinal.lt_aleph0_iff_finite.1 <| h.lt_aleph0_of_finite + +theorem setFinite [Module.Finite R M] {b : Set M} + (h : LinearIndependent R fun x : b => (x : M)) : b.Finite := + Cardinal.lt_aleph0_iff_set_finite.mp h.lt_aleph0_of_finite +#align linear_independent.finite LinearIndependent.setFinite + +end LinearIndependent + +@[deprecated] +alias cardinal_mk_le_finrank_of_linearIndependent := LinearIndependent.cardinal_mk_le_finrank +@[deprecated] +alias fintype_card_le_finrank_of_linearIndependent := LinearIndependent.fintype_card_le_finrank +@[deprecated] +alias finset_card_le_finrank_of_linearIndependent := LinearIndependent.finset_card_le_finrank +@[deprecated] +alias Module.Finite.lt_aleph0_of_linearIndependent := LinearIndependent.lt_aleph0_of_finite + +variable [Module.Finite R M] + +theorem Module.Finite.not_linearIndependent_of_infinite {ι : Type*} [Infinite ι] + (v : ι → M) : ¬LinearIndependent R v := mt LinearIndependent.finite <| @not_finite _ _ +#align finite_dimensional.not_linear_independent_of_infinite Module.Finite.not_linearIndependent_of_infinite + +variable [NoZeroSMulDivisors R M] + +theorem CompleteLattice.Independent.subtype_ne_bot_le_rank [Nontrivial R] + {V : ι → Submodule R M} (hV : CompleteLattice.Independent V) : + Cardinal.lift.{v} #{ i : ι // V i ≠ ⊥ } ≤ Cardinal.lift.{w} (Module.rank R M) := by + set I := { i : ι // V i ≠ ⊥ } + have hI : ∀ i : I, ∃ v ∈ V i, v ≠ (0 : M) := by + intro i + rw [← Submodule.ne_bot_iff] + exact i.prop + choose v hvV hv using hI + have : LinearIndependent R v := (hV.comp Subtype.coe_injective).linearIndependent _ hvV hv + exact this.cardinal_lift_le_rank +#align complete_lattice.independent.subtype_ne_bot_le_rank CompleteLattice.Independent.subtype_ne_bot_le_rank + +theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux + {p : ι → Submodule R M} (hp : CompleteLattice.Independent p) : + #{ i // p i ≠ ⊥ } ≤ (finrank R M : Cardinal.{w}) := by + suffices Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{v} (finrank R M : Cardinal.{w}) by + rwa [Cardinal.lift_le] at this + calc + Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{w} (Module.rank R M) := + hp.subtype_ne_bot_le_rank + _ = Cardinal.lift.{w} (finrank R M : Cardinal.{v}) := by rw [finrank_eq_rank] + _ = Cardinal.lift.{v} (finrank R M : Cardinal.{w}) := by simp +#align complete_lattice.independent.subtype_ne_bot_le_finrank_aux CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux + +/-- If `p` is an independent family of submodules of a `R`-finite module `M`, then the +number of nontrivial subspaces in the family `p` is finite. -/ +noncomputable def CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional + {p : ι → Submodule R M} (hp : CompleteLattice.Independent p) : + Fintype { i : ι // p i ≠ ⊥ } := by + suffices #{ i // p i ≠ ⊥ } < (ℵ₀ : Cardinal.{w}) by + rw [Cardinal.lt_aleph0_iff_fintype] at this + exact this.some + refine' lt_of_le_of_lt hp.subtype_ne_bot_le_finrank_aux _ + simp [Cardinal.nat_lt_aleph0] +#align complete_lattice.independent.fintype_ne_bot_of_finite_dimensional CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional + +/-- If `p` is an independent family of submodules of a `R`-finite module `M`, then the +number of nontrivial subspaces in the family `p` is bounded above by the dimension of `M`. + +Note that the `Fintype` hypothesis required here can be provided by +`CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional`. -/ +theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank + {p : ι → Submodule R M} (hp : CompleteLattice.Independent p) [Fintype { i // p i ≠ ⊥ }] : + Fintype.card { i // p i ≠ ⊥ } ≤ finrank R M := by simpa using hp.subtype_ne_bot_le_finrank_aux +#align complete_lattice.independent.subtype_ne_bot_le_finrank CompleteLattice.Independent.subtype_ne_bot_le_finrank + +section + +open BigOperators + +open Finset + +/-- If a finset has cardinality larger than the rank of a module, +then there is a nontrivial linear relation amongst its elements. -/ +theorem Module.exists_nontrivial_relation_of_finrank_lt_card {t : Finset M} + (h : finrank R M < t.card) : ∃ f : M → R, ∑ e in t, f e • e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by + obtain ⟨g, sum, z, nonzero⟩ := Fintype.not_linearIndependent_iff.mp + (mt LinearIndependent.finset_card_le_finrank h.not_le) + refine ⟨Subtype.val.extend g 0, ?_, z, z.2, by rwa [Subtype.val_injective.extend_apply]⟩ + rw [← Finset.sum_finset_coe]; convert sum; apply Subtype.val_injective.extend_apply +#align finite_dimensional.exists_nontrivial_relation_of_rank_lt_card Module.exists_nontrivial_relation_of_finrank_lt_card + +/-- If a finset has cardinality larger than `finrank + 1`, +then there is a nontrivial linear relation amongst its elements, +such that the coefficients of the relation sum to zero. -/ +theorem Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card + {t : Finset M} (h : finrank R M + 1 < t.card) : + ∃ f : M → R, ∑ e in t, f e • e = 0 ∧ ∑ e in t, f e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by + -- Pick an element x₀ ∈ t, + obtain ⟨x₀, x₀_mem⟩ := card_pos.1 ((Nat.succ_pos _).trans h) + -- and apply the previous lemma to the {xᵢ - x₀} + let shift : M ↪ M := ⟨(· - x₀), sub_left_injective⟩ + classical + let t' := (t.erase x₀).map shift + have h' : finrank R M < t'.card := by + rw [card_map, card_erase_of_mem x₀_mem] + exact Nat.lt_pred_iff.mpr h + -- to obtain a function `g`. + obtain ⟨g, gsum, x₁, x₁_mem, nz⟩ := exists_nontrivial_relation_of_finrank_lt_card h' + -- Then obtain `f` by translating back by `x₀`, + -- and setting the value of `f` at `x₀` to ensure `∑ e in t, f e = 0`. + let f : M → R := fun z ↦ if z = x₀ then -∑ z in t.erase x₀, g (z - x₀) else g (z - x₀) + refine ⟨f, ?_, ?_, ?_⟩ + -- After this, it's a matter of verifying the properties, + -- based on the corresponding properties for `g`. + · rw [sum_map, Embedding.coeFn_mk] at gsum + simp_rw [← t.sum_erase_add _ x₀_mem, if_pos, neg_smul, sum_smul, + ← sub_eq_add_neg, ← sum_sub_distrib, ← gsum, smul_sub] + refine sum_congr rfl fun x x_mem ↦ ?_ + rw [if_neg (mem_erase.mp x_mem).1] + · simp_rw [← t.sum_erase_add _ x₀_mem, if_pos, add_neg_eq_zero] + exact sum_congr rfl fun x x_mem ↦ if_neg (mem_erase.mp x_mem).1 + · obtain ⟨x₁, x₁_mem', rfl⟩ := Finset.mem_map.mp x₁_mem + have := mem_erase.mp x₁_mem' + exact ⟨x₁, by simpa only [Embedding.coeFn_mk, sub_add_cancel, this.2, true_and, if_neg this.1]⟩ +#align finite_dimensional.exists_nontrivial_relation_sum_zero_of_rank_succ_lt_card Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card + +end + +end Finite + +section FinrankZero + +variable [Nontrivial R] [NoZeroSMulDivisors R M] + +/-- A finite dimensional space is nontrivial if it has positive `finrank`. -/ +theorem FiniteDimensional.nontrivial_of_finrank_pos (h : 0 < finrank R M) : Nontrivial M := + rank_pos_iff_nontrivial.mp (lt_rank_of_lt_finrank h) +#align finite_dimensional.nontrivial_of_finrank_pos FiniteDimensional.nontrivial_of_finrank_pos + +/-- A finite dimensional space is nontrivial if it has `finrank` equal to the successor of a +natural number. -/ +theorem FiniteDimensional.nontrivial_of_finrank_eq_succ {n : ℕ} + (hn : finrank R M = n.succ) : Nontrivial M := + nontrivial_of_finrank_pos (by rw [hn]; exact n.succ_pos) +#align finite_dimensional.nontrivial_of_finrank_eq_succ FiniteDimensional.nontrivial_of_finrank_eq_succ + +/-- A (finite dimensional) space that is a subsingleton has zero `finrank`. -/ +@[nontriviality] +theorem FiniteDimensional.finrank_zero_of_subsingleton [Subsingleton M] : finrank R M = 0 := by + rw [finrank, rank_subsingleton', _root_.map_zero] +#align finite_dimensional.finrank_zero_of_subsingleton FiniteDimensional.finrank_zero_of_subsingleton + +lemma LinearIndependent.finrank_eq_zero_of_infinite {ι} [Nontrivial R] [Infinite ι] {v : ι → M} + (hv : LinearIndependent R v) : finrank R M = 0 := toNat_eq_zero.mpr <| .inr hv.aleph0_le_rank + +variable (R M) + +@[simp] +theorem finrank_bot : finrank R (⊥ : Submodule R M) = 0 := + finrank_eq_of_rank_eq (rank_bot _ _) +#align finrank_bot finrank_bot + +variable {R M} + +section StrongRankCondition + +variable [StrongRankCondition R] [Module.Finite R M] + +/-- A finite rank torsion-free module has positive `finrank` iff it has a nonzero element. -/ +theorem FiniteDimensional.finrank_pos_iff_exists_ne_zero [NoZeroSMulDivisors R M] : + 0 < finrank R M ↔ ∃ x : M, x ≠ 0 := + Iff.trans + (by + rw [← finrank_eq_rank] + norm_cast) + (@rank_pos_iff_exists_ne_zero R M _ _ _ _ _) +#align finite_dimensional.finrank_pos_iff_exists_ne_zero FiniteDimensional.finrank_pos_iff_exists_ne_zero + +/-- An `R`-finite torsion-free module has positive `finrank` iff it is nontrivial. -/ +theorem FiniteDimensional.finrank_pos_iff [NoZeroSMulDivisors R M] : + 0 < finrank R M ↔ Nontrivial M := + Iff.trans + (by rw [← finrank_eq_rank]; norm_cast) + (rank_pos_iff_nontrivial (R := R)) +#align finite_dimensional.finrank_pos_iff FiniteDimensional.finrank_pos_iff + +/-- A nontrivial finite dimensional space has positive `finrank`. -/ +theorem FiniteDimensional.finrank_pos [NoZeroSMulDivisors R M] [h : Nontrivial M] : + 0 < finrank R M := + finrank_pos_iff.mpr h +#align finite_dimensional.finrank_pos FiniteDimensional.finrank_pos + +/-- See `FiniteDimensional.finrank_zero_iff` + for the stronger version with `NoZeroSMulDivisors R M`. -/ +theorem FiniteDimensional.finrank_eq_zero_iff [Module.Finite R M] : + finrank R M = 0 ↔ ∀ x : M, ∃ a : R, a ≠ 0 ∧ a • x = 0 := + Iff.trans + (by rw [← finrank_eq_rank]; norm_cast) + (rank_eq_zero_iff (R := R)) + +/-- The `StrongRankCondition` is automatic. See `commRing_strongRankCondition`. -/ +theorem FiniteDimensional.finrank_eq_zero_iff_isTorsion {R} [CommRing R] [StrongRankCondition R] + [IsDomain R] [Module R M] [Module.Finite R M] : + finrank R M = 0 ↔ Module.IsTorsion R M := + Iff.trans + (by rw [← finrank_eq_rank]; norm_cast) + (rank_eq_zero_iff_isTorsion (R := R)) + +/-- A finite dimensional space has zero `finrank` iff it is a subsingleton. +This is the `finrank` version of `rank_zero_iff`. -/ +theorem FiniteDimensional.finrank_zero_iff [NoZeroSMulDivisors R M] : + finrank R M = 0 ↔ Subsingleton M := + Iff.trans + (by rw [← finrank_eq_rank]; norm_cast) + (rank_zero_iff (R := R)) +#align finite_dimensional.finrank_zero_iff FiniteDimensional.finrank_zero_iff + +end StrongRankCondition + +theorem FiniteDimensional.finrank_eq_zero_of_rank_eq_zero (h : Module.rank R M = 0) : + finrank R M = 0 := by + delta finrank + rw [h, zero_toNat] +#align finrank_eq_zero_of_rank_eq_zero FiniteDimensional.finrank_eq_zero_of_rank_eq_zero + +theorem Submodule.bot_eq_top_of_rank_eq_zero [NoZeroSMulDivisors R M] (h : Module.rank R M = 0) : + (⊥ : Submodule R M) = ⊤ := by + nontriviality R + rw [rank_zero_iff] at h + exact Subsingleton.elim _ _ +#align bot_eq_top_of_rank_eq_zero Submodule.bot_eq_top_of_rank_eq_zero + +/-- See `rank_subsingleton` for the reason that `Nontrivial R` is needed. -/ +@[simp] +theorem Submodule.rank_eq_zero [Nontrivial R] [NoZeroSMulDivisors R M] {S : Submodule R M} : + Module.rank R S = 0 ↔ S = ⊥ := + ⟨fun h => + (Submodule.eq_bot_iff _).2 fun x hx => + congr_arg Subtype.val <| + ((Submodule.eq_bot_iff _).1 <| Eq.symm <| Submodule.bot_eq_top_of_rank_eq_zero h) ⟨x, hx⟩ + Submodule.mem_top, + fun h => by rw [h, rank_bot]⟩ +#align rank_eq_zero Submodule.rank_eq_zero + +@[simp] +theorem Submodule.finrank_eq_zero [StrongRankCondition R] [NoZeroSMulDivisors R M] + {S : Submodule R M} [Module.Finite R S] : + finrank R S = 0 ↔ S = ⊥ := by + rw [← Submodule.rank_eq_zero, ← finrank_eq_rank, ← @Nat.cast_zero Cardinal, Cardinal.natCast_inj] +#align finrank_eq_zero Submodule.finrank_eq_zero + +variable [Module.Free R M] + +theorem finrank_eq_zero_of_basis_imp_not_finite + (h : ∀ s : Set M, Basis.{v} (s : Set M) R M → ¬s.Finite) : finrank R M = 0 := by + cases subsingleton_or_nontrivial R + · have := Module.subsingleton R M + exact (h ∅ ⟨LinearEquiv.ofSubsingleton _ _⟩ Set.finite_empty).elim + obtain ⟨_, ⟨b⟩⟩ := (Module.free_iff_set R M).mp ‹_› + have := Set.Infinite.to_subtype (h _ b) + exact b.linearIndependent.finrank_eq_zero_of_infinite +#align finrank_eq_zero_of_basis_imp_not_finite finrank_eq_zero_of_basis_imp_not_finite + +theorem finrank_eq_zero_of_basis_imp_false (h : ∀ s : Finset M, Basis.{v} (s : Set M) R M → False) : + finrank R M = 0 := + finrank_eq_zero_of_basis_imp_not_finite fun s b hs => + h hs.toFinset + (by + convert b + simp) +#align finrank_eq_zero_of_basis_imp_false finrank_eq_zero_of_basis_imp_false + +theorem finrank_eq_zero_of_not_exists_basis + (h : ¬∃ s : Finset M, Nonempty (Basis (s : Set M) R M)) : finrank R M = 0 := + finrank_eq_zero_of_basis_imp_false fun s b => h ⟨s, ⟨b⟩⟩ +#align finrank_eq_zero_of_not_exists_basis finrank_eq_zero_of_not_exists_basis + +theorem finrank_eq_zero_of_not_exists_basis_finite + (h : ¬∃ (s : Set M) (_ : Basis.{v} (s : Set M) R M), s.Finite) : finrank R M = 0 := + finrank_eq_zero_of_basis_imp_not_finite fun s b hs => h ⟨s, b, hs⟩ +#align finrank_eq_zero_of_not_exists_basis_finite finrank_eq_zero_of_not_exists_basis_finite + +theorem finrank_eq_zero_of_not_exists_basis_finset (h : ¬∃ s : Finset M, Nonempty (Basis s R M)) : + finrank R M = 0 := + finrank_eq_zero_of_basis_imp_false fun s b => h ⟨s, ⟨b⟩⟩ +#align finrank_eq_zero_of_not_exists_basis_finset finrank_eq_zero_of_not_exists_basis_finset + +end FinrankZero + +section RankOne + +variable [NoZeroSMulDivisors R M] [StrongRankCondition R] + +/-- If there is a nonzero vector and every other vector is a multiple of it, +then the module has dimension one. -/ +theorem rank_eq_one (v : M) (n : v ≠ 0) (h : ∀ w : M, ∃ c : R, c • v = w) : + Module.rank R M = 1 := by + haveI := nontrivial_of_invariantBasisNumber R + obtain ⟨b⟩ := (Basis.basis_singleton_iff.{u} PUnit).mpr ⟨v, n, h⟩ + rw [rank_eq_card_basis b, Fintype.card_punit, Nat.cast_one] + +/-- If there is a nonzero vector and every other vector is a multiple of it, +then the module has dimension one. -/ +theorem finrank_eq_one (v : M) (n : v ≠ 0) (h : ∀ w : M, ∃ c : R, c • v = w) : finrank R M = 1 := + finrank_eq_of_rank_eq (rank_eq_one v n h) +#align finrank_eq_one finrank_eq_one + +/-- If every vector is a multiple of some `v : M`, then `M` has dimension at most one. +-/ +theorem finrank_le_one (v : M) (h : ∀ w : M, ∃ c : R, c • v = w) : finrank R M ≤ 1 := by + haveI := nontrivial_of_invariantBasisNumber R + rcases eq_or_ne v 0 with (rfl | hn) + · haveI := + _root_.subsingleton_of_forall_eq (0 : M) fun w => by + obtain ⟨c, rfl⟩ := h w + simp + rw [finrank_zero_of_subsingleton] + exact zero_le_one + · exact (finrank_eq_one v hn h).le +#align finrank_le_one finrank_le_one + +end RankOne diff --git a/Mathlib/LinearAlgebra/Dimension/Finrank.lean b/Mathlib/LinearAlgebra/Dimension/Finrank.lean new file mode 100644 index 0000000000000..70d1fdbe4cd64 --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/Finrank.lean @@ -0,0 +1,144 @@ +/- +Copyright (c) 2019 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Anne Baanen +-/ +import Mathlib.LinearAlgebra.Dimension.Basic + +#align_import linear_algebra.finrank from "leanprover-community/mathlib"@"347636a7a80595d55bedf6e6fbd996a3c39da69a" + +/-! +# Finite dimension of vector spaces + +Definition of the rank of a module, or dimension of a vector space, as a natural number. + +## Main definitions + +Defined is `FiniteDimensional.finrank`, the dimension of a finite dimensional space, returning a +`Nat`, as opposed to `Module.rank`, which returns a `Cardinal`. When the space has infinite +dimension, its `finrank` is by convention set to `0`. + +The definition of `finrank` does not assume a `FiniteDimensional` instance, but lemmas might. +Import `LinearAlgebra.FiniteDimensional` to get access to these additional lemmas. + +Formulas for the dimension are given for linear equivs, in `LinearEquiv.finrank_eq`. + +## Implementation notes + +Most results are deduced from the corresponding results for the general dimension (as a cardinal), +in `Dimension.lean`. Not all results have been ported yet. + +You should not assume that there has been any effort to state lemmas as generally as possible. +-/ + + +universe u v w + +open Cardinal Submodule Module Function + +variable {R : Type u} {M : Type v} {N : Type w} + +variable [Ring R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] + +namespace FiniteDimensional + +section Ring + +/-- The rank of a module as a natural number. + +Defined by convention to be `0` if the space has infinite rank. + +For a vector space `M` over a field `R`, this is the same as the finite dimension +of `M` over `R`. +-/ +noncomputable def finrank (R M : Type*) [Semiring R] [AddCommGroup M] [Module R M] : ℕ := + Cardinal.toNat (Module.rank R M) +#align finite_dimensional.finrank FiniteDimensional.finrank + +theorem finrank_eq_of_rank_eq {n : ℕ} (h : Module.rank R M = ↑n) : finrank R M = n := by + apply_fun toNat at h + rw [toNat_cast] at h + exact mod_cast h +#align finite_dimensional.finrank_eq_of_rank_eq FiniteDimensional.finrank_eq_of_rank_eq + +lemma rank_eq_one_iff_finrank_eq_one : Module.rank R M = 1 ↔ finrank R M = 1 := + Cardinal.toNat_eq_one.symm + +/-- This is like `rank_eq_one_iff_finrank_eq_one` but works for `2`, `3`, `4`, ... -/ +lemma rank_eq_ofNat_iff_finrank_eq_ofNat (n : ℕ) [Nat.AtLeastTwo n] : + Module.rank R M = OfNat.ofNat n ↔ finrank R M = OfNat.ofNat n := + Cardinal.toNat_eq_ofNat.symm + +theorem finrank_le_of_rank_le {n : ℕ} (h : Module.rank R M ≤ ↑n) : finrank R M ≤ n := by + rwa [← Cardinal.toNat_le_iff_le_of_lt_aleph0, toNat_cast] at h + · exact h.trans_lt (nat_lt_aleph0 n) + · exact nat_lt_aleph0 n +#align finite_dimensional.finrank_le_of_rank_le FiniteDimensional.finrank_le_of_rank_le + +theorem finrank_lt_of_rank_lt {n : ℕ} (h : Module.rank R M < ↑n) : finrank R M < n := by + rwa [← Cardinal.toNat_lt_iff_lt_of_lt_aleph0, toNat_cast] at h + · exact h.trans (nat_lt_aleph0 n) + · exact nat_lt_aleph0 n +#align finite_dimensional.finrank_lt_of_rank_lt FiniteDimensional.finrank_lt_of_rank_lt + +theorem lt_rank_of_lt_finrank {n : ℕ} (h : n < finrank R M) : ↑n < Module.rank R M := by + rwa [← Cardinal.toNat_lt_iff_lt_of_lt_aleph0, toNat_cast] + · exact nat_lt_aleph0 n + · contrapose! h + rw [finrank, Cardinal.toNat_apply_of_aleph0_le h] + exact n.zero_le +#align finite_dimensional.rank_lt_of_finrank_lt FiniteDimensional.lt_rank_of_lt_finrank + +theorem one_lt_rank_of_one_lt_finrank (h : 1 < finrank R M) : 1 < Module.rank R M := by + simpa using lt_rank_of_lt_finrank h + +theorem finrank_le_finrank_of_rank_le_rank + (h : lift.{w} (Module.rank R M) ≤ Cardinal.lift.{v} (Module.rank R N)) + (h' : Module.rank R N < ℵ₀) : finrank R M ≤ finrank R N := by + simpa only [toNat_lift] using toNat_le_of_le_of_lt_aleph0 (lift_lt_aleph0.mpr h') h +#align finite_dimensional.finrank_le_finrank_of_rank_le_rank FiniteDimensional.finrank_le_finrank_of_rank_le_rank + +end Ring + +end FiniteDimensional + +open FiniteDimensional + +namespace LinearEquiv + +variable {R M M₂ : Type*} [Ring R] [AddCommGroup M] [AddCommGroup M₂] + +variable [Module R M] [Module R M₂] + +/-- The dimension of a finite dimensional space is preserved under linear equivalence. -/ +theorem finrank_eq (f : M ≃ₗ[R] M₂) : finrank R M = finrank R M₂ := by + unfold finrank + rw [← Cardinal.toNat_lift, f.lift_rank_eq, Cardinal.toNat_lift] +#align linear_equiv.finrank_eq LinearEquiv.finrank_eq + +/-- Pushforwards of finite-dimensional submodules along a `LinearEquiv` have the same finrank. -/ +theorem finrank_map_eq (f : M ≃ₗ[R] M₂) (p : Submodule R M) : + finrank R (p.map (f : M →ₗ[R] M₂)) = finrank R p := + (f.submoduleMap p).finrank_eq.symm +#align linear_equiv.finrank_map_eq LinearEquiv.finrank_map_eq + +end LinearEquiv + +/-- The dimensions of the domain and range of an injective linear map are equal. -/ +theorem LinearMap.finrank_range_of_inj {f : M →ₗ[R] N} (hf : Function.Injective f) : + finrank R (LinearMap.range f) = finrank R M := by rw [(LinearEquiv.ofInjective f hf).finrank_eq] +#align linear_map.finrank_range_of_inj LinearMap.finrank_range_of_inj + +@[simp] +theorem Submodule.finrank_map_subtype_eq (p : Submodule R M) (q : Submodule R p) : + finrank R (q.map p.subtype) = finrank R q := + (Submodule.equivSubtypeMap p q).symm.finrank_eq +#align finite_dimensional.submodule.finrank_map_subtype_eq Submodule.finrank_map_subtype_eq + +variable (R M) + +@[simp] +theorem finrank_top : finrank R (⊤ : Submodule R M) = finrank R M := by + unfold finrank + simp [rank_top] +#align finrank_top finrank_top diff --git a/Mathlib/LinearAlgebra/Dimension/Free.lean b/Mathlib/LinearAlgebra/Dimension/Free.lean new file mode 100644 index 0000000000000..661215d32a310 --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/Free.lean @@ -0,0 +1,206 @@ +/- +Copyright (c) 2021 Riccardo Brasca. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Riccardo Brasca +-/ +import Mathlib.LinearAlgebra.Dimension.StrongRankCondition +import Mathlib.LinearAlgebra.FreeModule.Basic +import Mathlib.LinearAlgebra.FreeModule.Finite.Basic + +#align_import linear_algebra.dimension from "leanprover-community/mathlib"@"47a5f8186becdbc826190ced4312f8199f9db6a5" + +/-! +# Rank of free modules + +## Main result +- `LinearEquiv.nonempty_equiv_iff_lift_rank_eq`: + Two free modules are isomorphic iff they have the same dimension. +- `FiniteDimensional.finBasis`: + An arbitrary basis of a finite free module indexed by `Fin n` given `finrank R M = n`. + +-/ + + +noncomputable section + +universe u v v' + +variable {R : Type u} {M M₁ : Type v} {M' : Type v'} + +open BigOperators Cardinal Basis Submodule Function Set DirectSum FiniteDimensional + +variable [Ring R] [StrongRankCondition R] + +variable [AddCommGroup M] [Module R M] [Module.Free R M] + +variable [AddCommGroup M'] [Module R M'] [Module.Free R M'] + +variable [AddCommGroup M₁] [Module R M₁] [Module.Free R M₁] + +namespace Module.Free + +variable (R M) + +/-- The rank of a free module `M` over `R` is the cardinality of `ChooseBasisIndex R M`. -/ +theorem rank_eq_card_chooseBasisIndex : Module.rank R M = #(ChooseBasisIndex R M) := + (chooseBasis R M).mk_eq_rank''.symm +#align module.free.rank_eq_card_choose_basis_index Module.Free.rank_eq_card_chooseBasisIndex + +/-- The finrank of a free module `M` over `R` is the cardinality of `ChooseBasisIndex R M`. -/ +theorem _root_.FiniteDimensional.finrank_eq_card_chooseBasisIndex [Module.Finite R M] : + finrank R M = Fintype.card (ChooseBasisIndex R M) := by + simp [finrank, rank_eq_card_chooseBasisIndex] +#align finite_dimensional.finrank_eq_card_choose_basis_index FiniteDimensional.finrank_eq_card_chooseBasisIndex + +/-- The rank of a free module `M` over an infinite scalar ring `R` is the cardinality of `M` +whenever `#R < #M`. -/ +lemma rank_eq_mk_of_infinite_lt [Infinite R] (h_lt : lift.{v} #R < lift.{u} #M) : + Module.rank R M = #M := by + have : Infinite M := infinite_iff.mpr <| lift_le.mp <| le_trans (by simp) h_lt.le + have h : lift #M = lift #(ChooseBasisIndex R M →₀ R) := lift_mk_eq'.mpr ⟨(chooseBasis R M).repr⟩ + simp only [mk_finsupp_lift_of_infinite', lift_id', ← rank_eq_card_chooseBasisIndex, lift_max, + lift_lift] at h + refine lift_inj.mp ((max_eq_iff.mp h.symm).resolve_right <| not_and_of_not_left _ ?_).left + exact (lift_umax.{v, u}.symm ▸ h_lt).ne + +end Module.Free + +open Module.Free + +open Cardinal + +/-- Two vector spaces are isomorphic if they have the same dimension. -/ +theorem nonempty_linearEquiv_of_lift_rank_eq + (cnd : Cardinal.lift.{v'} (Module.rank R M) = Cardinal.lift.{v} (Module.rank R M')) : + Nonempty (M ≃ₗ[R] M') := by + obtain ⟨⟨_, B⟩⟩ := Module.Free.exists_basis (R := R) (M := M) + obtain ⟨⟨_, B'⟩⟩ := Module.Free.exists_basis (R := R) (M := M') + have : Cardinal.lift.{v', v} #_ = Cardinal.lift.{v, v'} #_ := by + rw [B.mk_eq_rank'', cnd, B'.mk_eq_rank''] + exact (Cardinal.lift_mk_eq.{v, v', 0}.1 this).map (B.equiv B') +#align nonempty_linear_equiv_of_lift_rank_eq nonempty_linearEquiv_of_lift_rank_eq + +/-- Two vector spaces are isomorphic if they have the same dimension. -/ +theorem nonempty_linearEquiv_of_rank_eq (cond : Module.rank R M = Module.rank R M₁) : + Nonempty (M ≃ₗ[R] M₁) := + nonempty_linearEquiv_of_lift_rank_eq <| congr_arg _ cond +#align nonempty_linear_equiv_of_rank_eq nonempty_linearEquiv_of_rank_eq + +section + +variable (M M' M₁) + +/-- Two vector spaces are isomorphic if they have the same dimension. -/ +def LinearEquiv.ofLiftRankEq + (cond : Cardinal.lift.{v'} (Module.rank R M) = Cardinal.lift.{v} (Module.rank R M')) : + M ≃ₗ[R] M' := + Classical.choice (nonempty_linearEquiv_of_lift_rank_eq cond) +#align linear_equiv.of_lift_rank_eq LinearEquiv.ofLiftRankEq + +/-- Two vector spaces are isomorphic if they have the same dimension. -/ +def LinearEquiv.ofRankEq (cond : Module.rank R M = Module.rank R M₁) : M ≃ₗ[R] M₁ := + Classical.choice (nonempty_linearEquiv_of_rank_eq cond) +#align linear_equiv.of_rank_eq LinearEquiv.ofRankEq + +end + +/-- Two vector spaces are isomorphic if and only if they have the same dimension. -/ +theorem LinearEquiv.nonempty_equiv_iff_lift_rank_eq : Nonempty (M ≃ₗ[R] M') ↔ + Cardinal.lift.{v'} (Module.rank R M) = Cardinal.lift.{v} (Module.rank R M') := + ⟨fun ⟨h⟩ => LinearEquiv.lift_rank_eq h, fun h => nonempty_linearEquiv_of_lift_rank_eq h⟩ +#align linear_equiv.nonempty_equiv_iff_lift_rank_eq LinearEquiv.nonempty_equiv_iff_lift_rank_eq + +/-- Two vector spaces are isomorphic if and only if they have the same dimension. -/ +theorem LinearEquiv.nonempty_equiv_iff_rank_eq : + Nonempty (M ≃ₗ[R] M₁) ↔ Module.rank R M = Module.rank R M₁ := + ⟨fun ⟨h⟩ => LinearEquiv.rank_eq h, fun h => nonempty_linearEquiv_of_rank_eq h⟩ +#align linear_equiv.nonempty_equiv_iff_rank_eq LinearEquiv.nonempty_equiv_iff_rank_eq + +/-- Two finite and free modules are isomorphic if they have the same (finite) rank. -/ +theorem FiniteDimensional.nonempty_linearEquiv_of_finrank_eq + [Module.Finite R M] [Module.Finite R M'] (cond : finrank R M = finrank R M') : + Nonempty (M ≃ₗ[R] M') := + nonempty_linearEquiv_of_lift_rank_eq <| by simp only [← finrank_eq_rank, cond, lift_natCast] +#align finite_dimensional.nonempty_linear_equiv_of_finrank_eq FiniteDimensional.nonempty_linearEquiv_of_finrank_eq + +/-- Two finite and free modules are isomorphic if and only if they have the same (finite) rank. -/ +theorem FiniteDimensional.nonempty_linearEquiv_iff_finrank_eq [Module.Finite R M] + [Module.Finite R M'] : Nonempty (M ≃ₗ[R] M') ↔ finrank R M = finrank R M' := + ⟨fun ⟨h⟩ => h.finrank_eq, fun h => nonempty_linearEquiv_of_finrank_eq h⟩ +#align finite_dimensional.nonempty_linear_equiv_iff_finrank_eq FiniteDimensional.nonempty_linearEquiv_iff_finrank_eq + +variable (M M') + +/-- Two finite and free modules are isomorphic if they have the same (finite) rank. -/ +noncomputable def LinearEquiv.ofFinrankEq [Module.Finite R M] [Module.Finite R M'] + (cond : finrank R M = finrank R M') : M ≃ₗ[R] M' := + Classical.choice <| FiniteDimensional.nonempty_linearEquiv_of_finrank_eq cond +#align linear_equiv.of_finrank_eq LinearEquiv.ofFinrankEq + +variable {M M'} + +/-- See `rank_lt_aleph0` for the inverse direction without `Module.Free R M`. -/ +lemma Module.rank_lt_alpeh0_iff : + Module.rank R M < ℵ₀ ↔ Module.Finite R M := by + rw [Free.rank_eq_card_chooseBasisIndex, mk_lt_aleph0_iff] + exact ⟨fun h ↦ Finite.of_basis (Free.chooseBasis R M), + fun I ↦ Finite.of_fintype (Free.ChooseBasisIndex R M)⟩ + +theorem FiniteDimensional.finrank_of_not_finite + (h : ¬Module.Finite R M) : + finrank R M = 0 := + dif_neg (Module.rank_lt_alpeh0_iff.not.mpr h) + +theorem Module.finite_of_finrank_pos (h : 0 < finrank R M) : + Module.Finite R M := by + contrapose h + simp [finrank_of_not_finite h] + +theorem Module.finite_of_finrank_eq_succ {n : ℕ} + (hn : finrank R M = n.succ) : Module.Finite R M := + Module.finite_of_finrank_pos <| by rw [hn]; exact n.succ_pos + +theorem Module.finite_iff_of_rank_eq_nsmul {W} [AddCommGroup W] + [Module R W] [Module.Free R W] {n : ℕ} (hn : n ≠ 0) + (hVW : Module.rank R M = n • Module.rank R W) : + Module.Finite R M ↔ Module.Finite R W := by + simp only [← rank_lt_alpeh0_iff, hVW, nsmul_lt_aleph0_iff_of_ne_zero hn] + +namespace FiniteDimensional +variable (R M) + +/-- A finite rank free module has a basis indexed by `Fin (finrank R M)`. -/ +noncomputable def finBasis [Module.Finite R M] : + Basis (Fin (finrank R M)) R M := + (Module.Free.chooseBasis R M).reindex (Fintype.equivFinOfCardEq + (finrank_eq_card_chooseBasisIndex R M).symm) +#align finite_dimensional.fin_basis FiniteDimensional.finBasis + +/-- A rank `n` free module has a basis indexed by `Fin n`. -/ +noncomputable def finBasisOfFinrankEq [Module.Finite R M] + {n : ℕ} (hn : finrank R M = n) : + Basis (Fin n) R M := + (finBasis R M).reindex (Fin.castIso hn).toEquiv +#align finite_dimensional.fin_basis_of_finrank_eq FiniteDimensional.finBasisOfFinrankEq + +variable {R M} + +/-- A free module with rank 1 has a basis with one element. -/ +noncomputable def basisUnique (ι : Type*) [Unique ι] + (h : finrank R M = 1) : + Basis ι R M := + haveI : Module.Finite R M := + Module.finite_of_finrank_pos (_root_.zero_lt_one.trans_le h.symm.le) + (finBasisOfFinrankEq R M h).reindex (Equiv.equivOfUnique _ _) +#align finite_dimensional.basis_unique FiniteDimensional.basisUnique + +@[simp] +theorem basisUnique_repr_eq_zero_iff {ι : Type*} [Unique ι] + {h : finrank R M = 1} {v : M} {i : ι} : + (basisUnique ι h).repr v i = 0 ↔ v = 0 := + ⟨fun hv => + (basisUnique ι h).repr.map_eq_zero_iff.mp (Finsupp.ext fun j => Subsingleton.elim i j ▸ hv), + fun hv => by rw [hv, LinearEquiv.map_zero, Finsupp.zero_apply]⟩ +#align finite_dimensional.basis_unique.repr_eq_zero_iff FiniteDimensional.basisUnique_repr_eq_zero_iff + +end FiniteDimensional diff --git a/Mathlib/LinearAlgebra/Dimension/LinearMap.lean b/Mathlib/LinearAlgebra/Dimension/LinearMap.lean new file mode 100644 index 0000000000000..4f2cabdfd8294 --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/LinearMap.lean @@ -0,0 +1,143 @@ +/- +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 +-/ +import Mathlib.LinearAlgebra.Dimension.DivisionRing + +/-! +# The rank of a linear map + +## Main Definition +- `LinearMap.rank`: The rank of a linear map. +-/ + + +noncomputable section + +universe u v v' v'' + +variable {K : Type u} {V V₁ : Type v} {V' V'₁ : Type v'} {V'' : Type v''} + +open BigOperators Cardinal Basis Submodule Function Set + +namespace LinearMap + +section Ring + +variable [Ring K] [AddCommGroup V] [Module K V] [AddCommGroup V₁] [Module K V₁] + +variable [AddCommGroup V'] [Module K V'] + +/-- `rank f` is the rank of a `LinearMap` `f`, defined as the dimension of `f.range`. -/ +abbrev rank (f : V →ₗ[K] V') : Cardinal := + Module.rank K (LinearMap.range f) +#align linear_map.rank LinearMap.rank + +theorem rank_le_range (f : V →ₗ[K] V') : rank f ≤ Module.rank K V' := + rank_submodule_le _ +#align linear_map.rank_le_range LinearMap.rank_le_range + +theorem rank_le_domain (f : V →ₗ[K] V₁) : rank f ≤ Module.rank K V := + rank_range_le _ +#align linear_map.rank_le_domain LinearMap.rank_le_domain + +@[simp] +theorem rank_zero [Nontrivial K] : rank (0 : V →ₗ[K] V') = 0 := by + rw [rank, LinearMap.range_zero, rank_bot] +#align linear_map.rank_zero LinearMap.rank_zero + +variable [AddCommGroup V''] [Module K V''] + +theorem rank_comp_le_left (g : V →ₗ[K] V') (f : V' →ₗ[K] V'') : rank (f.comp g) ≤ rank f := by + refine' rank_le_of_submodule _ _ _ + rw [LinearMap.range_comp] + exact LinearMap.map_le_range +#align linear_map.rank_comp_le_left LinearMap.rank_comp_le_left + +theorem lift_rank_comp_le_right (g : V →ₗ[K] V') (f : V' →ₗ[K] V'') : + Cardinal.lift.{v'} (rank (f.comp g)) ≤ Cardinal.lift.{v''} (rank g) := by + rw [rank, rank, LinearMap.range_comp]; exact lift_rank_map_le _ _ +#align linear_map.lift_rank_comp_le_right LinearMap.lift_rank_comp_le_right + +/-- The rank of the composition of two maps is less than the minimum of their ranks. -/ +theorem lift_rank_comp_le (g : V →ₗ[K] V') (f : V' →ₗ[K] V'') : + Cardinal.lift.{v'} (rank (f.comp g)) ≤ + min (Cardinal.lift.{v'} (rank f)) (Cardinal.lift.{v''} (rank g)) := + le_min (Cardinal.lift_le.mpr <| rank_comp_le_left _ _) (lift_rank_comp_le_right _ _) +#align linear_map.lift_rank_comp_le LinearMap.lift_rank_comp_le + +variable [AddCommGroup V'₁] [Module K V'₁] + +theorem rank_comp_le_right (g : V →ₗ[K] V') (f : V' →ₗ[K] V'₁) : rank (f.comp g) ≤ rank g := by + simpa only [Cardinal.lift_id] using lift_rank_comp_le_right g f +#align linear_map.rank_comp_le_right LinearMap.rank_comp_le_right + +/-- The rank of the composition of two maps is less than the minimum of their ranks. + +See `lift_rank_comp_le` for the universe-polymorphic version. -/ +theorem rank_comp_le (g : V →ₗ[K] V') (f : V' →ₗ[K] V'₁) : + rank (f.comp g) ≤ min (rank f) (rank g) := by + simpa only [Cardinal.lift_id] using lift_rank_comp_le g f +#align linear_map.rank_comp_le LinearMap.rank_comp_le + +end Ring + +section DivisionRing + +variable [DivisionRing K] [AddCommGroup V] [Module K V] [AddCommGroup V₁] [Module K V₁] + +variable [AddCommGroup V'] [Module K V'] + +theorem rank_add_le (f g : V →ₗ[K] V') : rank (f + g) ≤ rank f + rank g := + calc + rank (f + g) ≤ Module.rank K (LinearMap.range f ⊔ LinearMap.range g : Submodule K V') := by + refine' rank_le_of_submodule _ _ _ + exact LinearMap.range_le_iff_comap.2 <| eq_top_iff'.2 fun x => + show f x + g x ∈ (LinearMap.range f ⊔ LinearMap.range g : Submodule K V') from + mem_sup.2 ⟨_, ⟨x, rfl⟩, _, ⟨x, rfl⟩, rfl⟩ + _ ≤ rank f + rank g := Submodule.rank_add_le_rank_add_rank _ _ +#align linear_map.rank_add_le LinearMap.rank_add_le + +theorem 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 _ _ _ _ _ (fun a b => rank a ≤ b) f (fun d => rank (f d)) s + (le_of_eq rank_zero) fun _ _ _ h => le_trans (rank_add_le _ _) (add_le_add_left h _) +#align linear_map.rank_finset_sum_le LinearMap.rank_finset_sum_le + +theorem le_rank_iff_exists_linearIndependent {c : Cardinal} {f : V →ₗ[K] V'} : + c ≤ rank f ↔ ∃ s : Set V, + Cardinal.lift.{v'} #s = Cardinal.lift.{v} c ∧ LinearIndependent K (fun x : s => f x) := by + rcases f.rangeRestrict.exists_rightInverse_of_surjective f.range_rangeRestrict with ⟨g, hg⟩ + have fg : LeftInverse f.rangeRestrict g := LinearMap.congr_fun hg + refine' ⟨fun h => _, _⟩ + · rcases _root_.le_rank_iff_exists_linearIndependent.1 h with ⟨s, rfl, si⟩ + refine' ⟨g '' s, Cardinal.mk_image_eq_lift _ _ fg.injective, _⟩ + replace fg : ∀ x, f (g x) = x + · intro x + convert congr_arg Subtype.val (fg x) + replace si : LinearIndependent K fun x : s => f (g x) + · simpa only [fg] using si.map' _ (ker_subtype _) + exact si.image_of_comp s g f + · rintro ⟨s, hsc, si⟩ + have : LinearIndependent K fun x : s => f.rangeRestrict x := + LinearIndependent.of_comp f.range.subtype (by convert si) + convert this.image.cardinal_le_rank + rw [← Cardinal.lift_inj, ← hsc, Cardinal.mk_image_eq_of_injOn_lift] + exact injOn_iff_injective.2 this.injective +#align linear_map.le_rank_iff_exists_linear_independent LinearMap.le_rank_iff_exists_linearIndependent + +theorem le_rank_iff_exists_linearIndependent_finset {n : ℕ} {f : V →ₗ[K] V'} : + ↑n ≤ rank f ↔ ∃ s : Finset V, s.card = n ∧ LinearIndependent K fun x : (s : Set V) => f x := by + simp only [le_rank_iff_exists_linearIndependent, Cardinal.lift_natCast, Cardinal.lift_eq_nat_iff, + Cardinal.mk_set_eq_nat_iff_finset] + constructor + · rintro ⟨s, ⟨t, rfl, rfl⟩, si⟩ + exact ⟨t, rfl, si⟩ + · rintro ⟨s, rfl, si⟩ + exact ⟨s, ⟨s, rfl, rfl⟩, si⟩ +#align linear_map.le_rank_iff_exists_linear_independent_finset LinearMap.le_rank_iff_exists_linearIndependent_finset + +end DivisionRing + +end LinearMap diff --git a/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean b/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean new file mode 100644 index 0000000000000..e87b3499c6730 --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean @@ -0,0 +1,498 @@ +/- +Copyright (c) 2021 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison +-/ +import Mathlib.LinearAlgebra.Dimension.Finrank +import Mathlib.LinearAlgebra.InvariantBasisNumber + +#align_import linear_algebra.dimension from "leanprover-community/mathlib"@"47a5f8186becdbc826190ced4312f8199f9db6a5" + +/-! +# Lemmas about rank and finrank in rings satisfying strong rank condition. + +## Main statements + +For modules over rings satisfying the rank condition + +* `Basis.le_span`: + the cardinality of a basis is bounded by the cardinality of any spanning set + +For modules over rings satisfying the strong rank condition + +* `linearIndependent_le_span`: + For any linearly independent family `v : ι → M` + and any finite spanning set `w : Set M`, + the cardinality of `ι` is bounded by the cardinality of `w`. +* `linearIndependent_le_basis`: + If `b` is a basis for a module `M`, + and `s` is a linearly independent set, + then the cardinality of `s` is bounded by the cardinality of `b`. + +For modules over rings with invariant basis number +(including all commutative rings and all noetherian rings) + +* `mk_eq_mk_of_basis`: the dimension theorem, any two bases of the same vector space have the same + cardinality. + +-/ + + +noncomputable section + +universe u v w w' + +variable {R : Type u} {M : Type v} [Ring R] [AddCommGroup M] [Module R M] + +variable {ι : Type w} {ι' : Type w'} + +open BigOperators Cardinal Basis Submodule Function Set + +attribute [local instance] nontrivial_of_invariantBasisNumber + +section InvariantBasisNumber + +variable [InvariantBasisNumber R] + +/-- The dimension theorem: if `v` and `v'` are two bases, their index types +have the same cardinalities. -/ +theorem mk_eq_mk_of_basis (v : Basis ι R M) (v' : Basis ι' R M) : + Cardinal.lift.{w'} #ι = Cardinal.lift.{w} #ι' := by + classical + haveI := nontrivial_of_invariantBasisNumber R + cases fintypeOrInfinite ι + · -- `v` is a finite basis, so by `basis_finite_of_finite_spans` so is `v'`. + -- haveI : Finite (range v) := Set.finite_range v + haveI := basis_finite_of_finite_spans _ (Set.finite_range v) v.span_eq v' + cases nonempty_fintype ι' + -- We clean up a little: + rw [Cardinal.mk_fintype, Cardinal.mk_fintype] + simp only [Cardinal.lift_natCast, Cardinal.natCast_inj] + -- Now we can use invariant basis number to show they have the same cardinality. + apply card_eq_of_linearEquiv R + exact + (Finsupp.linearEquivFunOnFinite R R ι).symm.trans v.repr.symm ≪≫ₗ v'.repr ≪≫ₗ + Finsupp.linearEquivFunOnFinite R R ι' + · -- `v` is an infinite basis, + -- so by `infinite_basis_le_maximal_linearIndependent`, `v'` is at least as big, + -- and then applying `infinite_basis_le_maximal_linearIndependent` again + -- we see they have the same cardinality. + have w₁ := infinite_basis_le_maximal_linearIndependent' v _ v'.linearIndependent v'.maximal + rcases Cardinal.lift_mk_le'.mp w₁ with ⟨f⟩ + haveI : Infinite ι' := Infinite.of_injective f f.2 + have w₂ := infinite_basis_le_maximal_linearIndependent' v' _ v.linearIndependent v.maximal + exact le_antisymm w₁ w₂ +#align mk_eq_mk_of_basis mk_eq_mk_of_basis + +/-- Given two bases indexed by `ι` and `ι'` of an `R`-module, where `R` satisfies the invariant +basis number property, an equiv `ι ≃ ι'`. -/ +def Basis.indexEquiv (v : Basis ι R M) (v' : Basis ι' R M) : ι ≃ ι' := + (Cardinal.lift_mk_eq'.1 <| mk_eq_mk_of_basis v v').some +#align basis.index_equiv Basis.indexEquiv + +theorem mk_eq_mk_of_basis' {ι' : Type w} (v : Basis ι R M) (v' : Basis ι' R M) : #ι = #ι' := + Cardinal.lift_inj.1 <| mk_eq_mk_of_basis v v' +#align mk_eq_mk_of_basis' mk_eq_mk_of_basis' + +end InvariantBasisNumber + +section RankCondition + +variable [RankCondition R] + +/-- An auxiliary lemma for `Basis.le_span`. + +If `R` satisfies the rank condition, +then for any finite basis `b : Basis ι R M`, +and any finite spanning set `w : Set M`, +the cardinality of `ι` is bounded by the cardinality of `w`. +-/ +theorem Basis.le_span'' {ι : Type*} [Fintype ι] (b : Basis ι R M) {w : Set M} [Fintype w] + (s : span R w = ⊤) : Fintype.card ι ≤ Fintype.card w := by + -- We construct a surjective linear map `(w → R) →ₗ[R] (ι → R)`, + -- by expressing a linear combination in `w` as a linear combination in `ι`. + fapply card_le_of_surjective' R + · exact b.repr.toLinearMap.comp (Finsupp.total w M R (↑)) + · apply Surjective.comp (g := b.repr.toLinearMap) + apply LinearEquiv.surjective + rw [← LinearMap.range_eq_top, Finsupp.range_total] + simpa using s +#align basis.le_span'' Basis.le_span'' + +/-- +Another auxiliary lemma for `Basis.le_span`, which does not require assuming the basis is finite, +but still assumes we have a finite spanning set. +-/ +theorem basis_le_span' {ι : Type*} (b : Basis ι R M) {w : Set M} [Fintype w] (s : span R w = ⊤) : + #ι ≤ Fintype.card w := by + haveI := nontrivial_of_invariantBasisNumber R + haveI := basis_finite_of_finite_spans w (toFinite _) s b + cases nonempty_fintype ι + rw [Cardinal.mk_fintype ι] + simp only [Cardinal.natCast_le] + exact Basis.le_span'' b s +#align basis_le_span' basis_le_span' + +-- Note that if `R` satisfies the strong rank condition, +-- this also follows from `linearIndependent_le_span` below. +/-- If `R` satisfies the rank condition, +then the cardinality of any basis is bounded by the cardinality of any spanning set. +-/ +theorem Basis.le_span {J : Set M} (v : Basis ι R M) (hJ : span R J = ⊤) : #(range v) ≤ #J := by + haveI := nontrivial_of_invariantBasisNumber R + cases fintypeOrInfinite J + · rw [← Cardinal.lift_le, Cardinal.mk_range_eq_of_injective v.injective, Cardinal.mk_fintype J] + convert Cardinal.lift_le.{v}.2 (basis_le_span' v hJ) + simp + · let S : J → Set ι := fun j => ↑(v.repr j).support + let S' : J → Set M := fun j => v '' S j + have hs : range v ⊆ ⋃ j, S' j := by + intro b hb + rcases mem_range.1 hb with ⟨i, hi⟩ + have : span R J ≤ comap v.repr.toLinearMap (Finsupp.supported R R (⋃ j, S j)) := + span_le.2 fun j hj x hx => ⟨_, ⟨⟨j, hj⟩, rfl⟩, hx⟩ + rw [hJ] at this + replace : v.repr (v i) ∈ Finsupp.supported R R (⋃ j, S j) := this trivial + rw [v.repr_self, Finsupp.mem_supported, Finsupp.support_single_ne_zero _ one_ne_zero] at this + · subst b + rcases mem_iUnion.1 (this (Finset.mem_singleton_self _)) with ⟨j, hj⟩ + exact mem_iUnion.2 ⟨j, (mem_image _ _ _).2 ⟨i, hj, rfl⟩⟩ + refine' le_of_not_lt fun IJ => _ + suffices #(⋃ j, S' j) < #(range v) by exact not_le_of_lt this ⟨Set.embeddingOfSubset _ _ hs⟩ + refine' lt_of_le_of_lt (le_trans Cardinal.mk_iUnion_le_sum_mk + (Cardinal.sum_le_sum _ (fun _ => ℵ₀) _)) _ + · exact fun j => (Cardinal.lt_aleph0_of_finite _).le + · simpa +#align basis.le_span Basis.le_span + +end RankCondition + +section StrongRankCondition + +variable [StrongRankCondition R] + +open Submodule + +-- An auxiliary lemma for `linearIndependent_le_span'`, +-- with the additional assumption that the linearly independent family is finite. +theorem linearIndependent_le_span_aux' {ι : Type*} [Fintype ι] (v : ι → M) + (i : LinearIndependent R v) (w : Set M) [Fintype w] (s : range v ≤ span R w) : + Fintype.card ι ≤ Fintype.card w := by + -- We construct an injective linear map `(ι → R) →ₗ[R] (w → R)`, + -- by thinking of `f : ι → R` as a linear combination of the finite family `v`, + -- and expressing that (using the axiom of choice) as a linear combination over `w`. + -- We can do this linearly by constructing the map on a basis. + fapply card_le_of_injective' R + · apply Finsupp.total + exact fun i => Span.repr R w ⟨v i, s (mem_range_self i)⟩ + · intro f g h + apply_fun Finsupp.total w M R (↑) at h + simp only [Finsupp.total_total, Submodule.coe_mk, Span.finsupp_total_repr] at h + rw [← sub_eq_zero, ← LinearMap.map_sub] at h + exact sub_eq_zero.mp (linearIndependent_iff.mp i _ h) +#align linear_independent_le_span_aux' linearIndependent_le_span_aux' + +/-- If `R` satisfies the strong rank condition, +then any linearly independent family `v : ι → M` +contained in the span of some finite `w : Set M`, +is itself finite. +-/ +lemma LinearIndependent.finite_of_le_span_finite {ι : Type*} (v : ι → M) (i : LinearIndependent R v) + (w : Set M) [Finite w] (s : range v ≤ span R w) : Finite ι := + letI := Fintype.ofFinite w + Fintype.finite <| fintypeOfFinsetCardLe (Fintype.card w) fun t => by + let v' := fun x : (t : Set ι) => v x + have i' : LinearIndependent R v' := i.comp _ Subtype.val_injective + have s' : range v' ≤ span R w := (range_comp_subset_range _ _).trans s + simpa using linearIndependent_le_span_aux' v' i' w s' +#align linear_independent_fintype_of_le_span_fintype LinearIndependent.finite_of_le_span_finite + +/-- If `R` satisfies the strong rank condition, +then for any linearly independent family `v : ι → M` +contained in the span of some finite `w : Set M`, +the cardinality of `ι` is bounded by the cardinality of `w`. +-/ +theorem linearIndependent_le_span' {ι : Type*} (v : ι → M) (i : LinearIndependent R v) (w : Set M) + [Fintype w] (s : range v ≤ span R w) : #ι ≤ Fintype.card w := by + haveI : Finite ι := i.finite_of_le_span_finite v w s + letI := Fintype.ofFinite ι + rw [Cardinal.mk_fintype] + simp only [Cardinal.natCast_le] + exact linearIndependent_le_span_aux' v i w s +#align linear_independent_le_span' linearIndependent_le_span' + +/-- If `R` satisfies the strong rank condition, +then for any linearly independent family `v : ι → M` +and any finite spanning set `w : Set M`, +the cardinality of `ι` is bounded by the cardinality of `w`. +-/ +theorem linearIndependent_le_span {ι : Type*} (v : ι → M) (i : LinearIndependent R v) (w : Set M) + [Fintype w] (s : span R w = ⊤) : #ι ≤ Fintype.card w := by + apply linearIndependent_le_span' v i w + rw [s] + exact le_top +#align linear_independent_le_span linearIndependent_le_span + +/-- A version of `linearIndependent_le_span` for `Finset`. -/ +theorem linearIndependent_le_span_finset {ι : Type*} (v : ι → M) (i : LinearIndependent R v) + (w : Finset M) (s : span R (w : Set M) = ⊤) : #ι ≤ w.card := by + simpa only [Finset.coe_sort_coe, Fintype.card_coe] using linearIndependent_le_span v i w s +#align linear_independent_le_span_finset linearIndependent_le_span_finset + +/-- An auxiliary lemma for `linearIndependent_le_basis`: +we handle the case where the basis `b` is infinite. +-/ +theorem linearIndependent_le_infinite_basis {ι : Type w} (b : Basis ι R M) [Infinite ι] {κ : Type w} + (v : κ → M) (i : LinearIndependent R v) : #κ ≤ #ι := by + classical + by_contra h + rw [not_le, ← Cardinal.mk_finset_of_infinite ι] at h + let Φ := fun k : κ => (b.repr (v k)).support + obtain ⟨s, w : Infinite ↑(Φ ⁻¹' {s})⟩ := Cardinal.exists_infinite_fiber Φ h (by infer_instance) + let v' := fun k : Φ ⁻¹' {s} => v k + have i' : LinearIndependent R v' := i.comp _ Subtype.val_injective + have w' : Finite (Φ ⁻¹' {s}) := by + apply i'.finite_of_le_span_finite v' (s.image b) + rintro m ⟨⟨p, ⟨rfl⟩⟩, rfl⟩ + simp only [SetLike.mem_coe, Subtype.coe_mk, Finset.coe_image] + apply Basis.mem_span_repr_support + exact w.false +#align linear_independent_le_infinite_basis linearIndependent_le_infinite_basis + +/-- Over any ring `R` satisfying the strong rank condition, +if `b` is a basis for a module `M`, +and `s` is a linearly independent set, +then the cardinality of `s` is bounded by the cardinality of `b`. +-/ +theorem linearIndependent_le_basis {ι : Type w} (b : Basis ι R M) {κ : Type w} (v : κ → M) + (i : LinearIndependent R v) : #κ ≤ #ι := by + classical + -- We split into cases depending on whether `ι` is infinite. + cases fintypeOrInfinite ι + · rw [Cardinal.mk_fintype ι] -- When `ι` is finite, we have `linearIndependent_le_span`, + haveI : Nontrivial R := nontrivial_of_invariantBasisNumber R + rw [Fintype.card_congr (Equiv.ofInjective b b.injective)] + exact linearIndependent_le_span v i (range b) b.span_eq + · -- and otherwise we have `linearIndependent_le_infinite_basis`. + exact linearIndependent_le_infinite_basis b v i +#align linear_independent_le_basis linearIndependent_le_basis + +/-- Let `R` satisfy the strong rank condition. If `m` elements of a free rank `n` `R`-module are +linearly independent, then `m ≤ n`. -/ +theorem Basis.card_le_card_of_linearIndependent_aux {R : Type*} [Ring R] [StrongRankCondition R] + (n : ℕ) {m : ℕ} (v : Fin m → Fin n → R) : LinearIndependent R v → m ≤ n := fun h => by + simpa using linearIndependent_le_basis (Pi.basisFun R (Fin n)) v h +#align basis.card_le_card_of_linear_independent_aux Basis.card_le_card_of_linearIndependent_aux + +-- When the basis is not infinite this need not be true! +/-- Over any ring `R` satisfying the strong rank condition, +if `b` is an infinite basis for a module `M`, +then every maximal linearly independent set has the same cardinality as `b`. + +This proof (along with some of the lemmas above) comes from +[Les familles libres maximales d'un module ont-elles le meme cardinal?][lazarus1973] +-/ +theorem maximal_linearIndependent_eq_infinite_basis {ι : Type w} (b : Basis ι R M) [Infinite ι] + {κ : Type w} (v : κ → M) (i : LinearIndependent R v) (m : i.Maximal) : #κ = #ι := by + apply le_antisymm + · exact linearIndependent_le_basis b v i + · haveI : Nontrivial R := nontrivial_of_invariantBasisNumber R + exact infinite_basis_le_maximal_linearIndependent b v i m +#align maximal_linear_independent_eq_infinite_basis maximal_linearIndependent_eq_infinite_basis + +theorem Basis.mk_eq_rank'' {ι : Type v} (v : Basis ι R M) : #ι = Module.rank R M := by + haveI := nontrivial_of_invariantBasisNumber R + rw [Module.rank_def] + apply le_antisymm + · trans + swap + · apply le_ciSup (Cardinal.bddAbove_range.{v, v} _) + exact + ⟨Set.range v, by + convert v.reindexRange.linearIndependent + ext + simp⟩ + · exact (Cardinal.mk_range_eq v v.injective).ge + · apply ciSup_le' + rintro ⟨s, li⟩ + apply linearIndependent_le_basis v _ li +#align basis.mk_eq_rank'' Basis.mk_eq_rank'' + +theorem Basis.mk_range_eq_rank (v : Basis ι R M) : #(range v) = Module.rank R M := + v.reindexRange.mk_eq_rank'' +#align basis.mk_range_eq_rank Basis.mk_range_eq_rank + +/-- If a vector space has a finite basis, then its dimension (seen as a cardinal) is equal to the +cardinality of the basis. -/ +theorem rank_eq_card_basis {ι : Type w} [Fintype ι] (h : Basis ι R M) : + Module.rank R M = Fintype.card ι := by + classical + haveI := nontrivial_of_invariantBasisNumber R + rw [← h.mk_range_eq_rank, Cardinal.mk_fintype, Set.card_range_of_injective h.injective] +#align rank_eq_card_basis rank_eq_card_basis + +theorem Basis.card_le_card_of_linearIndependent {ι : Type*} [Fintype ι] (b : Basis ι R M) + {ι' : Type*} [Fintype ι'] {v : ι' → M} (hv : LinearIndependent R v) : + Fintype.card ι' ≤ Fintype.card ι := by + letI := nontrivial_of_invariantBasisNumber R + simpa [rank_eq_card_basis b, Cardinal.mk_fintype] using hv.cardinal_lift_le_rank +#align basis.card_le_card_of_linear_independent Basis.card_le_card_of_linearIndependent + +theorem Basis.card_le_card_of_submodule (N : Submodule R M) [Fintype ι] (b : Basis ι R M) + [Fintype ι'] (b' : Basis ι' R N) : Fintype.card ι' ≤ Fintype.card ι := + b.card_le_card_of_linearIndependent (b'.linearIndependent.map' N.subtype N.ker_subtype) +#align basis.card_le_card_of_submodule Basis.card_le_card_of_submodule + +theorem Basis.card_le_card_of_le {N O : Submodule R M} (hNO : N ≤ O) [Fintype ι] (b : Basis ι R O) + [Fintype ι'] (b' : Basis ι' R N) : Fintype.card ι' ≤ Fintype.card ι := + b.card_le_card_of_linearIndependent + (b'.linearIndependent.map' (Submodule.inclusion hNO) (N.ker_inclusion O _)) +#align basis.card_le_card_of_le Basis.card_le_card_of_le + +theorem Basis.mk_eq_rank (v : Basis ι R M) : + Cardinal.lift.{v} #ι = Cardinal.lift.{w} (Module.rank R M) := by + haveI := nontrivial_of_invariantBasisNumber R + rw [← v.mk_range_eq_rank, Cardinal.mk_range_eq_of_injective v.injective] +#align basis.mk_eq_rank Basis.mk_eq_rank + +theorem Basis.mk_eq_rank'.{m} (v : Basis ι R M) : + Cardinal.lift.{max v m} #ι = Cardinal.lift.{max w m} (Module.rank R M) := + Cardinal.lift_umax_eq.{w, v, m}.mpr v.mk_eq_rank +#align basis.mk_eq_rank' Basis.mk_eq_rank' + +theorem rank_span {v : ι → M} (hv : LinearIndependent R v) : + Module.rank R ↑(span R (range v)) = #(range v) := by + haveI := nontrivial_of_invariantBasisNumber R + rw [← Cardinal.lift_inj, ← (Basis.span hv).mk_eq_rank, + Cardinal.mk_range_eq_of_injective (@LinearIndependent.injective ι R M v _ _ _ _ hv)] +#align rank_span rank_span + +theorem rank_span_set {s : Set M} (hs : LinearIndependent R (fun x => x : s → M)) : + Module.rank R ↑(span R s) = #s := by + rw [← @setOf_mem_eq _ s, ← Subtype.range_coe_subtype] + exact rank_span hs +#align rank_span_set rank_span_set + +/-- An induction (and recursion) principle for proving results about all submodules of a fixed +finite free module `M`. A property is true for all submodules of `M` if it satisfies the following +"inductive step": the property is true for a submodule `N` if it's true for all submodules `N'` +of `N` with the property that there exists `0 ≠ x ∈ N` such that the sum `N' + Rx` is direct. -/ +def Submodule.inductionOnRank [IsDomain R] [Finite ι] (b : Basis ι R M) + (P : Submodule R M → Sort*) (ih : ∀ N : Submodule R M, + (∀ N' ≤ N, ∀ x ∈ N, (∀ (c : R), ∀ y ∈ N', c • x + y = (0 : M) → c = 0) → P N') → P N) + (N : Submodule R M) : P N := + letI := Fintype.ofFinite ι + Submodule.inductionOnRankAux b P ih (Fintype.card ι) N fun hs hli => by + simpa using b.card_le_card_of_linearIndependent hli +#align submodule.induction_on_rank Submodule.inductionOnRank + +/-- If `S` a module-finite free `R`-algebra, then the `R`-rank of a nonzero `R`-free +ideal `I` of `S` is the same as the rank of `S`. -/ +theorem Ideal.rank_eq {R S : Type*} [CommRing R] [StrongRankCondition R] [Ring S] [IsDomain S] + [Algebra R S] {n m : Type*} [Fintype n] [Fintype m] (b : Basis n R S) {I : Ideal S} + (hI : I ≠ ⊥) (c : Basis m R I) : Fintype.card m = Fintype.card n := by + obtain ⟨a, ha⟩ := Submodule.nonzero_mem_of_bot_lt (bot_lt_iff_ne_bot.mpr hI) + have : LinearIndependent R fun i => b i • a := by + have hb := b.linearIndependent + rw [Fintype.linearIndependent_iff] at hb ⊢ + intro g hg + apply hb g + simp only [← smul_assoc, ← Finset.sum_smul, smul_eq_zero] at hg + exact hg.resolve_right ha + exact le_antisymm + (b.card_le_card_of_linearIndependent (c.linearIndependent.map' (Submodule.subtype I) + ((LinearMap.ker_eq_bot (f := (Submodule.subtype I : I →ₗ[R] S))).mpr Subtype.coe_injective))) + (c.card_le_card_of_linearIndependent this) +#align ideal.rank_eq Ideal.rank_eq + +open FiniteDimensional + +theorem finrank_eq_nat_card_basis (h : Basis ι R M) : + finrank R M = Nat.card ι := by + rw [Nat.card, ← toNat_lift.{v}, h.mk_eq_rank, toNat_lift, finrank] + +namespace FiniteDimensional + +/-- If a vector space (or module) has a finite basis, then its dimension (or rank) is equal to the +cardinality of the basis. -/ +theorem finrank_eq_card_basis {ι : Type w} [Fintype ι] (h : Basis ι R M) : + finrank R M = Fintype.card ι := + finrank_eq_of_rank_eq (rank_eq_card_basis h) +#align finite_dimensional.finrank_eq_card_basis FiniteDimensional.finrank_eq_card_basis + +/-- If a free module is of finite rank, then the cardinality of any basis is equal to its +`finrank`. -/ +theorem _root_.Module.mk_finrank_eq_card_basis [Module.Finite R M] + {ι : Type w} (h : Basis ι R M) : (finrank R M : Cardinal.{w}) = #ι := by + cases @nonempty_fintype _ (Module.Finite.finite_basis h) + rw [Cardinal.mk_fintype, finrank_eq_card_basis h] + +/-- If a vector space (or module) has a finite basis, then its dimension (or rank) is equal to the +cardinality of the basis. This lemma uses a `Finset` instead of indexed types. -/ +theorem finrank_eq_card_finset_basis {ι : Type w} {b : Finset ι} (h : Basis b R M) : + finrank R M = Finset.card b := by rw [finrank_eq_card_basis h, Fintype.card_coe] +#align finite_dimensional.finrank_eq_card_finset_basis FiniteDimensional.finrank_eq_card_finset_basis + +end FiniteDimensional + +open FiniteDimensional + +variable (R) + +@[simp] +theorem rank_self : Module.rank R R = 1 := by + rw [← Cardinal.lift_inj, ← (Basis.singleton PUnit R).mk_eq_rank, Cardinal.mk_punit] +#align rank_self rank_self + +/-- A ring satisfying `StrongRankCondition` (such as a `DivisionRing`) is one-dimensional as a +module over itself. -/ +@[simp] +theorem FiniteDimensional.finrank_self : finrank R R = 1 := + finrank_eq_of_rank_eq (by simp) +#align finite_dimensional.finrank_self FiniteDimensional.finrank_self + +/-- Given a basis of a ring over itself indexed by a type `ι`, then `ι` is `Unique`. -/ +noncomputable def Basis.unique {ι : Type*} (b : Basis ι R R) : Unique ι := by + have A : Cardinal.mk ι = ↑(FiniteDimensional.finrank R R) := + (Module.mk_finrank_eq_card_basis b).symm + -- porting note: replace `algebraMap.coe_one` with `Nat.cast_one` + simp only [Cardinal.eq_one_iff_unique, FiniteDimensional.finrank_self, Nat.cast_one] at A + exact Nonempty.some ((unique_iff_subsingleton_and_nonempty _).2 A) +#align basis.unique Basis.unique + +variable (M) + +/-- The rank of a finite module is finite. -/ +theorem rank_lt_aleph0 [Module.Finite R M] : Module.rank R M < ℵ₀ := by + simp only [Module.rank_def] + -- porting note: can't use `‹_›` as that pulls the unused `N` into the context + obtain ⟨S, hS⟩ := Module.finite_def.mp ‹Module.Finite R M› + refine' (ciSup_le' fun i => _).trans_lt (nat_lt_aleph0 S.card) + exact linearIndependent_le_span_finset _ i.prop S hS +#align finite_dimensional.rank_lt_aleph_0 rank_lt_aleph0 + +@[deprecated] protected alias FiniteDimensional.rank_lt_aleph0 := rank_lt_aleph0 + +/-- If `M` is finite, `finrank M = rank M`. -/ +@[simp] +theorem finrank_eq_rank [Module.Finite R M] : + ↑(FiniteDimensional.finrank R M) = Module.rank R M := by + rw [FiniteDimensional.finrank, cast_toNat_of_lt_aleph0 (rank_lt_aleph0 R M)] +#align finite_dimensional.finrank_eq_rank finrank_eq_rank + +@[deprecated] protected alias FiniteDimensional.finrank_eq_rank := finrank_eq_rank + +variable {R M} +variable {M'} [AddCommGroup M'] [Module R M'] + +theorem LinearMap.finrank_le_finrank_of_injective [Module.Finite R M'] {f : M →ₗ[R] M'} + (hf : Function.Injective f) : finrank R M ≤ finrank R M' := + finrank_le_finrank_of_rank_le_rank (LinearMap.lift_rank_le_of_injective _ hf) (rank_lt_aleph0 _ _) +#align linear_map.finrank_le_finrank_of_injective LinearMap.finrank_le_finrank_of_injective + +theorem LinearMap.finrank_range_le [Module.Finite R M] (f : M →ₗ[R] M') : + finrank R (LinearMap.range f) ≤ finrank R M := + finrank_le_finrank_of_rank_le_rank (lift_rank_range_le f) (rank_lt_aleph0 _ _) +#align linear_map.finrank_range_le LinearMap.finrank_range_le + +end StrongRankCondition diff --git a/Mathlib/LinearAlgebra/FiniteDimensional.lean b/Mathlib/LinearAlgebra/FiniteDimensional.lean index 3851077c96242..cb0bc96d39f12 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean @@ -3,11 +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 Mathlib.Algebra.Algebra.Subalgebra.Basic import Mathlib.FieldTheory.Finiteness -import Mathlib.LinearAlgebra.FreeModule.Finite.Rank -import Mathlib.Tactic.IntervalCases -import Mathlib.Tactic.ApplyCongr #align_import linear_algebra.finite_dimensional from "leanprover-community/mathlib"@"e95e4f92c8f8da3c7f693c3ec948bcf9b6683f51" @@ -139,7 +135,7 @@ theorem of_fintype_basis {ι : Type w} [Finite ι] (h : Basis ι K V) : FiniteDi /-- If a vector space is `FiniteDimensional`, all bases are indexed by a finite type -/ noncomputable def fintypeBasisIndex {ι : Type*} [FiniteDimensional K V] (b : Basis ι K V) : Fintype ι := - @Fintype.ofFinite _ (Module.Free.finite_basis b) + @Fintype.ofFinite _ (Module.Finite.finite_basis b) #align finite_dimensional.fintype_basis_index FiniteDimensional.fintypeBasisIndex /-- If a vector space is `FiniteDimensional`, `Basis.ofVectorSpace` is indexed by @@ -163,7 +159,7 @@ instance finiteDimensional_submodule [FiniteDimensional K V] (S : Submodule K V) exact iff_fg.1 (IsNoetherian.iff_rank_lt_aleph0.2 - (lt_of_le_of_lt (rank_submodule_le _) (rank_lt_aleph0 K V))) + (lt_of_le_of_lt (rank_submodule_le _) (_root_.rank_lt_aleph0 K V))) infer_instance #align finite_dimensional.finite_dimensional_submodule FiniteDimensional.finiteDimensional_submodule @@ -399,7 +395,7 @@ theorem finiteDimensional_of_le {S₁ S₂ : Submodule K V} [FiniteDimensional K haveI : IsNoetherian K S₂ := iff_fg.2 inferInstance iff_fg.1 (IsNoetherian.iff_rank_lt_aleph0.2 - (lt_of_le_of_lt (rank_le_of_submodule _ _ h) (FiniteDimensional.rank_lt_aleph0 K S₂))) + (lt_of_le_of_lt (rank_le_of_submodule _ _ h) (rank_lt_aleph0 K S₂))) #align submodule.finite_dimensional_of_le Submodule.finiteDimensional_of_le /-- The inf of two submodules, the first finite-dimensional, is @@ -1310,7 +1306,7 @@ theorem cardinal_lt_aleph0_of_finiteDimensional (K V : Type u) [DivisionRing K] [Module K V] [Finite K] [FiniteDimensional K V] : #V < ℵ₀ := by letI : IsNoetherian K V := IsNoetherian.iff_fg.2 inferInstance rw [cardinal_mk_eq_cardinal_mk_field_pow_rank K V] - exact Cardinal.power_lt_aleph0 (Cardinal.lt_aleph0_of_finite K) (IsNoetherian.rank_lt_aleph0 K V) + exact Cardinal.power_lt_aleph0 (Cardinal.lt_aleph0_of_finite K) (rank_lt_aleph0 K V) #align cardinal_lt_aleph_0_of_finite_dimensional cardinal_lt_aleph0_of_finiteDimensional end Module diff --git a/Mathlib/LinearAlgebra/Finrank.lean b/Mathlib/LinearAlgebra/Finrank.lean deleted file mode 100644 index 324138a45592c..0000000000000 --- a/Mathlib/LinearAlgebra/Finrank.lean +++ /dev/null @@ -1,621 +0,0 @@ -/- -Copyright (c) 2019 Chris Hughes. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Chris Hughes, Anne Baanen --/ -import Mathlib.LinearAlgebra.Dimension - -#align_import linear_algebra.finrank from "leanprover-community/mathlib"@"347636a7a80595d55bedf6e6fbd996a3c39da69a" - -/-! -# Finite dimension of vector spaces - -Definition of the rank of a module, or dimension of a vector space, as a natural number. - -## Main definitions - -Defined is `FiniteDimensional.finrank`, the dimension of a finite dimensional space, returning a -`Nat`, as opposed to `Module.rank`, which returns a `Cardinal`. When the space has infinite -dimension, its `finrank` is by convention set to `0`. - -The definition of `finrank` does not assume a `FiniteDimensional` instance, but lemmas might. -Import `LinearAlgebra.FiniteDimensional` to get access to these additional lemmas. - -Formulas for the dimension are given for linear equivs, in `LinearEquiv.finrank_eq`. - -## Implementation notes - -Most results are deduced from the corresponding results for the general dimension (as a cardinal), -in `Dimension.lean`. Not all results have been ported yet. - -You should not assume that there has been any effort to state lemmas as generally as possible. --/ - - -universe u v v' w - -open Cardinal - -open Cardinal Submodule Module Function - -variable {K : Type u} {V : Type v} - -namespace FiniteDimensional - -open IsNoetherian - -section Ring - -variable [Ring K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂] [Module K V₂] - -/-- The rank of a module as a natural number. - -Defined by convention to be `0` if the space has infinite rank. - -For a vector space `V` over a field `K`, this is the same as the finite dimension -of `V` over `K`. --/ -noncomputable def finrank (R V : Type*) [Semiring R] [AddCommGroup V] [Module R V] : ℕ := - Cardinal.toNat (Module.rank R V) -#align finite_dimensional.finrank FiniteDimensional.finrank - -theorem finrank_eq_of_rank_eq {n : ℕ} (h : Module.rank K V = ↑n) : finrank K V = n := by - apply_fun toNat at h - rw [toNat_cast] at h - exact mod_cast h -#align finite_dimensional.finrank_eq_of_rank_eq FiniteDimensional.finrank_eq_of_rank_eq - -lemma rank_eq_one_iff_finrank_eq_one : Module.rank K V = 1 ↔ finrank K V = 1 := - Cardinal.toNat_eq_one.symm - -/-- This is like `rank_eq_one_iff_finrank_eq_one` but works for `2`, `3`, `4`, ... -/ -lemma rank_eq_ofNat_iff_finrank_eq_ofNat (n : ℕ) [Nat.AtLeastTwo n] : - Module.rank K V = OfNat.ofNat n ↔ finrank K V = OfNat.ofNat n := - Cardinal.toNat_eq_ofNat.symm - -theorem finrank_le_of_rank_le {n : ℕ} (h : Module.rank K V ≤ ↑n) : finrank K V ≤ n := by - rwa [← Cardinal.toNat_le_iff_le_of_lt_aleph0, toNat_cast] at h - · exact h.trans_lt (nat_lt_aleph0 n) - · exact nat_lt_aleph0 n -#align finite_dimensional.finrank_le_of_rank_le FiniteDimensional.finrank_le_of_rank_le - -theorem finrank_lt_of_rank_lt {n : ℕ} (h : Module.rank K V < ↑n) : finrank K V < n := by - rwa [← Cardinal.toNat_lt_iff_lt_of_lt_aleph0, toNat_cast] at h - · exact h.trans (nat_lt_aleph0 n) - · exact nat_lt_aleph0 n -#align finite_dimensional.finrank_lt_of_rank_lt FiniteDimensional.finrank_lt_of_rank_lt - -theorem lt_rank_of_lt_finrank {n : ℕ} (h : n < finrank K V) : ↑n < Module.rank K V := by - rwa [← Cardinal.toNat_lt_iff_lt_of_lt_aleph0, toNat_cast] - · exact nat_lt_aleph0 n - · contrapose! h - rw [finrank, Cardinal.toNat_apply_of_aleph0_le h] - exact n.zero_le -#align finite_dimensional.rank_lt_of_finrank_lt FiniteDimensional.lt_rank_of_lt_finrank - -theorem one_lt_rank_of_one_lt_finrank (h : 1 < finrank K V) : 1 < Module.rank K V := by - simpa using lt_rank_of_lt_finrank h - -theorem finrank_le_finrank_of_rank_le_rank - (h : lift.{v'} (Module.rank K V) ≤ Cardinal.lift.{v} (Module.rank K V₂)) - (h' : Module.rank K V₂ < ℵ₀) : finrank K V ≤ finrank K V₂ := by - simpa only [toNat_lift] using toNat_le_of_le_of_lt_aleph0 (lift_lt_aleph0.mpr h') h -#align finite_dimensional.finrank_le_finrank_of_rank_le_rank FiniteDimensional.finrank_le_finrank_of_rank_le_rank - -section - -variable [Nontrivial K] [NoZeroSMulDivisors K V] - -/-- A finite dimensional space is nontrivial if it has positive `finrank`. -/ -theorem nontrivial_of_finrank_pos (h : 0 < finrank K V) : Nontrivial V := - rank_pos_iff_nontrivial.mp (lt_rank_of_lt_finrank h) -#align finite_dimensional.nontrivial_of_finrank_pos FiniteDimensional.nontrivial_of_finrank_pos - -/-- A finite dimensional space is nontrivial if it has `finrank` equal to the successor of a -natural number. -/ -theorem nontrivial_of_finrank_eq_succ {n : ℕ} (hn : finrank K V = n.succ) : Nontrivial V := - nontrivial_of_finrank_pos (by rw [hn]; exact n.succ_pos) -#align finite_dimensional.nontrivial_of_finrank_eq_succ FiniteDimensional.nontrivial_of_finrank_eq_succ - -/-- A (finite dimensional) space that is a subsingleton has zero `finrank`. -/ -@[nontriviality] -theorem finrank_zero_of_subsingleton [h : Subsingleton V] : finrank K V = 0 := by - by_contra h0 - obtain ⟨x, y, hxy⟩ := nontrivial_of_finrank_pos (Nat.pos_of_ne_zero h0) - exact hxy (Subsingleton.elim _ _) -#align finite_dimensional.finrank_zero_of_subsingleton FiniteDimensional.finrank_zero_of_subsingleton - -end - -section - -variable [StrongRankCondition K] - -/-- If a vector space (or module) has a finite basis, then its dimension (or rank) is equal to the -cardinality of the basis. -/ -theorem finrank_eq_card_basis {ι : Type w} [Fintype ι] (h : Basis ι K V) : - finrank K V = Fintype.card ι := - finrank_eq_of_rank_eq (rank_eq_card_basis h) -#align finite_dimensional.finrank_eq_card_basis FiniteDimensional.finrank_eq_card_basis - -/-- If a vector space (or module) has a finite basis, then its dimension (or rank) is equal to the -cardinality of the basis. This lemma uses a `Finset` instead of indexed types. -/ -theorem finrank_eq_card_finset_basis {ι : Type w} {b : Finset ι} (h : Basis b K V) : - finrank K V = Finset.card b := by rw [finrank_eq_card_basis h, Fintype.card_coe] -#align finite_dimensional.finrank_eq_card_finset_basis FiniteDimensional.finrank_eq_card_finset_basis - -variable (K) - -/-- A ring satisfying `StrongRankCondition` (such as a `DivisionRing`) is one-dimensional as a -module over itself. -/ -@[simp] -theorem finrank_self : finrank K K = 1 := - finrank_eq_of_rank_eq (by simp) -#align finite_dimensional.finrank_self FiniteDimensional.finrank_self - -/-- The vector space of functions on a `Fintype ι` has finrank equal to the cardinality of `ι`. -/ -@[simp] -theorem finrank_fintype_fun_eq_card {ι : Type v} [Fintype ι] : finrank K (ι → K) = Fintype.card ι := - finrank_eq_of_rank_eq rank_fun' -#align finite_dimensional.finrank_fintype_fun_eq_card FiniteDimensional.finrank_fintype_fun_eq_card - -/-- The vector space of functions on `Fin n` has finrank equal to `n`. -/ --- @[simp] -- Porting note: simp already proves this -theorem finrank_fin_fun {n : ℕ} : finrank K (Fin n → K) = n := by simp -#align finite_dimensional.finrank_fin_fun FiniteDimensional.finrank_fin_fun - -end - -end Ring - -section DivisionRing - -variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂] - [Module K V₂] - -theorem Basis.subset_extend {s : Set V} (hs : LinearIndependent K ((↑) : s → V)) : - s ⊆ hs.extend (Set.subset_univ _) := - hs.subset_extend _ -#align finite_dimensional.basis.subset_extend FiniteDimensional.Basis.subset_extend - -end DivisionRing - -end FiniteDimensional - -section ZeroRank - -variable [Ring K] [AddCommGroup V] [Module K V] - -open FiniteDimensional - -lemma LinearIndependent.finrank_eq_zero_of_infinite {ι} [Nontrivial K] [Infinite ι] {v : ι → V} - (hv : LinearIndependent K v) : finrank K V = 0 := toNat_eq_zero.mpr <| .inr hv.aleph0_le_rank - -theorem finrank_eq_nat_card_basis {ι} [StrongRankCondition K] - (h : Basis ι K V) : finrank K V = Nat.card ι := by - rw [Nat.card, ← toNat_lift.{v}, h.mk_eq_rank, toNat_lift, finrank] - -variable [Module.Free K V] - -theorem finrank_eq_zero_of_basis_imp_not_finite - (h : ∀ s : Set V, Basis.{v} (s : Set V) K V → ¬s.Finite) : finrank K V = 0 := by - cases subsingleton_or_nontrivial K - · have := Module.subsingleton K V - exact (h ∅ ⟨LinearEquiv.ofSubsingleton _ _⟩ Set.finite_empty).elim - obtain ⟨_, ⟨b⟩⟩ := (Module.free_iff_set K V).mp ‹_› - have := Set.Infinite.to_subtype (h _ b) - exact b.linearIndependent.finrank_eq_zero_of_infinite -#align finrank_eq_zero_of_basis_imp_not_finite finrank_eq_zero_of_basis_imp_not_finite - -theorem finrank_eq_zero_of_basis_imp_false (h : ∀ s : Finset V, Basis.{v} (s : Set V) K V → False) : - finrank K V = 0 := - finrank_eq_zero_of_basis_imp_not_finite fun s b hs => - h hs.toFinset - (by - convert b - simp) -#align finrank_eq_zero_of_basis_imp_false finrank_eq_zero_of_basis_imp_false - -theorem finrank_eq_zero_of_not_exists_basis - (h : ¬∃ s : Finset V, Nonempty (Basis (s : Set V) K V)) : finrank K V = 0 := - finrank_eq_zero_of_basis_imp_false fun s b => h ⟨s, ⟨b⟩⟩ -#align finrank_eq_zero_of_not_exists_basis finrank_eq_zero_of_not_exists_basis - -theorem finrank_eq_zero_of_not_exists_basis_finite - (h : ¬∃ (s : Set V) (_ : Basis.{v} (s : Set V) K V), s.Finite) : finrank K V = 0 := - finrank_eq_zero_of_basis_imp_not_finite fun s b hs => h ⟨s, b, hs⟩ -#align finrank_eq_zero_of_not_exists_basis_finite finrank_eq_zero_of_not_exists_basis_finite - -theorem finrank_eq_zero_of_not_exists_basis_finset (h : ¬∃ s : Finset V, Nonempty (Basis s K V)) : - finrank K V = 0 := - finrank_eq_zero_of_basis_imp_false fun s b => h ⟨s, ⟨b⟩⟩ -#align finrank_eq_zero_of_not_exists_basis_finset finrank_eq_zero_of_not_exists_basis_finset - -end ZeroRank - -namespace LinearEquiv - -open FiniteDimensional - -variable [Ring K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂] [Module K V₂] - -variable {R M M₂ : Type*} [Ring R] [AddCommGroup M] [AddCommGroup M₂] - -variable [Module R M] [Module R M₂] - -/-- The dimension of a finite dimensional space is preserved under linear equivalence. -/ -theorem finrank_eq (f : M ≃ₗ[R] M₂) : finrank R M = finrank R M₂ := by - unfold finrank - rw [← Cardinal.toNat_lift, f.lift_rank_eq, Cardinal.toNat_lift] -#align linear_equiv.finrank_eq LinearEquiv.finrank_eq - -/-- Pushforwards of finite-dimensional submodules along a `LinearEquiv` have the same finrank. -/ -theorem finrank_map_eq (f : M ≃ₗ[R] M₂) (p : Submodule R M) : - finrank R (p.map (f : M →ₗ[R] M₂)) = finrank R p := - (f.submoduleMap p).finrank_eq.symm -#align linear_equiv.finrank_map_eq LinearEquiv.finrank_map_eq - -end LinearEquiv - -namespace LinearMap - -open FiniteDimensional - -section Ring - -variable [Ring K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂] [Module K V₂] - -/-- The dimensions of the domain and range of an injective linear map are equal. -/ -theorem finrank_range_of_inj {f : V →ₗ[K] V₂} (hf : Function.Injective f) : - finrank K (LinearMap.range f) = finrank K V := by rw [(LinearEquiv.ofInjective f hf).finrank_eq] -#align linear_map.finrank_range_of_inj LinearMap.finrank_range_of_inj - -end Ring - -end LinearMap - -open Module FiniteDimensional - -section - -variable [Ring K] [AddCommGroup V] [Module K V] - -variable (K V) - -@[simp] -theorem finrank_bot [Nontrivial K] : finrank K (⊥ : Submodule K V) = 0 := - finrank_eq_of_rank_eq (rank_bot _ _) -#align finrank_bot finrank_bot - -@[simp] -theorem finrank_top : finrank K (⊤ : Submodule K V) = finrank K V := by - unfold finrank - simp [rank_top] -#align finrank_top finrank_top - -end - -namespace Submodule - -section Ring - -variable [Ring K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂] [Module K V₂] - -theorem lt_of_le_of_finrank_lt_finrank {s t : Submodule K V} (le : s ≤ t) - (lt : finrank K s < finrank K t) : s < t := - lt_of_le_of_ne le fun h => ne_of_lt lt (by rw [h]) -#align submodule.lt_of_le_of_finrank_lt_finrank Submodule.lt_of_le_of_finrank_lt_finrank - -theorem lt_top_of_finrank_lt_finrank {s : Submodule K V} (lt : finrank K s < finrank K V) : - s < ⊤ := by - rw [← finrank_top K V] at lt - exact lt_of_le_of_finrank_lt_finrank le_top lt -#align submodule.lt_top_of_finrank_lt_finrank Submodule.lt_top_of_finrank_lt_finrank - -end Ring - -end Submodule - -section Span - -open Submodule - -section DivisionRing - -variable [DivisionRing K] [AddCommGroup V] [Module K V] - -variable (K) - -/-- The rank of a set of vectors as a natural number. -/ -protected noncomputable def Set.finrank (s : Set V) : ℕ := - finrank K (span K s) -#align set.finrank Set.finrank - -variable {K} - -theorem finrank_span_le_card (s : Set V) [Fintype s] : finrank K (span K s) ≤ s.toFinset.card := - finrank_le_of_rank_le (by simpa using rank_span_le (K := K) s) -#align finrank_span_le_card finrank_span_le_card - -theorem finrank_span_finset_le_card (s : Finset V) : (s : Set V).finrank K ≤ s.card := - calc - (s : Set V).finrank K ≤ (s : Set V).toFinset.card := finrank_span_le_card (V := V) s - _ = s.card := by simp -#align finrank_span_finset_le_card finrank_span_finset_le_card - -theorem finrank_range_le_card {ι : Type*} [Fintype ι] {b : ι → V} : - (Set.range b).finrank K ≤ Fintype.card ι := by - classical - refine (finrank_span_le_card _).trans ?_ - rw [Set.toFinset_range] - exact Finset.card_image_le -#align finrank_range_le_card finrank_range_le_card - -theorem finrank_span_eq_card {ι : Type*} [Fintype ι] {b : ι → V} (hb : LinearIndependent K b) : - finrank K (span K (Set.range b)) = Fintype.card ι := - finrank_eq_of_rank_eq - (by - have : Module.rank K (span K (Set.range b)) = #(Set.range b) := rank_span hb - rwa [← lift_inj, mk_range_eq_of_injective hb.injective, Cardinal.mk_fintype, lift_natCast, - lift_eq_nat_iff] at this) -#align finrank_span_eq_card finrank_span_eq_card - -theorem finrank_span_set_eq_card (s : Set V) [Fintype s] (hs : LinearIndependent K ((↑) : s → V)) : - finrank K (span K s) = s.toFinset.card := - finrank_eq_of_rank_eq - (by - have : Module.rank K (span K s) = #s := rank_span_set hs - rwa [Cardinal.mk_fintype, ← Set.toFinset_card] at this) -#align finrank_span_set_eq_card finrank_span_set_eq_card - -theorem finrank_span_finset_eq_card (s : Finset V) (hs : LinearIndependent K ((↑) : s → V)) : - finrank K (span K (s : Set V)) = s.card := by - convert finrank_span_set_eq_card (s : Set V) hs - ext - simp -#align finrank_span_finset_eq_card finrank_span_finset_eq_card - -theorem span_lt_of_subset_of_card_lt_finrank {s : Set V} [Fintype s] {t : Submodule K V} - (subset : s ⊆ t) (card_lt : s.toFinset.card < finrank K t) : span K s < t := - lt_of_le_of_finrank_lt_finrank (span_le.mpr subset) - (lt_of_le_of_lt (finrank_span_le_card _) card_lt) -#align span_lt_of_subset_of_card_lt_finrank span_lt_of_subset_of_card_lt_finrank - -theorem span_lt_top_of_card_lt_finrank {s : Set V} [Fintype s] - (card_lt : s.toFinset.card < finrank K V) : span K s < ⊤ := - lt_top_of_finrank_lt_finrank (lt_of_le_of_lt (finrank_span_le_card _) card_lt) -#align span_lt_top_of_card_lt_finrank span_lt_top_of_card_lt_finrank - -/-- Given a family of `n` linearly independent vectors in a finite-dimensional space of -dimension `> n`, one may extend the family by another vector while retaining linear independence. -/ -theorem exists_linearIndependent_snoc_of_lt_finrank {n : ℕ} {v : Fin n → V} - (hv : LinearIndependent K v) (h : n < finrank K V) : - ∃ (x : V), LinearIndependent K (Fin.snoc v x) := - exists_linearIndependent_snoc_of_lt_rank hv (lt_rank_of_lt_finrank h) - -/-- Given a family of `n` linearly independent vectors in a finite-dimensional space of -dimension `> n`, one may extend the family by another vector while retaining linear independence. -/ -theorem exists_linearIndependent_cons_of_lt_finrank {n : ℕ} {v : Fin n → V} - (hv : LinearIndependent K v) (h : n < finrank K V) : - ∃ (x : V), LinearIndependent K (Fin.cons x v) := - exists_linearIndependent_cons_of_lt_rank hv (lt_rank_of_lt_finrank h) - -/-- Given a nonzero vector in a finite-dimensional space of dimension `> 1`, one may find another -vector linearly independent of the first one. -/ -theorem exists_linearIndependent_pair_of_one_lt_finrank - (h : 1 < finrank K V) {x : V} (hx : x ≠ 0) : - ∃ y, LinearIndependent K ![x, y] := - exists_linearIndependent_pair_of_one_lt_rank (one_lt_rank_of_one_lt_finrank h) hx - -end DivisionRing - -end Span - -section Basis - -section DivisionRing - -variable [DivisionRing K] [AddCommGroup V] [Module K V] - -theorem linearIndependent_of_top_le_span_of_card_eq_finrank {ι : Type*} [Fintype ι] {b : ι → V} - (spans : ⊤ ≤ span K (Set.range b)) (card_eq : Fintype.card ι = finrank K V) : - LinearIndependent K b := - linearIndependent_iff'.mpr fun s g dependent i i_mem_s => by - classical - by_contra gx_ne_zero - -- We'll derive a contradiction by showing `b '' (univ \ {i})` of cardinality `n - 1` - -- spans a vector space of dimension `n`. - refine' not_le_of_gt (span_lt_top_of_card_lt_finrank - (show (b '' (Set.univ \ {i})).toFinset.card < finrank K V from _)) _ - · calc - (b '' (Set.univ \ {i})).toFinset.card = ((Set.univ \ {i}).toFinset.image b).card := by - rw [Set.toFinset_card, Fintype.card_ofFinset] - _ ≤ (Set.univ \ {i}).toFinset.card := Finset.card_image_le - _ = (Finset.univ.erase i).card := (congr_arg Finset.card (Finset.ext (by simp [and_comm]))) - _ < Finset.univ.card := (Finset.card_erase_lt_of_mem (Finset.mem_univ i)) - _ = finrank K V := card_eq - -- We already have that `b '' univ` spans the whole space, - -- so we only need to show that the span of `b '' (univ \ {i})` contains each `b j`. - refine' spans.trans (span_le.mpr _) - rintro _ ⟨j, rfl, rfl⟩ - -- The case that `j ≠ i` is easy because `b j ∈ b '' (univ \ {i})`. - by_cases j_eq : j = i - swap - · refine' subset_span ⟨j, (Set.mem_diff _).mpr ⟨Set.mem_univ _, _⟩, rfl⟩ - exact mt Set.mem_singleton_iff.mp j_eq - -- To show `b i ∈ span (b '' (univ \ {i}))`, we use that it's a weighted sum - -- of the other `b j`s. - rw [j_eq, SetLike.mem_coe, show b i = -((g i)⁻¹ • (s.erase i).sum fun j => g j • b j) from _] - · refine' neg_mem (smul_mem _ _ (sum_mem fun k hk => _)) - obtain ⟨k_ne_i, _⟩ := Finset.mem_erase.mp hk - refine' smul_mem _ _ (subset_span ⟨k, _, rfl⟩) - simp_all only [Set.mem_univ, Set.mem_diff, Set.mem_singleton_iff, and_self, not_false_eq_true] - -- To show `b i` is a weighted sum of the other `b j`s, we'll rewrite this sum - -- to have the form of the assumption `dependent`. - apply eq_neg_of_add_eq_zero_left - calc - (b i + (g i)⁻¹ • (s.erase i).sum fun j => g j • b j) = - (g i)⁻¹ • (g i • b i + (s.erase i).sum fun j => g j • b j) := - by rw [smul_add, ← mul_smul, inv_mul_cancel gx_ne_zero, one_smul] - _ = (g i)⁻¹ • (0 : V) := (congr_arg _ ?_) - _ = 0 := smul_zero _ - -- And then it's just a bit of manipulation with finite sums. - rwa [← Finset.insert_erase i_mem_s, Finset.sum_insert (Finset.not_mem_erase _ _)] at dependent -#align linear_independent_of_top_le_span_of_card_eq_finrank linearIndependent_of_top_le_span_of_card_eq_finrank - -/-- A finite family of vectors is linearly independent if and only if -its cardinality equals the dimension of its span. -/ -theorem linearIndependent_iff_card_eq_finrank_span {ι : Type*} [Fintype ι] {b : ι → V} : - LinearIndependent K b ↔ Fintype.card ι = (Set.range b).finrank K := by - constructor - · intro h - exact (finrank_span_eq_card h).symm - · intro hc - let f := Submodule.subtype (span K (Set.range b)) - let b' : ι → span K (Set.range b) := fun i => - ⟨b i, mem_span.2 fun p hp => hp (Set.mem_range_self _)⟩ - have hs : ⊤ ≤ span K (Set.range b') := by - intro x - have h : span K (f '' Set.range b') = map f (span K (Set.range b')) := span_image f - have hf : f '' Set.range b' = Set.range b := by - ext x - simp [Set.mem_image, Set.mem_range] - rw [hf] at h - have hx : (x : V) ∈ span K (Set.range b) := x.property - conv at hx => - arg 2 - rw [h] - simpa [mem_map] using hx - have hi : LinearMap.ker f = ⊥ := ker_subtype _ - convert (linearIndependent_of_top_le_span_of_card_eq_finrank hs hc).map' _ hi -#align linear_independent_iff_card_eq_finrank_span linearIndependent_iff_card_eq_finrank_span - -theorem linearIndependent_iff_card_le_finrank_span {ι : Type*} [Fintype ι] {b : ι → V} : - LinearIndependent K b ↔ Fintype.card ι ≤ (Set.range b).finrank K := by - rw [linearIndependent_iff_card_eq_finrank_span, finrank_range_le_card.le_iff_eq] -#align linear_independent_iff_card_le_finrank_span linearIndependent_iff_card_le_finrank_span - -/-- A family of `finrank K V` vectors forms a basis if they span the whole space. -/ -noncomputable def basisOfTopLeSpanOfCardEqFinrank {ι : Type*} [Fintype ι] (b : ι → V) - (le_span : ⊤ ≤ span K (Set.range b)) (card_eq : Fintype.card ι = finrank K V) : Basis ι K V := - Basis.mk (linearIndependent_of_top_le_span_of_card_eq_finrank le_span card_eq) le_span -#align basis_of_top_le_span_of_card_eq_finrank basisOfTopLeSpanOfCardEqFinrank - -@[simp] -theorem coe_basisOfTopLeSpanOfCardEqFinrank {ι : Type*} [Fintype ι] (b : ι → V) - (le_span : ⊤ ≤ span K (Set.range b)) (card_eq : Fintype.card ι = finrank K V) : - ⇑(basisOfTopLeSpanOfCardEqFinrank b le_span card_eq) = b := - Basis.coe_mk _ _ -#align coe_basis_of_top_le_span_of_card_eq_finrank coe_basisOfTopLeSpanOfCardEqFinrank - -/-- A finset of `finrank K V` vectors forms a basis if they span the whole space. -/ -@[simps! repr_apply] -noncomputable def finsetBasisOfTopLeSpanOfCardEqFinrank {s : Finset V} - (le_span : ⊤ ≤ span K (s : Set V)) (card_eq : s.card = finrank K V) : Basis {x // x ∈ s} K V := - basisOfTopLeSpanOfCardEqFinrank ((↑) : ↥(s : Set V) → V) - ((@Subtype.range_coe_subtype _ fun x => x ∈ s).symm ▸ le_span) - (_root_.trans (Fintype.card_coe _) card_eq) -#align finset_basis_of_top_le_span_of_card_eq_finrank finsetBasisOfTopLeSpanOfCardEqFinrank - -/-- A set of `finrank K V` vectors forms a basis if they span the whole space. -/ -@[simps! repr_apply] -noncomputable def setBasisOfTopLeSpanOfCardEqFinrank {s : Set V} [Fintype s] - (le_span : ⊤ ≤ span K s) (card_eq : s.toFinset.card = finrank K V) : Basis s K V := - basisOfTopLeSpanOfCardEqFinrank ((↑) : s → V) ((@Subtype.range_coe_subtype _ s).symm ▸ le_span) - (_root_.trans s.toFinset_card.symm card_eq) -#align set_basis_of_top_le_span_of_card_eq_finrank setBasisOfTopLeSpanOfCardEqFinrank - -end DivisionRing - -end Basis - -/-! -We now give characterisations of `finrank K V = 1` and `finrank K V ≤ 1`. --/ - - -section finrank_eq_one - -variable [Ring K] [AddCommGroup V] [Module K V] - -variable [NoZeroSMulDivisors K V] [StrongRankCondition K] - -/-- If there is a nonzero vector and every other vector is a multiple of it, -then the module has dimension one. -/ -theorem finrank_eq_one (v : V) (n : v ≠ 0) (h : ∀ w : V, ∃ c : K, c • v = w) : finrank K V = 1 := by - haveI := nontrivial_of_invariantBasisNumber K - obtain ⟨b⟩ := (Basis.basis_singleton_iff.{u} PUnit).mpr ⟨v, n, h⟩ - rw [finrank_eq_card_basis b, Fintype.card_punit] -#align finrank_eq_one finrank_eq_one - -/-- If every vector is a multiple of some `v : V`, then `V` has dimension at most one. --/ -theorem finrank_le_one (v : V) (h : ∀ w : V, ∃ c : K, c • v = w) : finrank K V ≤ 1 := by - haveI := nontrivial_of_invariantBasisNumber K - rcases eq_or_ne v 0 with (rfl | hn) - · haveI := - subsingleton_of_forall_eq (0 : V) fun w => by - obtain ⟨c, rfl⟩ := h w - simp - rw [finrank_zero_of_subsingleton] - exact zero_le_one - · exact (finrank_eq_one v hn h).le -#align finrank_le_one finrank_le_one - -end finrank_eq_one - -section SubalgebraRank - -open Module - -variable {F E : Type*} [CommRing F] [Ring E] [Algebra F E] - -@[simp] -theorem Subalgebra.rank_toSubmodule (S : Subalgebra F E) : - Module.rank F (Subalgebra.toSubmodule S) = Module.rank F S := - rfl -#align subalgebra.rank_to_submodule Subalgebra.rank_toSubmodule - -@[simp] -theorem Subalgebra.finrank_toSubmodule (S : Subalgebra F E) : - finrank F (Subalgebra.toSubmodule S) = finrank F S := - rfl -#align subalgebra.finrank_to_submodule Subalgebra.finrank_toSubmodule - -theorem subalgebra_top_rank_eq_submodule_top_rank : - Module.rank F (⊤ : Subalgebra F E) = Module.rank F (⊤ : Submodule F E) := by - rw [← Algebra.top_toSubmodule] - rfl -#align subalgebra_top_rank_eq_submodule_top_rank subalgebra_top_rank_eq_submodule_top_rank - -theorem subalgebra_top_finrank_eq_submodule_top_finrank : - finrank F (⊤ : Subalgebra F E) = finrank F (⊤ : Submodule F E) := by - rw [← Algebra.top_toSubmodule] - rfl -#align subalgebra_top_finrank_eq_submodule_top_finrank subalgebra_top_finrank_eq_submodule_top_finrank - -theorem Subalgebra.rank_top : Module.rank F (⊤ : Subalgebra F E) = Module.rank F E := by - rw [subalgebra_top_rank_eq_submodule_top_rank] - exact _root_.rank_top F E -#align subalgebra.rank_top Subalgebra.rank_top - -section - -variable [StrongRankCondition F] [NoZeroSMulDivisors F E] [Nontrivial E] - -@[simp] -theorem Subalgebra.rank_bot : Module.rank F (⊥ : Subalgebra F E) = 1 := - (Subalgebra.toSubmoduleEquiv (⊥ : Subalgebra F E)).symm.rank_eq.trans <| by - rw [Algebra.toSubmodule_bot, one_eq_span, rank_span_set, mk_singleton _] - letI := Module.nontrivial F E - exact linearIndependent_singleton one_ne_zero -#align subalgebra.rank_bot Subalgebra.rank_bot - -@[simp] -theorem Subalgebra.finrank_bot : finrank F (⊥ : Subalgebra F E) = 1 := - finrank_eq_of_rank_eq (by simp) -#align subalgebra.finrank_bot Subalgebra.finrank_bot - -end - -end SubalgebraRank diff --git a/Mathlib/LinearAlgebra/FreeAlgebra.lean b/Mathlib/LinearAlgebra/FreeAlgebra.lean index 70e3130a1365c..bb6cacfbb5f11 100644 --- a/Mathlib/LinearAlgebra/FreeAlgebra.lean +++ b/Mathlib/LinearAlgebra/FreeAlgebra.lean @@ -5,7 +5,6 @@ Authors: Eric Wieser -/ import Mathlib.LinearAlgebra.Basis import Mathlib.Algebra.FreeAlgebra -import Mathlib.LinearAlgebra.Dimension import Mathlib.LinearAlgebra.FinsuppVectorSpace import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean index 7426961e297b8..6fbd8071c92d4 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean @@ -3,9 +3,8 @@ Copyright (c) 2021 Riccardo Brasca. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ -import Mathlib.LinearAlgebra.Dimension -import Mathlib.LinearAlgebra.FreeModule.Basic import Mathlib.RingTheory.Finiteness +import Mathlib.LinearAlgebra.FreeModule.Basic #align_import linear_algebra.free_module.finite.basic from "leanprover-community/mathlib"@"59628387770d82eb6f6dd7b7107308aa2509ec95" @@ -31,13 +30,6 @@ section Ring variable [Ring R] [AddCommGroup M] [Module R M] [Module.Free R M] -/-- If a free module is finite, then any arbitrary basis is finite. -/ -lemma finite_basis {R M} [Ring R] [Nontrivial R] [AddCommGroup M] [Module R M] - {ι} [Module.Finite R M] (b : Basis ι R M) : - _root_.Finite ι := - let ⟨s, hs⟩ := ‹Module.Finite R M› - basis_finite_of_finite_spans (↑s) s.finite_toSet hs b - /-- If a free module is finite, then the arbitrary basis is finite. -/ noncomputable instance ChooseBasisIndex.fintype [Module.Finite R M] : Fintype (Module.Free.ChooseBasisIndex R M) := by @@ -46,7 +38,7 @@ noncomputable instance ChooseBasisIndex.fintype [Module.Finite R M] : · have := Module.subsingleton R M rw [ChooseBasisIndex] infer_instance - · exact finite_basis (chooseBasis _ _) + · exact Module.Finite.finite_basis (chooseBasis _ _) #align module.free.choose_basis_index.fintype Module.Free.ChooseBasisIndex.fintype end Ring diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean index 01c6107deccad..e4d7267b05ff3 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean @@ -3,9 +3,7 @@ Copyright (c) 2021 Riccardo Brasca. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ -import Mathlib.LinearAlgebra.Finrank -import Mathlib.LinearAlgebra.FreeModule.Finite.Rank -import Mathlib.LinearAlgebra.Matrix.ToLin +import Mathlib.LinearAlgebra.Dimension.LinearMap #align_import linear_algebra.free_module.finite.matrix from "leanprover-community/mathlib"@"b1c23399f01266afe392a0d8f71f599a0dad4f7b" diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean deleted file mode 100644 index 92f9259fcb02e..0000000000000 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Rank.lean +++ /dev/null @@ -1,592 +0,0 @@ -/- -Copyright (c) 2021 Riccardo Brasca. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Riccardo Brasca --/ -import Mathlib.LinearAlgebra.Finrank -import Mathlib.LinearAlgebra.FreeModule.Rank -import Mathlib.LinearAlgebra.FreeModule.Finite.Basic - -#align_import linear_algebra.free_module.finite.rank from "leanprover-community/mathlib"@"e95e4f92c8f8da3c7f693c3ec948bcf9b6683f51" - -/-! - -# Rank of finite free modules - -This is a basic API for the rank of finite free modules. - --/ - - ---TODO: many results from `LinearAlgebra/FiniteDimensional` should be moved here. ---TODO: This file contains many misplaced lemmas and should be reorganized. -universe u v w v' - -variable (R : Type u) (M : Type v) (N : Type w) - -open TensorProduct DirectSum BigOperators Cardinal - -open Cardinal FiniteDimensional Fintype - -namespace FiniteDimensional - -open Module.Free - -section Ring - -variable [Ring R] - -variable [AddCommGroup M] [Module R M] - -variable [AddCommGroup N] [Module R N] - -@[simp] -theorem Submodule.finrank_map_subtype_eq (p : Submodule R M) (q : Submodule R p) : - finrank R (q.map p.subtype) = finrank R q := - (Submodule.equivSubtypeMap p q).symm.finrank_eq -#align finite_dimensional.submodule.finrank_map_subtype_eq FiniteDimensional.Submodule.finrank_map_subtype_eq - -@[simp] -theorem finrank_ulift : finrank R (ULift M) = finrank R M := by - simp_rw [finrank, rank_ulift, toNat_lift] - -end Ring - -section RingFinite - -variable [Ring R] [StrongRankCondition R] - -variable [AddCommGroup M] [Module R M] [Module.Finite R M] - -variable [AddCommGroup N] [Module R N] [Module.Finite R N] - -/-- The rank of a finite module is finite. -/ -theorem rank_lt_aleph0 : Module.rank R M < ℵ₀ := by - simp only [Module.rank_def] - letI := nontrivial_of_invariantBasisNumber R - -- porting note: can't use `‹_›` as that pulls the unused `N` into the context - obtain ⟨S, hS⟩ := Module.finite_def.mp ‹Module.Finite R M› - refine' (ciSup_le' fun i => _).trans_lt (nat_lt_aleph0 S.card) - exact linearIndependent_le_span_finset _ i.prop S hS -#align finite_dimensional.rank_lt_aleph_0 FiniteDimensional.rank_lt_aleph0 - -/-- If `M` is finite, `finrank M = rank M`. -/ -@[simp] -theorem finrank_eq_rank : ↑(finrank R M) = Module.rank R M := by - rw [finrank, cast_toNat_of_lt_aleph0 (rank_lt_aleph0 R M)] -#align finite_dimensional.finrank_eq_rank FiniteDimensional.finrank_eq_rank - -end RingFinite - -section RingFree - -variable [Ring R] [StrongRankCondition R] - -variable [AddCommGroup M] [Module R M] [Module.Free R M] [Module.Finite R M] - -variable [AddCommGroup N] [Module R N] [Module.Free R N] [Module.Finite R N] - -/-- The finrank of a free module `M` over `R` is the cardinality of `ChooseBasisIndex R M`. -/ -theorem finrank_eq_card_chooseBasisIndex : - finrank R M = card (ChooseBasisIndex R M) := by - simp [finrank, rank_eq_card_chooseBasisIndex] -#align finite_dimensional.finrank_eq_card_choose_basis_index FiniteDimensional.finrank_eq_card_chooseBasisIndex - -@[simp] -theorem finrank_finsupp {ι : Type v} [Fintype ι] : finrank R (ι →₀ M) = card ι * finrank R M := by - rw [finrank, finrank, rank_finsupp, ← mk_toNat_eq_card, toNat_mul, toNat_lift, toNat_lift] - -/-- The finrank of `(ι →₀ R)` is `Fintype.card ι`. -/ -@[simp] -theorem finrank_finsupp_self {ι : Type v} [Fintype ι] : finrank R (ι →₀ R) = card ι := by - rw [finrank, rank_finsupp_self, ← mk_toNat_eq_card, toNat_lift] -#align finite_dimensional.finrank_finsupp FiniteDimensional.finrank_finsupp_self - -/-- The finrank of `(ι → R)` is `Fintype.card ι`. -/ -theorem finrank_pi {ι : Type v} [Fintype ι] : finrank R (ι → R) = card ι := by - simp [finrank] -#align finite_dimensional.finrank_pi FiniteDimensional.finrank_pi - -/-- The finrank of the direct sum is the sum of the finranks. -/ -@[simp] -theorem finrank_directSum {ι : Type v} [Fintype ι] (M : ι → Type w) [∀ i : ι, AddCommGroup (M i)] - [∀ i : ι, Module R (M i)] [∀ i : ι, Module.Free R (M i)] [∀ i : ι, Module.Finite R (M i)] : - finrank R (⨁ i, M i) = ∑ i, finrank R (M i) := by - letI := nontrivial_of_invariantBasisNumber R - simp only [finrank, fun i => rank_eq_card_chooseBasisIndex R (M i), rank_directSum, ← mk_sigma, - mk_toNat_eq_card, card_sigma] -#align finite_dimensional.finrank_direct_sum FiniteDimensional.finrank_directSum - -/-- The finrank of `M × N` is `(finrank R M) + (finrank R N)`. -/ -@[simp] -theorem finrank_prod : finrank R (M × N) = finrank R M + finrank R N := by - simp [finrank, rank_lt_aleph0 R M, rank_lt_aleph0 R N] -#align finite_dimensional.finrank_prod FiniteDimensional.finrank_prod - ---TODO: this should follow from `LinearEquiv.finrank_eq`, that is over a field. -/-- The finrank of a finite product is the sum of the finranks. -/ -theorem finrank_pi_fintype {ι : Type v} [Fintype ι] {M : ι → Type w} [∀ i : ι, AddCommGroup (M i)] - [∀ i : ι, Module R (M i)] [∀ i : ι, Module.Free R (M i)] [∀ i : ι, Module.Finite R (M i)] : - finrank R (∀ i, M i) = ∑ i, finrank R (M i) := by - letI := nontrivial_of_invariantBasisNumber R - simp only [finrank, fun i => rank_eq_card_chooseBasisIndex R (M i), rank_pi, ← mk_sigma, - mk_toNat_eq_card, card_sigma] -#align finite_dimensional.finrank_pi_fintype FiniteDimensional.finrank_pi_fintype - -/-- If `m` and `n` are `Fintype`, the finrank of `m × n` matrices is - `(Fintype.card m) * (Fintype.card n)`. -/ -theorem finrank_matrix (m n : Type*) [Fintype m] [Fintype n] : - finrank R (Matrix m n R) = card m * card n := by simp [finrank] -#align finite_dimensional.finrank_matrix FiniteDimensional.finrank_matrix - -variable {R M N} - -/-- Two finite and free modules are isomorphic if they have the same (finite) rank. -/ -theorem nonempty_linearEquiv_of_finrank_eq (cond : finrank R M = finrank R N) : - Nonempty (M ≃ₗ[R] N) := - nonempty_linearEquiv_of_lift_rank_eq <| by simp only [← finrank_eq_rank, cond, lift_natCast] -#align finite_dimensional.nonempty_linear_equiv_of_finrank_eq FiniteDimensional.nonempty_linearEquiv_of_finrank_eq - -/-- Two finite and free modules are isomorphic if and only if they have the same (finite) rank. -/ -theorem nonempty_linearEquiv_iff_finrank_eq : Nonempty (M ≃ₗ[R] N) ↔ finrank R M = finrank R N := - ⟨fun ⟨h⟩ => h.finrank_eq, fun h => nonempty_linearEquiv_of_finrank_eq h⟩ -#align finite_dimensional.nonempty_linear_equiv_iff_finrank_eq FiniteDimensional.nonempty_linearEquiv_iff_finrank_eq - -variable (M N) - -/-- Two finite and free modules are isomorphic if they have the same (finite) rank. -/ -noncomputable def _root_.LinearEquiv.ofFinrankEq (cond : finrank R M = finrank R N) : M ≃ₗ[R] N := - Classical.choice <| nonempty_linearEquiv_of_finrank_eq cond -#align linear_equiv.of_finrank_eq LinearEquiv.ofFinrankEq - -end RingFree - -section CommRing - -variable [CommRing R] [StrongRankCondition R] - -variable [AddCommGroup M] [Module R M] [Module.Free R M] [Module.Finite R M] - -variable [AddCommGroup N] [Module R N] [Module.Free R N] [Module.Finite R N] - -/-- The finrank of `M ⊗[R] N` is `(finrank R M) * (finrank R N)`. -/ -@[simp] -theorem finrank_tensorProduct (M : Type v) (N : Type w) [AddCommGroup M] [Module R M] - [Module.Free R M] [AddCommGroup N] [Module R N] [Module.Free R N] : - finrank R (M ⊗[R] N) = finrank R M * finrank R N := by simp [finrank] -#align finite_dimensional.finrank_tensor_product FiniteDimensional.finrank_tensorProduct - -end CommRing - -end FiniteDimensional - -section - -open FiniteDimensional - -variable {R M N} - -variable [Ring R] [StrongRankCondition R] - -variable [AddCommGroup M] [Module R M] - -variable [AddCommGroup N] [Module R N] - -theorem LinearMap.finrank_le_finrank_of_injective [Module.Finite R N] {f : M →ₗ[R] N} - (hf : Function.Injective f) : finrank R M ≤ finrank R N := - finrank_le_finrank_of_rank_le_rank (LinearMap.lift_rank_le_of_injective _ hf) (rank_lt_aleph0 _ _) -#align linear_map.finrank_le_finrank_of_injective LinearMap.finrank_le_finrank_of_injective - -theorem LinearMap.finrank_range_le [Module.Finite R M] (f : M →ₗ[R] N) : - finrank R (LinearMap.range f) ≤ finrank R M := - finrank_le_finrank_of_rank_le_rank (lift_rank_range_le f) (rank_lt_aleph0 _ _) -#align linear_map.finrank_range_le LinearMap.finrank_range_le - -/-- The dimension of a submodule is bounded by the dimension of the ambient space. -/ -theorem Submodule.finrank_le [Module.Finite R M] (s : Submodule R M) : - finrank R s ≤ finrank R M := by - simpa only [Cardinal.toNat_lift] using - toNat_le_of_le_of_lt_aleph0 (rank_lt_aleph0 _ _) (rank_submodule_le s) -#align submodule.finrank_le Submodule.finrank_le - -/-- The dimension of a quotient is bounded by the dimension of the ambient space. -/ -theorem Submodule.finrank_quotient_le [Module.Finite R M] (s : Submodule R M) : - finrank R (M ⧸ s) ≤ finrank R M := by - simpa only [Cardinal.toNat_lift] using - toNat_le_of_le_of_lt_aleph0 (rank_lt_aleph0 _ _) - ((Submodule.mkQ s).rank_le_of_surjective (surjective_quot_mk _)) -#align submodule.finrank_quotient_le Submodule.finrank_quotient_le - -/-- Pushforwards of finite submodules have a smaller finrank. -/ -theorem Submodule.finrank_map_le (f : M →ₗ[R] N) (p : Submodule R M) [Module.Finite R p] : - finrank R (p.map f) ≤ finrank R p := - finrank_le_finrank_of_rank_le_rank (lift_rank_map_le _ _) (rank_lt_aleph0 _ _) -#align submodule.finrank_map_le Submodule.finrank_map_le - -theorem Submodule.finrank_le_finrank_of_le {s t : Submodule R M} [Module.Finite R t] (hst : s ≤ t) : - finrank R s ≤ finrank R t := - calc - finrank R s = finrank R (s.comap t.subtype) := - (Submodule.comapSubtypeEquivOfLe hst).finrank_eq.symm - _ ≤ finrank R t := Submodule.finrank_le _ -#align submodule.finrank_le_finrank_of_le Submodule.finrank_le_finrank_of_le - -end - - -open Cardinal Submodule Module Function FiniteDimensional - -attribute [local instance] nontrivial_of_invariantBasisNumber - -variable {R} {V : Type v} - -open IsNoetherian - -section DivisionRing - -variable [AddCommGroup V] {V₂ : Type v'} [AddCommGroup V₂] -variable [Ring R] [StrongRankCondition R] [Module R V] [Module.Free R V] - -/-- See `FiniteDimensional.rank_lt_aleph0` for the inverse direction without `Module.Free R V`. -/ -lemma Module.rank_lt_alpeh0_iff : - Module.rank R V < ℵ₀ ↔ Module.Finite R V := by - rw [Free.rank_eq_card_chooseBasisIndex, mk_lt_aleph0_iff] - exact ⟨fun h ↦ Finite.of_basis (Free.chooseBasis R V), - fun I ↦ Finite.of_fintype (Free.ChooseBasisIndex R V)⟩ - -theorem FiniteDimensional.finrank_of_not_finite - (h : ¬Module.Finite R V) : - finrank R V = 0 := - dif_neg (rank_lt_alpeh0_iff.not.mpr h) - -theorem Module.finite_of_finrank_pos (h : 0 < finrank R V) : - Module.Finite R V := by - contrapose h - simp [finrank_of_not_finite h] - -theorem Module.finite_of_finrank_eq_succ {n : ℕ} - (hn : finrank R V = n.succ) : Module.Finite R V := - Module.finite_of_finrank_pos <| by rw [hn]; exact n.succ_pos - -theorem Module.finite_iff_of_rank_eq_nsmul {W} [AddCommGroup W] - [Module R W] [Module.Free R W] {n : ℕ} (hn : n ≠ 0) - (hVW : Module.rank R V = n • Module.rank R W) : - Module.Finite R V ↔ Module.Finite R W := by - simp only [← rank_lt_alpeh0_iff, hVW, nsmul_lt_aleph0_iff_of_ne_zero hn] - -/-- If a free module is of finite rank, then the cardinality of any basis is equal to its -`finrank`. -/ -theorem Module.mk_finrank_eq_card_basis [Module.Finite R V] - {ι : Type w} (h : Basis ι R V) : (finrank R V : Cardinal.{w}) = #ι := by - cases @nonempty_fintype _ (Free.finite_basis h) - rw [Cardinal.mk_fintype, finrank_eq_card_basis h] - -/-- Given a basis of a ring over itself indexed by a type `ι`, then `ι` is `Unique`. -/ -noncomputable def Basis.unique {ι : Type*} (b : Basis ι R R) : Unique ι := by - have A : Cardinal.mk ι = ↑(FiniteDimensional.finrank R R) := - (Module.mk_finrank_eq_card_basis b).symm - -- porting note: replace `algebraMap.coe_one` with `Nat.cast_one` - simp only [Cardinal.eq_one_iff_unique, FiniteDimensional.finrank_self, Nat.cast_one] at A - exact Nonempty.some ((unique_iff_subsingleton_and_nonempty _).2 A) -#align basis.unique Basis.unique - -namespace FiniteDimensional -variable (R V) - -/-- A finite rank free module has a basis indexed by `Fin (finrank R V)`. -/ -noncomputable def finBasis [Module.Finite R V] : - Basis (Fin (finrank R V)) R V := - (Free.chooseBasis R V).reindex (Fintype.equivFinOfCardEq - (finrank_eq_card_chooseBasisIndex R V).symm) -#align finite_dimensional.fin_basis FiniteDimensional.finBasis - -/-- A rank `n` free module has a basis indexed by `Fin n`. -/ -noncomputable def finBasisOfFinrankEq [Module.Finite R V] - {n : ℕ} (hn : finrank R V = n) : - Basis (Fin n) R V := - (finBasis R V).reindex (Fin.castIso hn).toEquiv -#align finite_dimensional.fin_basis_of_finrank_eq FiniteDimensional.finBasisOfFinrankEq - -variable {R V} - -/-- A free module with rank 1 has a basis with one element. -/ -noncomputable def basisUnique (ι : Type*) [Unique ι] - (h : finrank R V = 1) : - Basis ι R V := - haveI : Module.Finite R V := - Module.finite_of_finrank_pos (_root_.zero_lt_one.trans_le h.symm.le) - (finBasisOfFinrankEq R V h).reindex (Equiv.equivOfUnique _ _) -#align finite_dimensional.basis_unique FiniteDimensional.basisUnique - -@[simp] -theorem basisUnique_repr_eq_zero_iff {ι : Type*} [Unique ι] - {h : finrank R V = 1} {v : V} {i : ι} : - (basisUnique ι h).repr v i = 0 ↔ v = 0 := - ⟨fun hv => - (basisUnique ι h).repr.map_eq_zero_iff.mp (Finsupp.ext fun j => Subsingleton.elim i j ▸ hv), - fun hv => by rw [hv, LinearEquiv.map_zero, Finsupp.zero_apply]⟩ -#align finite_dimensional.basis_unique.repr_eq_zero_iff FiniteDimensional.basisUnique_repr_eq_zero_iff - -end FiniteDimensional - -namespace LinearIndependent - -theorem cardinal_mk_le_finrank [Module.Finite R V] - {ι : Type w} {b : ι → V} (h : LinearIndependent R b) : #ι ≤ finrank R V := by - rw [← lift_le.{max v w}] - simpa only [← finrank_eq_rank, lift_natCast, lift_le_nat_iff] using h.cardinal_lift_le_rank -#align finite_dimensional.cardinal_mk_le_finrank_of_linear_independent LinearIndependent.cardinal_mk_le_finrank - -theorem fintype_card_le_finrank [Module.Finite R V] - {ι : Type*} [Fintype ι] {b : ι → V} (h : LinearIndependent R b) : - Fintype.card ι ≤ finrank R V := by - simpa using h.cardinal_mk_le_finrank -#align finite_dimensional.fintype_card_le_finrank_of_linear_independent LinearIndependent.fintype_card_le_finrank - -theorem finset_card_le_finrank [Module.Finite R V] - {b : Finset V} (h : LinearIndependent R (fun x => x : b → V)) : - b.card ≤ finrank R V := by - rw [← Fintype.card_coe] - exact h.fintype_card_le_finrank -#align finite_dimensional.finset_card_le_finrank_of_linear_independent LinearIndependent.finset_card_le_finrank - -theorem lt_aleph0_of_finite {ι : Type w} - [Module.Finite R V] {v : ι → V} (h : LinearIndependent R v) : #ι < ℵ₀ := by - apply Cardinal.lift_lt.1 - apply lt_of_le_of_lt - apply h.cardinal_lift_le_rank - rw [← finrank_eq_rank, Cardinal.lift_aleph0, Cardinal.lift_natCast] - apply Cardinal.nat_lt_aleph0 - -theorem finite [Module.Finite R V] {ι : Type*} {f : ι → V} - (h : LinearIndependent R f) : Finite ι := - Cardinal.lt_aleph0_iff_finite.1 <| h.lt_aleph0_of_finite - -theorem setFinite [Module.Finite R V] {b : Set V} - (h : LinearIndependent R fun x : b => (x : V)) : b.Finite := - Cardinal.lt_aleph0_iff_set_finite.mp h.lt_aleph0_of_finite -#align linear_independent.finite LinearIndependent.setFinite - -end LinearIndependent - -@[deprecated] -alias cardinal_mk_le_finrank_of_linearIndependent := LinearIndependent.cardinal_mk_le_finrank -@[deprecated] -alias fintype_card_le_finrank_of_linearIndependent := LinearIndependent.fintype_card_le_finrank -@[deprecated] -alias finset_card_le_finrank_of_linearIndependent := LinearIndependent.finset_card_le_finrank -@[deprecated] -alias Module.Finite.lt_aleph0_of_linearIndependent := LinearIndependent.lt_aleph0_of_finite - -theorem Module.Finite.not_linearIndependent_of_infinite {ι : Type*} [Infinite ι] [Module.Finite R V] - (v : ι → V) : ¬LinearIndependent R v := mt LinearIndependent.finite <| @not_finite _ _ -#align finite_dimensional.not_linear_independent_of_infinite Module.Finite.not_linearIndependent_of_infinite - -/-- A finite rank torsion-free module has positive `finrank` iff it has a nonzero element. -/ -theorem FiniteDimensional.finrank_pos_iff_exists_ne_zero - [Module.Finite R V] [NoZeroSMulDivisors R V] : - 0 < finrank R V ↔ ∃ x : V, x ≠ 0 := - Iff.trans - (by - rw [← finrank_eq_rank] - norm_cast) - (@rank_pos_iff_exists_ne_zero R V _ _ _ _ _) -#align finite_dimensional.finrank_pos_iff_exists_ne_zero FiniteDimensional.finrank_pos_iff_exists_ne_zero - -/-- An `R`-finite torsion-free module has positive `finrank` iff it is nontrivial. -/ -theorem FiniteDimensional.finrank_pos_iff [Module.Finite R V] [NoZeroSMulDivisors R V] : - 0 < finrank R V ↔ Nontrivial V := - Iff.trans - (by rw [← finrank_eq_rank]; norm_cast) - (rank_pos_iff_nontrivial (R := R)) -#align finite_dimensional.finrank_pos_iff FiniteDimensional.finrank_pos_iff - -/-- A nontrivial finite dimensional space has positive `finrank`. -/ -theorem FiniteDimensional.finrank_pos - [Module.Finite R V] [NoZeroSMulDivisors R V] [h : Nontrivial V] : - 0 < finrank R V := - finrank_pos_iff.mpr h -#align finite_dimensional.finrank_pos FiniteDimensional.finrank_pos - -/-- See `FiniteDimensional.finrank_zero_iff` - for the stronger version with `NoZeroSMulDivisors R V`. -/ -theorem FiniteDimensional.finrank_eq_zero_iff [Module.Finite R V] : - finrank R V = 0 ↔ ∀ x : V, ∃ a : R, a ≠ 0 ∧ a • x = 0 := - Iff.trans - (by rw [← finrank_eq_rank]; norm_cast) - (rank_eq_zero_iff (R := R)) - -/-- The `StrongRankCondition` is automatic. See `commRing_strongRankCondition`. -/ -theorem FiniteDimensional.finrank_eq_zero_iff_isTorsion {R} [CommRing R] [StrongRankCondition R] - [IsDomain R] [Module R V] [Module.Finite R V] : - finrank R V = 0 ↔ IsTorsion R V := - Iff.trans - (by rw [← finrank_eq_rank]; norm_cast) - (rank_eq_zero_iff_isTorsion (R := R)) - -/-- A finite dimensional space has zero `finrank` iff it is a subsingleton. -This is the `finrank` version of `rank_zero_iff`. -/ -theorem FiniteDimensional.finrank_zero_iff [Module.Finite R V] [NoZeroSMulDivisors R V] : - finrank R V = 0 ↔ Subsingleton V := - Iff.trans - (by rw [← finrank_eq_rank]; norm_cast) - (rank_zero_iff (R := R)) -#align finite_dimensional.finrank_zero_iff FiniteDimensional.finrank_zero_iff - -theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux [Module.Finite R V] - [NoZeroSMulDivisors R V] - {ι : Type w} {p : ι → Submodule R V} (hp : CompleteLattice.Independent p) : - #{ i // p i ≠ ⊥ } ≤ (finrank R V : Cardinal.{w}) := by - suffices Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{v} (finrank R V : Cardinal.{w}) by - rwa [Cardinal.lift_le] at this - calc - Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{w} (Module.rank R V) := - hp.subtype_ne_bot_le_rank - _ = Cardinal.lift.{w} (finrank R V : Cardinal.{v}) := by rw [finrank_eq_rank] - _ = Cardinal.lift.{v} (finrank R V : Cardinal.{w}) := by simp -#align complete_lattice.independent.subtype_ne_bot_le_finrank_aux CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux - -/-- If `p` is an independent family of submodules of a `R`-finite module `V`, then the -number of nontrivial subspaces in the family `p` is finite. -/ -noncomputable def CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional - [Module.Finite R V] [NoZeroSMulDivisors R V] {ι : Type w} {p : ι → Submodule R V} - (hp : CompleteLattice.Independent p) : Fintype { i : ι // p i ≠ ⊥ } := by - suffices #{ i // p i ≠ ⊥ } < (ℵ₀ : Cardinal.{w}) by - rw [Cardinal.lt_aleph0_iff_fintype] at this - exact this.some - refine' lt_of_le_of_lt hp.subtype_ne_bot_le_finrank_aux _ - simp [Cardinal.nat_lt_aleph0] -#align complete_lattice.independent.fintype_ne_bot_of_finite_dimensional CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional - -/-- If `p` is an independent family of submodules of a `R`-finite module `V`, then the -number of nontrivial subspaces in the family `p` is bounded above by the dimension of `V`. - -Note that the `Fintype` hypothesis required here can be provided by -`CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional`. -/ -theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank - [Module.Finite R V] [NoZeroSMulDivisors R V] - {ι : Type w} {p : ι → Submodule R V} (hp : CompleteLattice.Independent p) - [Fintype { i // p i ≠ ⊥ }] : - Fintype.card { i // p i ≠ ⊥ } ≤ finrank R V := by simpa using hp.subtype_ne_bot_le_finrank_aux -#align complete_lattice.independent.subtype_ne_bot_le_finrank CompleteLattice.Independent.subtype_ne_bot_le_finrank - -section - -open BigOperators - -open Finset - -/-- If a finset has cardinality larger than the rank of a module, -then there is a nontrivial linear relation amongst its elements. -/ -theorem Module.exists_nontrivial_relation_of_finrank_lt_card - [Module.Finite R V] {t : Finset V} - (h : finrank R V < t.card) : ∃ f : V → R, ∑ e in t, f e • e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by - obtain ⟨g, sum, z, nonzero⟩ := Fintype.not_linearIndependent_iff.mp - (mt LinearIndependent.finset_card_le_finrank h.not_le) - refine ⟨Subtype.val.extend g 0, ?_, z, z.2, by rwa [Subtype.val_injective.extend_apply]⟩ - rw [← Finset.sum_finset_coe]; convert sum; apply Subtype.val_injective.extend_apply -#align finite_dimensional.exists_nontrivial_relation_of_rank_lt_card Module.exists_nontrivial_relation_of_finrank_lt_card - -/-- If a finset has cardinality larger than `finrank + 1`, -then there is a nontrivial linear relation amongst its elements, -such that the coefficients of the relation sum to zero. -/ -theorem Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card [Module.Finite R V] - {t : Finset V} (h : finrank R V + 1 < t.card) : - ∃ f : V → R, ∑ e in t, f e • e = 0 ∧ ∑ e in t, f e = 0 ∧ ∃ x ∈ t, f x ≠ 0 := by - -- Pick an element x₀ ∈ t, - obtain ⟨x₀, x₀_mem⟩ := card_pos.1 ((Nat.succ_pos _).trans h) - -- and apply the previous lemma to the {xᵢ - x₀} - let shift : V ↪ V := ⟨(· - x₀), sub_left_injective⟩ - classical - let t' := (t.erase x₀).map shift - have h' : finrank R V < t'.card := by - rw [card_map, card_erase_of_mem x₀_mem] - exact Nat.lt_pred_iff.mpr h - -- to obtain a function `g`. - obtain ⟨g, gsum, x₁, x₁_mem, nz⟩ := exists_nontrivial_relation_of_finrank_lt_card h' - -- Then obtain `f` by translating back by `x₀`, - -- and setting the value of `f` at `x₀` to ensure `∑ e in t, f e = 0`. - let f : V → R := fun z ↦ if z = x₀ then -∑ z in t.erase x₀, g (z - x₀) else g (z - x₀) - refine ⟨f, ?_, ?_, ?_⟩ - -- After this, it's a matter of verifying the properties, - -- based on the corresponding properties for `g`. - · rw [sum_map, Embedding.coeFn_mk] at gsum - simp_rw [← t.sum_erase_add _ x₀_mem, if_pos, neg_smul, sum_smul, - ← sub_eq_add_neg, ← sum_sub_distrib, ← gsum, smul_sub] - refine sum_congr rfl fun x x_mem ↦ ?_ - rw [if_neg (mem_erase.mp x_mem).1] - · simp_rw [← t.sum_erase_add _ x₀_mem, if_pos, add_neg_eq_zero] - exact sum_congr rfl fun x x_mem ↦ if_neg (mem_erase.mp x_mem).1 - · obtain ⟨x₁, x₁_mem', rfl⟩ := Finset.mem_map.mp x₁_mem - have := mem_erase.mp x₁_mem' - exact ⟨x₁, by simpa only [Embedding.coeFn_mk, sub_add_cancel, this.2, true_and, if_neg this.1]⟩ -#align finite_dimensional.exists_nontrivial_relation_sum_zero_of_rank_succ_lt_card Module.exists_nontrivial_relation_sum_zero_of_finrank_succ_lt_card - -end - -end DivisionRing - -section ZeroRank - -variable [Ring R] [AddCommGroup V] [Module R V] - -open FiniteDimensional - -theorem Module.finite_of_rank_eq_nat [Module.Free R V] {n : ℕ} (h : Module.rank R V = n) : - Module.Finite R V := by - nontriviality R - obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := R) (M := V) - have := mk_lt_aleph0_iff.mp <| - b.linearIndependent.cardinal_le_rank |>.trans_eq h |>.trans_lt <| nat_lt_aleph0 n - exact Module.Finite.of_basis b - -theorem Module.finite_of_rank_eq_zero [NoZeroSMulDivisors R V] - (h : Module.rank R V = 0) : - Module.Finite R V := by - nontriviality R - rw [rank_zero_iff] at h - infer_instance - -theorem Module.finite_of_rank_eq_one [Module.Free R V] (h : Module.rank R V = 1) : - Module.Finite R V := - Module.finite_of_rank_eq_nat <| h.trans Nat.cast_one.symm - -theorem FiniteDimensional.finrank_eq_zero_of_rank_eq_zero (h : Module.rank R V = 0) : - finrank R V = 0 := by - delta finrank - rw [h, zero_toNat] -#align finrank_eq_zero_of_rank_eq_zero FiniteDimensional.finrank_eq_zero_of_rank_eq_zero - -variable (R V) - -instance Module.finite_bot : Module.Finite R (⊥ : Submodule R V) := inferInstance - -variable {R V} - -theorem Submodule.bot_eq_top_of_rank_eq_zero [NoZeroSMulDivisors R V] (h : Module.rank R V = 0) : - (⊥ : Submodule R V) = ⊤ := by - nontriviality R - rw [rank_zero_iff] at h - exact Subsingleton.elim _ _ -#align bot_eq_top_of_rank_eq_zero Submodule.bot_eq_top_of_rank_eq_zero - -/-- See `rank_subsingleton` for the reason that `Nontrivial R` is needed. -/ -@[simp] -theorem Submodule.rank_eq_zero [Nontrivial R] [NoZeroSMulDivisors R V] {S : Submodule R V} : - Module.rank R S = 0 ↔ S = ⊥ := - ⟨fun h => - (Submodule.eq_bot_iff _).2 fun x hx => - congr_arg Subtype.val <| - ((Submodule.eq_bot_iff _).1 <| Eq.symm <| Submodule.bot_eq_top_of_rank_eq_zero h) ⟨x, hx⟩ - Submodule.mem_top, - fun h => by rw [h, rank_bot]⟩ -#align rank_eq_zero Submodule.rank_eq_zero - -@[simp] -theorem Submodule.finrank_eq_zero [StrongRankCondition R] [NoZeroSMulDivisors R V] - {S : Submodule R V} [Module.Finite R S] : - finrank R S = 0 ↔ S = ⊥ := by - rw [← Submodule.rank_eq_zero, ← finrank_eq_rank, ← @Nat.cast_zero Cardinal, Cardinal.natCast_inj] -#align finrank_eq_zero Submodule.finrank_eq_zero - -end ZeroRank diff --git a/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean b/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean index 48df29c1f2b1a..c660b3009e1b4 100644 --- a/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean +++ b/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean @@ -3,8 +3,6 @@ Copyright (c) 2022 Anne Baanen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ -import Mathlib.Data.ZMod.Quotient -import Mathlib.LinearAlgebra.FreeModule.Finite.Rank import Mathlib.LinearAlgebra.FreeModule.PID import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition import Mathlib.LinearAlgebra.QuotientPi diff --git a/Mathlib/LinearAlgebra/FreeModule/PID.lean b/Mathlib/LinearAlgebra/FreeModule/PID.lean index 5cc56d4b87326..33b9639e6cbcc 100644 --- a/Mathlib/LinearAlgebra/FreeModule/PID.lean +++ b/Mathlib/LinearAlgebra/FreeModule/PID.lean @@ -3,11 +3,8 @@ Copyright (c) 2020 Anne Baanen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ -import Mathlib.LinearAlgebra.Dimension +import Mathlib.LinearAlgebra.Dimension.StrongRankCondition import Mathlib.LinearAlgebra.FreeModule.Basic -import Mathlib.LinearAlgebra.Matrix.ToLin -import Mathlib.RingTheory.PrincipalIdealDomain -import Mathlib.RingTheory.Finiteness #align_import linear_algebra.free_module.pid from "leanprover-community/mathlib"@"d87199d51218d36a0a42c66c82d147b5a7ff87b3" diff --git a/Mathlib/LinearAlgebra/FreeModule/Rank.lean b/Mathlib/LinearAlgebra/FreeModule/Rank.lean deleted file mode 100644 index b7c2087e963eb..0000000000000 --- a/Mathlib/LinearAlgebra/FreeModule/Rank.lean +++ /dev/null @@ -1,257 +0,0 @@ -/- -Copyright (c) 2021 Riccardo Brasca. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Riccardo Brasca --/ -import Mathlib.LinearAlgebra.Dimension -import Mathlib.SetTheory.Cardinal.Subfield - -#align_import linear_algebra.free_module.rank from "leanprover-community/mathlib"@"465d4301d8da5945ef1dc1b29fb34c2f2b315ac4" - -/-! - -# Extra results about `Module.rank` - -This file contains some extra results not in `LinearAlgebra.Dimension`. - -It also contains a proof of the Erdős-Kaplansky theorem (`rank_dual_eq_card_dual_of_aleph0_le_rank`) -which says that the dimension of an infinite-dimensional dual space over a division ring -has dimension equal to its cardinality. - --/ - - -universe u v w - -variable (R : Type u) (M : Type v) (N : Type w) - -open TensorProduct DirectSum BigOperators Cardinal - -open Cardinal - -section Ring - -variable [Ring R] [StrongRankCondition R] - -variable [AddCommGroup M] [Module R M] [Module.Free R M] - -variable [AddCommGroup N] [Module R N] [Module.Free R N] - -open Module.Free - -@[simp] -theorem rank_finsupp (ι : Type w) : - Module.rank R (ι →₀ M) = Cardinal.lift.{v} #ι * Cardinal.lift.{w} (Module.rank R M) := by - obtain ⟨⟨_, bs⟩⟩ := Module.Free.exists_basis (R := R) (M := M) - rw [← bs.mk_eq_rank'', ← (Finsupp.basis fun _ : ι => bs).mk_eq_rank'', Cardinal.mk_sigma, - Cardinal.sum_const] -#align rank_finsupp rank_finsupp - -theorem rank_finsupp' (ι : Type v) : Module.rank R (ι →₀ M) = #ι * Module.rank R M := by - simp [rank_finsupp] -#align rank_finsupp' rank_finsupp' - -/-- The rank of `(ι →₀ R)` is `(#ι).lift`. -/ --- Porting note, this should not be `@[simp]`, as simp can prove it. --- @[simp] -theorem rank_finsupp_self (ι : Type w) : Module.rank R (ι →₀ R) = Cardinal.lift.{u} #ι := by - simp [rank_finsupp] -#align rank_finsupp_self rank_finsupp_self - -/-- If `R` and `ι` lie in the same universe, the rank of `(ι →₀ R)` is `# ι`. -/ -theorem rank_finsupp_self' {ι : Type u} : Module.rank R (ι →₀ R) = #ι := by simp -#align rank_finsupp_self' rank_finsupp_self' - -variable {R M} -theorem rank_eq_cardinal_basis {ι : Type w} (b : Basis ι R M) : - Cardinal.lift.{w} (Module.rank R M) = Cardinal.lift.{v} #ι := by - apply Cardinal.lift_injective.{u} - simp_rw [Cardinal.lift_lift] - have := b.repr.lift_rank_eq - rwa [rank_finsupp_self, Cardinal.lift_lift] at this - -theorem rank_eq_cardinal_basis' {ι : Type v} (b : Basis ι R M) : Module.rank R M = #ι := - Cardinal.lift_injective.{v} (rank_eq_cardinal_basis b) - -variable (R M) - -/-- The rank of the direct sum is the sum of the ranks. -/ -@[simp] -theorem rank_directSum {ι : Type v} (M : ι → Type w) [∀ i : ι, AddCommGroup (M i)] - [∀ i : ι, Module R (M i)] [∀ i : ι, Module.Free R (M i)] : - Module.rank R (⨁ i, M i) = Cardinal.sum fun i => Module.rank R (M i) := by - let B i := chooseBasis R (M i) - let b : Basis _ R (⨁ i, M i) := DFinsupp.basis fun i => B i - simp [← b.mk_eq_rank'', fun i => (B i).mk_eq_rank''] -#align rank_direct_sum rank_directSum - -/-- If `m` and `n` are `Fintype`, the rank of `m × n` matrices is `(#m).lift * (#n).lift`. -/ -@[simp] -theorem rank_matrix (m : Type v) (n : Type w) [Finite m] [Finite n] : - Module.rank R (Matrix m n R) = - Cardinal.lift.{max v w u, v} #m * Cardinal.lift.{max v w u, w} #n := by - cases nonempty_fintype m - cases nonempty_fintype n - have h := (Matrix.stdBasis R m n).mk_eq_rank - rw [← lift_lift.{max v w u, max v w}, lift_inj] at h - simpa using h.symm -#align rank_matrix rank_matrix - -/-- If `m` and `n` are `Fintype` that lie in the same universe, the rank of `m × n` matrices is - `(#n * #m).lift`. -/ -@[simp high] -theorem rank_matrix' (m n : Type v) [Finite m] [Finite n] : - Module.rank R (Matrix m n R) = Cardinal.lift.{u} (#m * #n) := by - rw [rank_matrix, lift_mul, lift_umax.{v, u}] -#align rank_matrix' rank_matrix' - -/-- If `m` and `n` are `Fintype` that lie in the same universe as `R`, the rank of `m × n` matrices - is `# m * # n`. -/ --- @[simp] -- Porting note: simp can prove this -theorem rank_matrix'' (m n : Type u) [Finite m] [Finite n] : - Module.rank R (Matrix m n R) = #m * #n := by simp -#align rank_matrix'' rank_matrix'' - -end Ring - -section CommRing - -variable [CommRing R] [StrongRankCondition R] - -variable [AddCommGroup M] [Module R M] [Module.Free R M] - -variable [AddCommGroup N] [Module R N] [Module.Free R N] - -open Module.Free - -/-- The rank of `M ⊗[R] N` is `(Module.rank R M).lift * (Module.rank R N).lift`. -/ -@[simp] -theorem rank_tensorProduct : - Module.rank R (M ⊗[R] N) = - Cardinal.lift.{w, v} (Module.rank R M) * Cardinal.lift.{v, w} (Module.rank R N) := by - obtain ⟨⟨_, bM⟩⟩ := Module.Free.exists_basis (R := R) (M := M) - obtain ⟨⟨_, bN⟩⟩ := Module.Free.exists_basis (R := R) (M := N) - rw [← bM.mk_eq_rank'', ← bN.mk_eq_rank'', ← (bM.tensorProduct bN).mk_eq_rank'', Cardinal.mk_prod] -#align rank_tensor_product rank_tensorProduct - -/-- If `M` and `N` lie in the same universe, the rank of `M ⊗[R] N` is - `(Module.rank R M) * (Module.rank R N)`. -/ -theorem rank_tensorProduct' (N : Type v) [AddCommGroup N] [Module R N] [Module.Free R N] : - Module.rank R (M ⊗[R] N) = Module.rank R M * Module.rank R N := by simp -#align rank_tensor_product' rank_tensorProduct' - -end CommRing - -section DivisionRing - -variable (K : Type u) [DivisionRing K] - -/-- Key lemma towards the Erdős-Kaplansky theorem from https://mathoverflow.net/a/168624 -/ -theorem max_aleph0_card_le_rank_fun_nat : max ℵ₀ #K ≤ Module.rank K (ℕ → K) := by - have aleph0_le : ℵ₀ ≤ Module.rank K (ℕ → K) := (rank_finsupp_self K ℕ).symm.trans_le - (Finsupp.lcoeFun.rank_le_of_injective <| by exact FunLike.coe_injective) - refine max_le aleph0_le ?_ - obtain card_K | card_K := le_or_lt #K ℵ₀ - · exact card_K.trans aleph0_le - by_contra! - obtain ⟨⟨ιK, bK⟩⟩ := Module.Free.exists_basis (R := K) (M := ℕ → K) - let L := Subfield.closure (Set.range (fun i : ιK × ℕ ↦ bK i.1 i.2)) - have hLK : #L < #K - · refine (Subfield.cardinal_mk_closure_le_max _).trans_lt - (max_lt_iff.mpr ⟨mk_range_le.trans_lt ?_, card_K⟩) - rwa [mk_prod, ← aleph0, lift_uzero, ← rank_eq_cardinal_basis' bK, mul_aleph0_eq aleph0_le] - letI := Module.compHom K (RingHom.op L.subtype) - obtain ⟨⟨ιL, bL⟩⟩ := Module.Free.exists_basis (R := Lᵐᵒᵖ) (M := K) - have card_ιL : ℵ₀ ≤ #ιL - · contrapose! hLK - haveI := @Fintype.ofFinite _ (lt_aleph0_iff_finite.mp hLK) - rw [bL.repr.toEquiv.cardinal_eq, mk_finsupp_of_fintype, - ← MulOpposite.opEquiv.cardinal_eq] at card_K ⊢ - apply power_nat_le - contrapose! card_K - exact (power_lt_aleph0 card_K <| nat_lt_aleph0 _).le - obtain ⟨e⟩ := lift_mk_le'.mp (card_ιL.trans_eq (lift_uzero #ιL).symm) - have rep_e := bK.total_repr (bL ∘ e) - rw [Finsupp.total_apply, Finsupp.sum] at rep_e - set c := bK.repr (bL ∘ e) - set s := c.support - let f i (j : s) : L := ⟨bK j i, Subfield.subset_closure ⟨(j, i), rfl⟩⟩ - have : ¬LinearIndependent Lᵐᵒᵖ f := fun h ↦ by - have := h.cardinal_lift_le_rank - rw [lift_uzero, (LinearEquiv.piCongrRight fun _ ↦ MulOpposite.opLinearEquiv Lᵐᵒᵖ).rank_eq, - rank_fun'] at this - exact (nat_lt_aleph0 _).not_le this - obtain ⟨t, g, eq0, i, hi, hgi⟩ := not_linearIndependent_iff.mp this - refine hgi (linearIndependent_iff'.mp (bL.linearIndependent.comp e e.injective) t g ?_ i hi) - clear_value c s - simp_rw [← rep_e, Finset.sum_apply, Pi.smul_apply, Finset.smul_sum] - rw [Finset.sum_comm] - refine Finset.sum_eq_zero fun i hi ↦ ?_ - replace eq0 := congr_arg L.subtype (congr_fun eq0 ⟨i, hi⟩) - rw [Finset.sum_apply, map_sum] at eq0 - have : SMulCommClass Lᵐᵒᵖ K K := ⟨fun _ _ _ ↦ mul_assoc _ _ _⟩ - simp_rw [smul_comm _ (c i), ← Finset.smul_sum] - erw [eq0, smul_zero] - -variable {K} - -open Function in -theorem rank_fun_infinite {ι : Type v} [hι : Infinite ι] : Module.rank K (ι → K) = #(ι → K) := by - obtain ⟨⟨ιK, bK⟩⟩ := Module.Free.exists_basis (R := K) (M := ι → K) - obtain ⟨e⟩ := lift_mk_le'.mp ((aleph0_le_mk_iff.mpr hι).trans_eq (lift_uzero #ι).symm) - have := LinearMap.lift_rank_le_of_injective _ <| - LinearMap.funLeft_injective_of_surjective K K _ (invFun_surjective e.injective) - rw [lift_umax.{u,v}, lift_id'.{u,v}] at this - have key := (lift_le.{v}.mpr <| max_aleph0_card_le_rank_fun_nat K).trans this - rw [lift_max, lift_aleph0, max_le_iff] at key - haveI : Infinite ιK := by - rw [← aleph0_le_mk_iff, ← rank_eq_cardinal_basis' bK]; exact key.1 - rw [bK.repr.toEquiv.cardinal_eq, mk_finsupp_lift_of_infinite, - lift_umax.{u,v}, lift_id'.{u,v}, ← rank_eq_cardinal_basis' bK, eq_comm, max_eq_left] - exact key.2 - -/-- The **Erdős-Kaplansky Theorem**: the dual of an infinite-dimensional vector space - over a division ring has dimension equal to its cardinality. -/ -theorem rank_dual_eq_card_dual_of_aleph0_le_rank' {V : Type*} [AddCommGroup V] [Module K V] - (h : ℵ₀ ≤ Module.rank K V) : Module.rank Kᵐᵒᵖ (V →ₗ[K] K) = #(V →ₗ[K] K) := by - obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) - rw [rank_eq_cardinal_basis' b, aleph0_le_mk_iff] at h - have e := (b.constr Kᵐᵒᵖ (M' := K)).symm.trans - (LinearEquiv.piCongrRight fun _ ↦ MulOpposite.opLinearEquiv Kᵐᵒᵖ) - rw [e.rank_eq, e.toEquiv.cardinal_eq] - apply rank_fun_infinite - -/-- The **Erdős-Kaplansky Theorem** over a field. -/ -theorem rank_dual_eq_card_dual_of_aleph0_le_rank {K V} [Field K] [AddCommGroup V] [Module K V] - (h : ℵ₀ ≤ Module.rank K V) : Module.rank K (V →ₗ[K] K) = #(V →ₗ[K] K) := by - obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) - rw [rank_eq_cardinal_basis' b, aleph0_le_mk_iff] at h - have e := (b.constr K (M' := K)).symm - rw [e.rank_eq, e.toEquiv.cardinal_eq] - apply rank_fun_infinite - -theorem lift_rank_lt_rank_dual' {V : Type v} [AddCommGroup V] [Module K V] - (h : ℵ₀ ≤ Module.rank K V) : - Cardinal.lift.{u} (Module.rank K V) < Module.rank Kᵐᵒᵖ (V →ₗ[K] K) := by - obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V) - rw [rank_eq_cardinal_basis' b, rank_dual_eq_card_dual_of_aleph0_le_rank' h, - ← (b.constr ℕ (M' := K)).toEquiv.cardinal_eq, mk_arrow] - apply cantor' - erw [nat_lt_lift_iff, one_lt_iff_nontrivial] - infer_instance - -theorem lift_rank_lt_rank_dual {K : Type u} {V : Type v} [Field K] [AddCommGroup V] [Module K V] - (h : ℵ₀ ≤ Module.rank K V) : - Cardinal.lift.{u} (Module.rank K V) < Module.rank K (V →ₗ[K] K) := by - rw [rank_dual_eq_card_dual_of_aleph0_le_rank h, ← rank_dual_eq_card_dual_of_aleph0_le_rank' h] - exact lift_rank_lt_rank_dual' h - -theorem rank_lt_rank_dual' {V : Type u} [AddCommGroup V] [Module K V] (h : ℵ₀ ≤ Module.rank K V) : - Module.rank K V < Module.rank Kᵐᵒᵖ (V →ₗ[K] K) := by - convert lift_rank_lt_rank_dual' h; rw [lift_id] - -theorem rank_lt_rank_dual {K V : Type u} [Field K] [AddCommGroup V] [Module K V] - (h : ℵ₀ ≤ Module.rank K V) : Module.rank K V < Module.rank K (V →ₗ[K] K) := by - convert lift_rank_lt_rank_dual h; rw [lift_id] - -end DivisionRing diff --git a/Mathlib/LinearAlgebra/Matrix/Diagonal.lean b/Mathlib/LinearAlgebra/Matrix/Diagonal.lean index bca279c5c5177..72e02c68eb72a 100644 --- a/Mathlib/LinearAlgebra/Matrix/Diagonal.lean +++ b/Mathlib/LinearAlgebra/Matrix/Diagonal.lean @@ -3,8 +3,7 @@ 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 -/ -import Mathlib.LinearAlgebra.Matrix.ToLin -import Mathlib.LinearAlgebra.FreeModule.Rank +import Mathlib.LinearAlgebra.Dimension.LinearMap #align_import linear_algebra.matrix.diagonal from "leanprover-community/mathlib"@"b1c23399f01266afe392a0d8f71f599a0dad4f7b" diff --git a/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean b/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean index 988419527c93c..43fe7fe1e73ea 100644 --- a/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean +++ b/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean @@ -4,9 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.LinearAlgebra.TensorAlgebra.Basic -import Mathlib.LinearAlgebra.FreeModule.Basic -import Mathlib.LinearAlgebra.FreeModule.Rank -import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition import Mathlib.LinearAlgebra.FreeAlgebra /-! diff --git a/Mathlib/LinearAlgebra/Trace.lean b/Mathlib/LinearAlgebra/Trace.lean index 2c292d45e5369..b5b54579236e9 100644 --- a/Mathlib/LinearAlgebra/Trace.lean +++ b/Mathlib/LinearAlgebra/Trace.lean @@ -3,14 +3,7 @@ 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, Antoine Labelle -/ -import Mathlib.LinearAlgebra.Matrix.ToLin -import Mathlib.LinearAlgebra.Matrix.Trace import Mathlib.LinearAlgebra.Contraction -import Mathlib.LinearAlgebra.TensorProductBasis -import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition -import Mathlib.LinearAlgebra.FreeModule.Finite.Rank -import Mathlib.LinearAlgebra.Projection -import Mathlib.LinearAlgebra.FreeModule.PID #align_import linear_algebra.trace from "leanprover-community/mathlib"@"4cf7ca0e69e048b006674cf4499e5c7d296a89e0" diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean index 03dc54465341c..fa28b61e6ac9f 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean @@ -448,7 +448,7 @@ theorem addHaar_ball_of_pos (x : E) {r : ℝ} (hr : 0 < r) : theorem addHaar_ball_mul [Nontrivial E] (x : E) {r : ℝ} (hr : 0 ≤ r) (s : ℝ) : μ (ball x (r * s)) = ENNReal.ofReal (r ^ finrank ℝ E) * μ (ball 0 s) := by rcases hr.eq_or_lt with (rfl | h) - · simp only [zero_pow (finrank_pos (R := ℝ) (V := E)), measure_empty, zero_mul, + · simp only [zero_pow (finrank_pos (R := ℝ) (M := E)), measure_empty, zero_mul, ENNReal.ofReal_zero, ball_zero] · exact addHaar_ball_mul_of_pos μ x h s #align measure_theory.measure.add_haar_ball_mul MeasureTheory.Measure.addHaar_ball_mul diff --git a/Mathlib/NumberTheory/RamificationInertia.lean b/Mathlib/NumberTheory/RamificationInertia.lean index 3f5f11f09d59b..6c9591e5a387b 100644 --- a/Mathlib/NumberTheory/RamificationInertia.lean +++ b/Mathlib/NumberTheory/RamificationInertia.lean @@ -3,7 +3,6 @@ Copyright (c) 2022 Anne Baanen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ -import Mathlib.LinearAlgebra.FreeModule.Finite.Rank import Mathlib.RingTheory.DedekindDomain.Ideal #align_import number_theory.ramification_inertia from "leanprover-community/mathlib"@"039a089d2a4b93c761b234f3e5f5aeb752bac60f" diff --git a/Mathlib/RingTheory/Finiteness.lean b/Mathlib/RingTheory/Finiteness.lean index cc97605ed93a3..ae455e22ea73e 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -738,6 +738,13 @@ instance Module.Finite.tensorProduct [CommSemiring R] [AddCommMonoid M] [Module out := (TensorProduct.map₂_mk_top_top_eq_top R M N).subst (hM.out.map₂ _ hN.out) #align module.finite.tensor_product Module.Finite.tensorProduct +/-- If a free module is finite, then any arbitrary basis is finite. -/ +lemma Module.Finite.finite_basis {R M} [Ring R] [Nontrivial R] [AddCommGroup M] [Module R M] + {ι} [Module.Finite R M] (b : Basis ι R M) : + _root_.Finite ι := + let ⟨s, hs⟩ := ‹Module.Finite R M› + basis_finite_of_finite_spans (↑s) s.finite_toSet hs b + end ModuleAndAlgebra namespace Submodule From 5683185bee6799867b53e866c930b341ea627a75 Mon Sep 17 00:00:00 2001 From: Amelia Livingston <101damnations@github.com> Date: Mon, 1 Jan 2024 15:59:48 +0000 Subject: [PATCH 297/353] feat(RepresentationTheory/GroupCohomology/LowDegree): Identify `groupCohomology A n`with `Hn A` for `n = 0, 1, 2` (#8802) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joël Riou --- .../GroupCohomology/Basic.lean | 19 ++ .../GroupCohomology/LowDegree.lean | 164 +++++++++++++++++- 2 files changed, 177 insertions(+), 6 deletions(-) diff --git a/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean b/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean index c2e8043a3b16c..107b8481575ac 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean @@ -220,6 +220,19 @@ def inhomogeneousCochainsIso : inhomogeneousCochains A ≅ linearYonedaObjResolu Category.comp_id] #align group_cohomology.inhomogeneous_cochains_iso groupCohomology.inhomogeneousCochainsIso +/-- The `n`-cocycles `Zⁿ(G, A)` of a `k`-linear `G`-representation `A`, i.e. the kernel of the +`n`th differential in the complex of inhomogeneous cochains. -/ +abbrev cocycles (n : ℕ) : ModuleCat k := (inhomogeneousCochains A).cycles n + +/-- The natural inclusion of the `n`-cocycles `Zⁿ(G, A)` into the `n`-cochains `Cⁿ(G, A).` -/ +abbrev iCocycles (n : ℕ) : cocycles A n ⟶ ModuleCat.of k ((Fin n → G) → A) := + (inhomogeneousCochains A).iCycles n + +/-- This is the map from `i`-cochains to `j`-cocycles induced by the differential in the complex of +inhomogeneous cochains. -/ +abbrev toCocycles (i j : ℕ) : ModuleCat.of k ((Fin i → G) → A) ⟶ cocycles A j := + (inhomogeneousCochains A).toCycles i j + end groupCohomology open groupCohomology @@ -230,6 +243,12 @@ def groupCohomology [Group G] (A : Rep k G) (n : ℕ) : ModuleCat k := (inhomogeneousCochains A).homology n #align group_cohomology groupCohomology +/-- The natural map from `n`-cocycles to `n`th group cohomology for a `k`-linear +`G`-representation `A`. -/ +abbrev groupCohomologyπ [Group G] (A : Rep k G) (n : ℕ) : + groupCohomology.cocycles A n ⟶ groupCohomology A n := + (inhomogeneousCochains A).homologyπ n + /-- The `n`th group cohomology of a `k`-linear `G`-representation `A` is isomorphic to `Extⁿ(k, A)` (taken in `Rep k G`), where `k` is a trivial `k`-linear `G`-representation. -/ def groupCohomologyIsoExt [Group G] (A : Rep k G) (n : ℕ) : diff --git a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean index bd779ec3f2dce..3ef48ae74ca4d 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean @@ -1,9 +1,10 @@ /- Copyright (c) 2023 Amelia Livingston. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Amelia Livingston +Authors: Amelia Livingston, Joël Riou -/ +import Mathlib.Algebra.Homology.ShortComplex.ModuleCat import Mathlib.RepresentationTheory.GroupCohomology.Basic import Mathlib.RepresentationTheory.Invariants @@ -20,9 +21,9 @@ cokernel, whereas the definitions here are explicit quotients of cocycles by cob We also show that when the representation on `A` is trivial, `H¹(G, A) ≃ Hom(G, A)`. -Later this file will contain an identification between the definition in -`RepresentationTheory.GroupCohomology.Basic`, `groupCohomology A n`, and the `Hn A` in this file, -for `n = 0, 1, 2`. +The file also contains an identification between the definitions in +`RepresentationTheory.GroupCohomology.Basic`, `groupCohomology.cocycles A n` and +`groupCohomology A n`, and the `nCocycles` and `Hn A` in this file, for `n = 0, 1, 2`. ## Main definitions @@ -33,11 +34,11 @@ for `n = 0, 1, 2`. 2-coboundaries (i.e. `B²(G, A) := Im(d¹: Fun(G, A) → Fun(G², A))`). * `groupCohomology.H1LequivOfIsTrivial`: the isomorphism `H¹(G, A) ≃ Hom(G, A)` when the representation on `A` is trivial. +* `groupCohomology.isoHn` for `n = 0, 1, 2`: an isomorphism +`groupCohomology A n ≅ groupCohomology.Hn A`. ## TODO -* Identify `Hn A` as defined in this file with `groupCohomology A n` for `n = 0, 1, 2`. -* Hilbert's theorem 90 * The relationship between `H2` and group extensions * The inflation-restriction exact sequence * Nonabelian group cohomology @@ -405,4 +406,155 @@ theorem H1LequivOfIsTrivial_comp_H1_π [A.IsTrivial] : rfl end H1 +section groupCohomologyIso +open ShortComplex +section H0 + +lemma dZero_comp_H0_subtype : dZero A ∘ₗ (H0 A).subtype = 0 := by + ext ⟨x, hx⟩ g + replace hx := hx g + rw [← sub_eq_zero] at hx + exact hx + +/-- The (exact) short complex `A.ρ.invariants ⟶ A ⟶ (G → A)`. -/ +@[simps!] +def shortComplexH0 : ShortComplex (ModuleCat k) := + ShortComplex.moduleCatMk _ _ (dZero_comp_H0_subtype A) + +instance : Mono (shortComplexH0 A).f := by + rw [ModuleCat.mono_iff_injective] + apply Submodule.injective_subtype + +lemma shortComplexH0_exact : (shortComplexH0 A).Exact := by + rw [ShortComplex.moduleCat_exact_iff] + intro (x : A) (hx : dZero _ x = 0) + refine' ⟨⟨x, fun g => _⟩, rfl⟩ + rw [← sub_eq_zero] + exact congr_fun hx g + +/-- The arrow `A --dZero--> Fun(G, A)` is isomorphic to the differential +`(inhomogeneousCochains A).d 0 1` of the complex of inhomogeneous cochains of `A`. -/ +@[simps! hom_left hom_right inv_left inv_right] +def dZeroArrowIso : Arrow.mk ((inhomogeneousCochains A).d 0 1) ≅ + Arrow.mk (ModuleCat.ofHom (dZero A)) := + Arrow.isoMk (zeroCochainsLequiv A).toModuleIso + (oneCochainsLequiv A).toModuleIso (dZero_comp_eq A) + +/-- The 0-cocycles of the complex of inhomogeneous cochains of `A` are isomorphic to +`A.ρ.invariants`, which is a simpler type. -/ +def isoZeroCocycles : cocycles A 0 ≅ ModuleCat.of k A.ρ.invariants := + KernelFork.mapIsoOfIsLimit + ((inhomogeneousCochains A).cyclesIsKernel 0 1 (by simp)) (shortComplexH0_exact A).fIsKernel + (dZeroArrowIso A) + +lemma isoZeroCocycles_hom_comp_subtype : + (isoZeroCocycles A).hom ≫ A.ρ.invariants.subtype = + iCocycles A 0 ≫ (zeroCochainsLequiv A).toModuleIso.hom := by + dsimp [isoZeroCocycles] + apply KernelFork.mapOfIsLimit_ι + +/-- The 0th group cohomology of `A`, defined as the 0th cohomology of the complex of inhomogeneous +cochains, is isomorphic to the invariants of the representation on `A`. -/ +def isoH0 : groupCohomology A 0 ≅ ModuleCat.of k (H0 A) := + (CochainComplex.isoHomologyπ₀ _).symm ≪≫ isoZeroCocycles A + +lemma groupCohomologyπ_comp_isoH0_hom : + groupCohomologyπ A 0 ≫ (isoH0 A).hom = (isoZeroCocycles A).hom := by + simp [isoH0] + +end H0 +section H1 + +/-- The short complex `A --dZero--> Fun(G, A) --dOne--> Fun(G × G, A)`. -/ +def shortComplexH1 : ShortComplex (ModuleCat k) := + moduleCatMk (dZero A) (dOne A) (dOne_comp_dZero A) + +/-- The short complex `A --dZero--> Fun(G, A) --dOne--> Fun(G × G, A)` is isomorphic to the 1st +short complex associated to the complex of inhomogeneous cochains of `A`. -/ +@[simps! hom inv] +def shortComplexH1Iso : (inhomogeneousCochains A).sc' 0 1 2 ≅ shortComplexH1 A := + isoMk (zeroCochainsLequiv A).toModuleIso (oneCochainsLequiv A).toModuleIso + (twoCochainsLequiv A).toModuleIso (dZero_comp_eq A) (dOne_comp_eq A) + +/-- The 1-cocycles of the complex of inhomogeneous cochains of `A` are isomorphic to +`oneCocycles A`, which is a simpler type. -/ +def isoOneCocycles : cocycles A 1 ≅ ModuleCat.of k (oneCocycles A) := + (inhomogeneousCochains A).cyclesIsoSc' _ _ _ (by aesop) (by aesop) ≪≫ + cyclesMapIso (shortComplexH1Iso A) ≪≫ (shortComplexH1 A).moduleCatCyclesIso + +lemma isoOneCocycles_hom_comp_subtype : + (isoOneCocycles A).hom ≫ ModuleCat.ofHom (oneCocycles A).subtype = + iCocycles A 1 ≫ (oneCochainsLequiv A).toModuleIso.hom := by + dsimp [isoOneCocycles] + rw [Category.assoc, Category.assoc] + erw [(shortComplexH1 A).moduleCatCyclesIso_hom_subtype] + rw [cyclesMap_i, HomologicalComplex.cyclesIsoSc'_hom_iCycles_assoc] + +lemma toCocycles_comp_isoOneCocycles_hom : + toCocycles A 0 1 ≫ (isoOneCocycles A).hom = + (zeroCochainsLequiv A).toModuleIso.hom ≫ + ModuleCat.ofHom (shortComplexH1 A).moduleCatToCycles := by + simp [isoOneCocycles] + rfl + +/-- The 1st group cohomology of `A`, defined as the 1st cohomology of the complex of inhomogeneous +cochains, is isomorphic to `oneCocycles A ⧸ oneCoboundaries A`, which is a simpler type. -/ +def isoH1 : groupCohomology A 1 ≅ ModuleCat.of k (H1 A) := + (inhomogeneousCochains A).homologyIsoSc' _ _ _ (by aesop) (by aesop) ≪≫ + homologyMapIso (shortComplexH1Iso A) ≪≫ (shortComplexH1 A).moduleCatHomologyIso + +lemma groupCohomologyπ_comp_isoH1_hom : + groupCohomologyπ A 1 ≫ (isoH1 A).hom = + (isoOneCocycles A).hom ≫ (shortComplexH1 A).moduleCatHomologyπ := by + simp [isoH1, isoOneCocycles] + +end H1 +section H2 + +/-- The short complex `Fun(G, A) --dOne--> Fun(G × G, A) --dTwo--> Fun(G × G × G, A)`. -/ +def shortComplexH2 : ShortComplex (ModuleCat k) := + moduleCatMk (dOne A) (dTwo A) (dTwo_comp_dOne A) + +/-- The short complex `Fun(G, A) --dOne--> Fun(G × G, A) --dTwo--> Fun(G × G × G, A)` is +isomorphic to the 2nd short complex associated to the complex of inhomogeneous cochains of `A`. -/ +@[simps! hom inv] +def shortComplexH2Iso : + (inhomogeneousCochains A).sc' 1 2 3 ≅ shortComplexH2 A := + isoMk (oneCochainsLequiv A).toModuleIso (twoCochainsLequiv A).toModuleIso + (threeCochainsLequiv A).toModuleIso (dOne_comp_eq A) (dTwo_comp_eq A) + +/-- The 2-cocycles of the complex of inhomogeneous cochains of `A` are isomorphic to +`twoCocycles A`, which is a simpler type. -/ +def isoTwoCocycles : cocycles A 2 ≅ ModuleCat.of k (twoCocycles A) := + (inhomogeneousCochains A).cyclesIsoSc' _ _ _ (by aesop) (by aesop) ≪≫ + cyclesMapIso (shortComplexH2Iso A) ≪≫ (shortComplexH2 A).moduleCatCyclesIso + +lemma isoTwoCocycles_hom_comp_subtype : + (isoTwoCocycles A).hom ≫ ModuleCat.ofHom (twoCocycles A).subtype = + iCocycles A 2 ≫ (twoCochainsLequiv A).toModuleIso.hom := by + dsimp [isoTwoCocycles] + rw [Category.assoc, Category.assoc] + erw [(shortComplexH2 A).moduleCatCyclesIso_hom_subtype] + rw [cyclesMap_i, HomologicalComplex.cyclesIsoSc'_hom_iCycles_assoc] + +lemma toCocycles_comp_isoTwoCocycles_hom : + toCocycles A 1 2 ≫ (isoTwoCocycles A).hom = + (oneCochainsLequiv A).toModuleIso.hom ≫ + ModuleCat.ofHom (shortComplexH2 A).moduleCatToCycles := by + simp [isoTwoCocycles] + rfl + +/-- The 2nd group cohomology of `A`, defined as the 2nd cohomology of the complex of inhomogeneous +cochains, is isomorphic to `twoCocycles A ⧸ twoCoboundaries A`, which is a simpler type. -/ +def isoH2 : groupCohomology A 2 ≅ ModuleCat.of k (H2 A) := + (inhomogeneousCochains A).homologyIsoSc' _ _ _ (by aesop) (by aesop) ≪≫ + homologyMapIso (shortComplexH2Iso A) ≪≫ (shortComplexH2 A).moduleCatHomologyIso + +lemma groupCohomologyπ_comp_isoH2_hom : + groupCohomologyπ A 2 ≫ (isoH2 A).hom = + (isoTwoCocycles A).hom ≫ (shortComplexH2 A).moduleCatHomologyπ := by + simp [isoH2, isoTwoCocycles] + +end H2 +end groupCohomologyIso end groupCohomology From 4ae461307cc26a0ea89fda5bb97db497e18811d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 1 Jan 2024 17:53:37 +0000 Subject: [PATCH 298/353] chore(Algebra/GroupPower/Order): Fix "See also" comment (#9384) Reported by Alex [here](https://github.com/leanprover-community/mathlib4/commit/d61c95e1653dffe3f92c8927a905826929f50bce) --- Mathlib/Algebra/GroupPower/Order.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Algebra/GroupPower/Order.lean b/Mathlib/Algebra/GroupPower/Order.lean index 5e89df4fa0631..d2c43828400a5 100644 --- a/Mathlib/Algebra/GroupPower/Order.lean +++ b/Mathlib/Algebra/GroupPower/Order.lean @@ -126,7 +126,7 @@ theorem pow_lt_pow_left (h : x < y) (hx : 0 ≤ x) : ∀ {n : ℕ}, n ≠ 0 → mul_lt_mul_of_le_of_le' (pow_le_pow_left hx h.le _) h (pow_pos (hx.trans_lt h) _) hx #align pow_lt_pow_of_lt_left pow_lt_pow_left -/-- See also `pow_left_strictMonoOn`. -/ +/-- See also `pow_left_strictMono` and `Nat.pow_left_strictMono`. -/ lemma pow_left_strictMonoOn (hn : n ≠ 0) : StrictMonoOn (· ^ n : R → R) (Set.Ici 0) := fun _a ha _b _ hab ↦ pow_lt_pow_left hab ha hn #align strict_mono_on_pow pow_left_strictMonoOn From 5192777c94aec06289e492ce206d68fbbe72572c Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 1 Jan 2024 19:29:52 +0000 Subject: [PATCH 299/353] refactor: decapitalize names in `@[mk_iff]` (#9378) * `@[mk_iff] class MyPred` now generates `myPred_iff`, not `MyPred_iff` * add `Lean.Name.decapitalize` * fix indentation and a few typos in the docs/comments. Partially addresses issue #9129 --- Archive/Imo/Imo1981Q3.lean | 2 +- Mathlib/Algebra/CharP/Basic.lean | 2 +- .../Morphisms/FiniteType.lean | 2 +- .../Morphisms/QuasiCompact.lean | 2 +- .../Morphisms/QuasiSeparated.lean | 4 +- .../Morphisms/UniversallyClosed.lean | 2 +- Mathlib/Analysis/Calculus/TangentCone.lean | 2 +- .../Combinatorics/SimpleGraph/Acyclic.lean | 2 +- .../SimpleGraph/Connectivity.lean | 2 +- Mathlib/Data/Multiset/Basic.lean | 6 +- Mathlib/GroupTheory/Subsemigroup/Center.lean | 4 +- Mathlib/Lean/Name.lean | 6 + .../LinearAlgebra/Dimension/DivisionRing.lean | 2 +- Mathlib/Logic/Relation.lean | 5 +- Mathlib/Logic/UnivLE.lean | 2 +- Mathlib/NumberTheory/Cyclotomic/Basic.lean | 22 +-- Mathlib/Order/Atoms.lean | 6 +- Mathlib/Order/PrimeIdeal.lean | 6 +- Mathlib/Order/RelClasses.lean | 2 +- Mathlib/RingTheory/Etale.lean | 5 +- Mathlib/RingTheory/Ideal/Cotangent.lean | 4 +- Mathlib/RingTheory/Nilpotent.lean | 2 +- .../Polynomial/Eisenstein/Basic.lean | 2 +- Mathlib/RingTheory/PrincipalIdealDomain.lean | 2 +- Mathlib/SetTheory/Game/PGame.lean | 2 +- Mathlib/Tactic/MkIffOfInductiveProp.lean | 136 +++++++++--------- Mathlib/Topology/Bases.lean | 2 +- Mathlib/Topology/CompletelyRegular.lean | 4 +- .../Connected/TotallyDisconnected.lean | 2 +- Mathlib/Topology/FiberBundle/Basic.lean | 2 +- Mathlib/Topology/Maps.lean | 8 +- Mathlib/Topology/NoetherianSpace.lean | 2 +- Mathlib/Topology/QuasiSeparated.lean | 3 +- Mathlib/Topology/Separation.lean | 4 +- Mathlib/Topology/Sequences.lean | 2 +- Mathlib/Topology/Sober.lean | 2 +- .../UniformSpace/UniformEmbedding.lean | 4 +- test/MkIffOfInductive.lean | 2 +- 38 files changed, 135 insertions(+), 136 deletions(-) diff --git a/Archive/Imo/Imo1981Q3.lean b/Archive/Imo/Imo1981Q3.lean index 90b29784e58c4..16b8d382cde78 100644 --- a/Archive/Imo/Imo1981Q3.lean +++ b/Archive/Imo/Imo1981Q3.lean @@ -207,5 +207,5 @@ theorem imo1981_q3 : IsGreatest (specifiedSet 1981) 3524578 := by apply this · decide · decide - · norm_num [ProblemPredicate_iff]; decide + · norm_num [problemPredicate_iff]; decide #align imo1981_q3 imo1981_q3 diff --git a/Mathlib/Algebra/CharP/Basic.lean b/Mathlib/Algebra/CharP/Basic.lean index e312db33bddfc..5b8f1392cf593 100644 --- a/Mathlib/Algebra/CharP/Basic.lean +++ b/Mathlib/Algebra/CharP/Basic.lean @@ -103,7 +103,7 @@ For instance, endowing `{0, 1}` with addition given by `max` (i.e. `1` is absorb `CharZero {0, 1}` does not hold and yet `CharP {0, 1} 0` does. This example is formalized in `Counterexamples/CharPZeroNeCharZero.lean`. -/ -@[mk_iff charP_iff] +@[mk_iff] class CharP [AddMonoidWithOne R] (p : ℕ) : Prop where cast_eq_zero_iff' : ∀ x : ℕ, (x : R) = 0 ↔ p ∣ x #align char_p CharP diff --git a/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean b/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean index 13078c9c38642..5d6a653e841f2 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean @@ -43,7 +43,7 @@ class LocallyOfFiniteType (f : X ⟶ Y) : Prop where theorem locallyOfFiniteType_eq : @LocallyOfFiniteType = affineLocally @RingHom.FiniteType := by ext X Y f - rw [LocallyOfFiniteType_iff, affineLocally_iff_affineOpens_le] + rw [locallyOfFiniteType_iff, affineLocally_iff_affineOpens_le] exact RingHom.finiteType_respectsIso #align algebraic_geometry.locally_of_finite_type_eq AlgebraicGeometry.locallyOfFiniteType_eq diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean index dc056e57db862..a5f6eb28aa967 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean @@ -96,7 +96,7 @@ theorem isCompact_open_iff_eq_basicOpen_union {X : Scheme} [IsAffine X] (U : Set theorem quasiCompact_iff_forall_affine : QuasiCompact f ↔ ∀ U : Opens Y.carrier, IsAffineOpen U → IsCompact (f.1.base ⁻¹' (U : Set Y.carrier)) := by - rw [QuasiCompact_iff] + rw [quasiCompact_iff] refine' ⟨fun H U hU => H U U.isOpen hU.isCompact, _⟩ intro H U hU hU' obtain ⟨S, hS, rfl⟩ := (isCompact_open_iff_eq_finset_affine_union U).mp ⟨hU', hU⟩ diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean index 9b251d3054082..3f1ebec5f544d 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean @@ -56,7 +56,7 @@ def QuasiSeparated.affineProperty : AffineTargetMorphismProperty := fun X _ _ _ theorem quasiSeparatedSpace_iff_affine (X : Scheme) : QuasiSeparatedSpace X.carrier ↔ ∀ U V : X.affineOpens, IsCompact (U ∩ V : Set X.carrier) := by - rw [QuasiSeparatedSpace_iff] + rw [quasiSeparatedSpace_iff] constructor · intro H U V; exact H U V U.1.2 U.2.isCompact V.1.2 V.2.isCompact · intro H @@ -115,7 +115,7 @@ theorem quasi_compact_affineProperty_iff_quasiSeparatedSpace {X Y : Scheme} [IsA #align algebraic_geometry.quasi_compact_affine_property_iff_quasi_separated_space AlgebraicGeometry.quasi_compact_affineProperty_iff_quasiSeparatedSpace theorem quasiSeparated_eq_diagonal_is_quasiCompact : - @QuasiSeparated = MorphismProperty.diagonal @QuasiCompact := by ext; exact QuasiSeparated_iff _ + @QuasiSeparated = MorphismProperty.diagonal @QuasiCompact := by ext; exact quasiSeparated_iff _ #align algebraic_geometry.quasi_separated_eq_diagonal_is_quasi_compact AlgebraicGeometry.quasiSeparated_eq_diagonal_is_quasiCompact theorem quasi_compact_affineProperty_diagonal_eq : diff --git a/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean b/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean index 05339be03fc5d..b9aba7a2bb1bf 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean @@ -43,7 +43,7 @@ class UniversallyClosed (f : X ⟶ Y) : Prop where #align algebraic_geometry.universally_closed AlgebraicGeometry.UniversallyClosed theorem universallyClosed_eq : @UniversallyClosed = universally (topologically @IsClosedMap) := by - ext X Y f; rw [UniversallyClosed_iff] + ext X Y f; rw [universallyClosed_iff] #align algebraic_geometry.universally_closed_eq AlgebraicGeometry.universallyClosed_eq theorem universallyClosed_respectsIso : RespectsIso @UniversallyClosed := diff --git a/Mathlib/Analysis/Calculus/TangentCone.lean b/Mathlib/Analysis/Calculus/TangentCone.lean index 34e2f39c5bbb6..0eea4602ee8df 100644 --- a/Mathlib/Analysis/Calculus/TangentCone.lean +++ b/Mathlib/Analysis/Calculus/TangentCone.lean @@ -56,7 +56,7 @@ The main role of this property is to ensure that the differential within `s` at hence this name. The uniqueness it asserts is proved in `UniqueDiffWithinAt.eq` in `Fderiv.Basic`. To avoid pathologies in dimension 0, we also require that `x` belongs to the closure of `s` (which is automatic when `E` is not `0`-dimensional). -/ -@[mk_iff uniqueDiffWithinAt_iff] +@[mk_iff] structure UniqueDiffWithinAt (s : Set E) (x : E) : Prop where dense_tangentCone : Dense (Submodule.span 𝕜 (tangentConeAt 𝕜 s x) : Set E) mem_closure : x ∈ closure s diff --git a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean index 1c02bf8f62db3..9f1601be19201 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean @@ -134,7 +134,7 @@ theorem isAcyclic_iff_path_unique : G.IsAcyclic ↔ ∀ ⦃v w : V⦄ (p q : G.P theorem isTree_iff_existsUnique_path : G.IsTree ↔ Nonempty V ∧ ∀ v w : V, ∃! p : G.Walk v w, p.IsPath := by classical - rw [IsTree_iff, isAcyclic_iff_path_unique] + rw [isTree_iff, isAcyclic_iff_path_unique] constructor · rintro ⟨hc, hu⟩ refine ⟨hc.nonempty, ?_⟩ diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity.lean index 83c4a00358465..778bb1bad5a96 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity.lean @@ -2037,7 +2037,7 @@ This follows the convention observed by mathlib that something is connected iff exactly one connected component. There is a `CoeFun` instance so that `h u v` can be used instead of `h.Preconnected u v`. -/ -@[mk_iff connected_iff] +@[mk_iff] structure Connected : Prop where protected preconnected : G.Preconnected protected [nonempty : Nonempty V] diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index e0b3640e52acf..b847b159bf5ca 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -2744,7 +2744,7 @@ inductive Rel (r : α → β → Prop) : Multiset α → Multiset β → Prop | zero : Rel r 0 0 | cons {a b as bs} : r a b → Rel r as bs → Rel r (a ::ₘ as) (b ::ₘ bs) #align multiset.rel Multiset.Rel -#align multiset.rel_iff Multiset.Rel_iff +#align multiset.rel_iff Multiset.rel_iff variable {δ : Type*} {r : α → β → Prop} {p : γ → δ → Prop} @@ -2796,11 +2796,11 @@ theorem rel_flip_eq {s t : Multiset α} : Rel (fun a b => b = a) s t ↔ s = t : #align multiset.rel_flip_eq Multiset.rel_flip_eq @[simp] -theorem rel_zero_left {b : Multiset β} : Rel r 0 b ↔ b = 0 := by rw [Rel_iff]; simp +theorem rel_zero_left {b : Multiset β} : Rel r 0 b ↔ b = 0 := by rw [rel_iff]; simp #align multiset.rel_zero_left Multiset.rel_zero_left @[simp] -theorem rel_zero_right {a : Multiset α} : Rel r a 0 ↔ a = 0 := by rw [Rel_iff]; simp +theorem rel_zero_right {a : Multiset α} : Rel r a 0 ↔ a = 0 := by rw [rel_iff]; simp #align multiset.rel_zero_right Multiset.rel_zero_right theorem rel_cons_left {a as bs} : diff --git a/Mathlib/GroupTheory/Subsemigroup/Center.lean b/Mathlib/GroupTheory/Subsemigroup/Center.lean index dd4c15de90db2..555e6dcfd3760 100644 --- a/Mathlib/GroupTheory/Subsemigroup/Center.lean +++ b/Mathlib/GroupTheory/Subsemigroup/Center.lean @@ -56,9 +56,7 @@ structure IsMulCentral [Mul M] (z : M) : Prop where /-- associative property for right multiplication -/ right_assoc (a b : M) : (a * b) * z = a * (b * z) --- TODO: these should have explicit arguments (mathlib4#9129) -attribute [mk_iff isMulCentral_iff] IsMulCentral -attribute [mk_iff isAddCentral_iff] IsAddCentral +attribute [mk_iff] IsMulCentral IsAddCentral attribute [to_additive existing] isMulCentral_iff namespace IsMulCentral diff --git a/Mathlib/Lean/Name.lean b/Mathlib/Lean/Name.lean index f79c010c65e1f..ee2cf29cee6b7 100644 --- a/Mathlib/Lean/Name.lean +++ b/Mathlib/Lean/Name.lean @@ -55,3 +55,9 @@ def getModule (name : Name) (s := "") : Name := | .anonymous => s | .num _ _ => panic s!"panic in `getModule`: did not expect numerical name: {name}." | .str pre s => getModule pre s + +/-- Decapitalize the last component of a name. -/ +def Lean.Name.decapitalize (n : Name) : Name := + n.modifyBase fun + | .str p s => .str p s.decapitalize + | n => n diff --git a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean index 89f7d68b6c890..ceaced347eef7 100644 --- a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean +++ b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean @@ -302,7 +302,7 @@ theorem rank_submodule_le_one_iff' (s : Submodule K V) : theorem Submodule.rank_le_one_iff_isPrincipal (W : Submodule K V) : Module.rank K W ≤ 1 ↔ W.IsPrincipal := by - simp only [rank_le_one_iff, Submodule.IsPrincipal_iff, le_antisymm_iff, le_span_singleton_iff, + simp only [rank_le_one_iff, Submodule.isPrincipal_iff, le_antisymm_iff, le_span_singleton_iff, span_singleton_le_iff_mem] constructor · rintro ⟨⟨m, hm⟩, hm'⟩ diff --git a/Mathlib/Logic/Relation.lean b/Mathlib/Logic/Relation.lean index 544154eba73fb..6fcfb39847fdb 100644 --- a/Mathlib/Logic/Relation.lean +++ b/Mathlib/Logic/Relation.lean @@ -256,16 +256,15 @@ inductive ReflTransGen (r : α → α → Prop) (a : α) : α → Prop attribute [refl] ReflTransGen.refl /-- `ReflGen r`: reflexive closure of `r` -/ -@[mk_iff reflGen_iff] +@[mk_iff] inductive ReflGen (r : α → α → Prop) (a : α) : α → Prop | refl : ReflGen r a a | single {b} : r a b → ReflGen r a b #align relation.refl_gen Relation.ReflGen - #align relation.refl_gen_iff Relation.reflGen_iff /-- `TransGen r`: transitive closure of `r` -/ -@[mk_iff transGen_iff] +@[mk_iff] inductive TransGen (r : α → α → Prop) (a : α) : α → Prop | single {b} : r a b → TransGen r a b | tail {b c} : TransGen r a b → r b c → TransGen r a c diff --git a/Mathlib/Logic/UnivLE.lean b/Mathlib/Logic/UnivLE.lean index 022ac1934516c..aad869948aea4 100644 --- a/Mathlib/Logic/UnivLE.lean +++ b/Mathlib/Logic/UnivLE.lean @@ -59,5 +59,5 @@ instance univLE_of_max [UnivLE.{max u v, v}] : UnivLE.{u, v} := @UnivLE.trans un -- example (α : Type u) (β : Type v) [UnivLE.{u, v}] : Small.{v} (α → β) := inferInstance example : ¬ UnivLE.{u+1, u} := by - simp only [Small_iff, not_forall, not_exists, not_nonempty_iff] + simp only [small_iff, not_forall, not_exists, not_nonempty_iff] exact ⟨Type u, fun α => ⟨fun f => Function.not_surjective_Type.{u, u} f.symm f.symm.surjective⟩⟩ diff --git a/Mathlib/NumberTheory/Cyclotomic/Basic.lean b/Mathlib/NumberTheory/Cyclotomic/Basic.lean index 072f72e49bc12..1f07282403dca 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Basic.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Basic.lean @@ -103,18 +103,18 @@ theorem iff_adjoin_eq_top : theorem iff_singleton : IsCyclotomicExtension {n} A B ↔ (∃ r : B, IsPrimitiveRoot r n) ∧ ∀ x, x ∈ adjoin A {b : B | b ^ (n : ℕ) = 1} := - by simp [IsCyclotomicExtension_iff] + by simp [isCyclotomicExtension_iff] #align is_cyclotomic_extension.iff_singleton IsCyclotomicExtension.iff_singleton /-- If `IsCyclotomicExtension ∅ A B`, then the image of `A` in `B` equals `B`. -/ theorem empty [h : IsCyclotomicExtension ∅ A B] : (⊥ : Subalgebra A B) = ⊤ := by - simpa [Algebra.eq_top_iff, IsCyclotomicExtension_iff] using h + simpa [Algebra.eq_top_iff, isCyclotomicExtension_iff] using h #align is_cyclotomic_extension.empty IsCyclotomicExtension.empty /-- If `IsCyclotomicExtension {1} A B`, then the image of `A` in `B` equals `B`. -/ theorem singleton_one [h : IsCyclotomicExtension {1} A B] : (⊥ : Subalgebra A B) = ⊤ := Algebra.eq_top_iff.2 fun x => by - simpa [adjoin_singleton_one] using ((IsCyclotomicExtension_iff _ _ _).1 h).2 x + simpa [adjoin_singleton_one] using ((isCyclotomicExtension_iff _ _ _).1 h).2 x #align is_cyclotomic_extension.singleton_one IsCyclotomicExtension.singleton_one variable {A B} @@ -137,16 +137,16 @@ theorem trans (C : Type w) [CommRing C] [Algebra A C] [Algebra B C] [IsScalarTow (h : Function.Injective (algebraMap B C)) : IsCyclotomicExtension (S ∪ T) A C := by refine' ⟨fun hn => _, fun x => _⟩ · cases' hn with hn hn - · obtain ⟨b, hb⟩ := ((IsCyclotomicExtension_iff _ _ _).1 hS).1 hn + · obtain ⟨b, hb⟩ := ((isCyclotomicExtension_iff _ _ _).1 hS).1 hn refine' ⟨algebraMap B C b, _⟩ exact hb.map_of_injective h - · exact ((IsCyclotomicExtension_iff _ _ _).1 hT).1 hn - · refine' adjoin_induction (((IsCyclotomicExtension_iff T B _).1 hT).2 x) + · exact ((isCyclotomicExtension_iff _ _ _).1 hT).1 hn + · refine' adjoin_induction (((isCyclotomicExtension_iff T B _).1 hT).2 x) (fun c ⟨n, hn⟩ => subset_adjoin ⟨n, Or.inr hn.1, hn.2⟩) (fun b => _) (fun x y hx hy => Subalgebra.add_mem _ hx hy) fun x y hx hy => Subalgebra.mul_mem _ hx hy · let f := IsScalarTower.toAlgHom A B C have hb : f b ∈ (adjoin A {b : B | ∃ a : ℕ+, a ∈ S ∧ b ^ (a : ℕ) = 1}).map f := - ⟨b, ((IsCyclotomicExtension_iff _ _ _).1 hS).2 b, rfl⟩ + ⟨b, ((isCyclotomicExtension_iff _ _ _).1 hS).2 b, rfl⟩ rw [IsScalarTower.toAlgHom_apply, ← adjoin_image] at hb refine' adjoin_mono (fun y hy => _) hb obtain ⟨b₁, ⟨⟨n, hn⟩, h₁⟩⟩ := hy @@ -185,8 +185,8 @@ theorem union_right [h : IsCyclotomicExtension (S ∪ T) A B] : · rintro x (⟨n, hn⟩ | ⟨n, hn⟩) · exact ⟨n, Or.inl hn.1, hn.2⟩ · exact ⟨n, Or.inr hn.1, hn.2⟩ - refine' ⟨fun hn => ((IsCyclotomicExtension_iff _ A _).1 h).1 (mem_union_right S hn), fun b => _⟩ - replace h := ((IsCyclotomicExtension_iff _ _ _).1 h).2 b + refine' ⟨fun hn => ((isCyclotomicExtension_iff _ A _).1 h).1 (mem_union_right S hn), fun b => _⟩ + replace h := ((isCyclotomicExtension_iff _ _ _).1 h).2 b rwa [this, adjoin_union_eq_adjoin_adjoin, Subalgebra.mem_restrictScalars] at h #align is_cyclotomic_extension.union_right IsCyclotomicExtension.union_right @@ -196,7 +196,7 @@ given by roots of unity of order in `S`. -/ theorem union_left [h : IsCyclotomicExtension T A B] (hS : S ⊆ T) : IsCyclotomicExtension S A (adjoin A {b : B | ∃ a : ℕ+, a ∈ S ∧ b ^ (a : ℕ) = 1}) := by refine' ⟨@fun n hn => _, fun b => _⟩ - · obtain ⟨b, hb⟩ := ((IsCyclotomicExtension_iff _ _ _).1 h).1 (hS hn) + · obtain ⟨b, hb⟩ := ((isCyclotomicExtension_iff _ _ _).1 h).1 (hS hn) refine' ⟨⟨b, subset_adjoin ⟨n, hn, hb.pow_eq_one⟩⟩, _⟩ rwa [← IsPrimitiveRoot.coe_submonoidClass_iff, Subtype.coe_mk] · convert mem_top (R := A) (x := b) @@ -443,7 +443,7 @@ theorem splits_X_pow_sub_one [H : IsCyclotomicExtension S K L] (hS : n ∈ S) : Splits (algebraMap K L) (X ^ (n : ℕ) - 1) := by rw [← splits_id_iff_splits, Polynomial.map_sub, Polynomial.map_one, Polynomial.map_pow, Polynomial.map_X] - obtain ⟨z, hz⟩ := ((IsCyclotomicExtension_iff _ _ _).1 H).1 hS + obtain ⟨z, hz⟩ := ((isCyclotomicExtension_iff _ _ _).1 H).1 hS exact X_pow_sub_one_splits hz set_option linter.uppercaseLean3 false in #align is_cyclotomic_extension.splits_X_pow_sub_one IsCyclotomicExtension.splits_X_pow_sub_one diff --git a/Mathlib/Order/Atoms.lean b/Mathlib/Order/Atoms.lean index f967ed6d32a64..7ab1fbb46c5a0 100644 --- a/Mathlib/Order/Atoms.lean +++ b/Mathlib/Order/Atoms.lean @@ -265,7 +265,7 @@ class IsAtomic [OrderBot α] : Prop where /--Every element other than `⊥` has an atom below it. -/ eq_bot_or_exists_atom_le : ∀ b : α, b = ⊥ ∨ ∃ a : α, IsAtom a ∧ a ≤ b #align is_atomic IsAtomic -#align is_atomic_iff IsAtomic_iff +#align is_atomic_iff isAtomic_iff /-- A lattice is coatomic iff every element other than `⊤` has a coatom above it. -/ @[mk_iff] @@ -273,7 +273,7 @@ class IsCoatomic [OrderTop α] : Prop where /--Every element other than `⊤` has an atom above it. -/ eq_top_or_exists_le_coatom : ∀ b : α, b = ⊤ ∨ ∃ a : α, IsCoatom a ∧ b ≤ a #align is_coatomic IsCoatomic -#align is_coatomic_iff IsCoatomic_iff +#align is_coatomic_iff isCoatomic_iff export IsAtomic (eq_bot_or_exists_atom_le) @@ -915,7 +915,7 @@ theorem isSimpleOrder [BoundedOrder α] [BoundedOrder β] [h : IsSimpleOrder β] protected theorem isAtomic_iff [OrderBot α] [OrderBot β] (f : α ≃o β) : IsAtomic α ↔ IsAtomic β := by - simp only [IsAtomic_iff, f.surjective.forall, f.surjective.exists, ← map_bot f, f.eq_iff_eq, + simp only [isAtomic_iff, f.surjective.forall, f.surjective.exists, ← map_bot f, f.eq_iff_eq, f.le_iff_le, f.isAtom_iff] #align order_iso.is_atomic_iff OrderIso.isAtomic_iff diff --git a/Mathlib/Order/PrimeIdeal.lean b/Mathlib/Order/PrimeIdeal.lean index 77096ecd3fa28..9e4166566f42c 100644 --- a/Mathlib/Order/PrimeIdeal.lean +++ b/Mathlib/Order/PrimeIdeal.lean @@ -129,10 +129,10 @@ theorem IsPrime.mem_or_mem (hI : IsPrime I) {x y : P} : x ⊓ y ∈ I → x ∈ theorem IsPrime.of_mem_or_mem [IsProper I] (hI : ∀ {x y : P}, x ⊓ y ∈ I → x ∈ I ∨ y ∈ I) : IsPrime I := by - rw [IsPrime_iff] + rw [isPrime_iff] use ‹_› refine .of_def ?_ ?_ ?_ - · exact Set.nonempty_compl.2 (I.IsProper_iff.1 ‹_›) + · exact Set.nonempty_compl.2 (I.isProper_iff.1 ‹_›) · intro x hx y hy exact ⟨x ⊓ y, fun h => (hI h).elim hx hy, inf_le_left, inf_le_right⟩ · exact @mem_compl_of_ge _ _ _ @@ -195,7 +195,7 @@ theorem isPrime_iff_mem_or_compl_mem [IsProper I] : IsPrime I ↔ ∀ {x : P}, x #align order.ideal.is_prime_iff_mem_or_compl_mem Order.Ideal.isPrime_iff_mem_or_compl_mem instance (priority := 100) IsPrime.isMaximal [IsPrime I] : IsMaximal I := by - simp only [IsMaximal_iff, Set.eq_univ_iff_forall, IsPrime.toIsProper, true_and] + simp only [isMaximal_iff, Set.eq_univ_iff_forall, IsPrime.toIsProper, true_and] intro J hIJ x rcases Set.exists_of_ssubset hIJ with ⟨y, hyJ, hyI⟩ suffices ass : x ⊓ y ⊔ x ⊓ yᶜ ∈ J by rwa [sup_inf_inf_compl] at ass diff --git a/Mathlib/Order/RelClasses.lean b/Mathlib/Order/RelClasses.lean index f8b22f2e4d7cd..d6cc4a85990a6 100644 --- a/Mathlib/Order/RelClasses.lean +++ b/Mathlib/Order/RelClasses.lean @@ -276,7 +276,7 @@ instance (priority := 100) isStrictTotalOrder_of_isStrictTotalOrder [IsStrictTot /-- The relation is `WellFounded`, as a proposition. -/ wf : WellFounded r #align is_well_founded IsWellFounded -#align is_well_founded_iff IsWellFounded_iff +#align is_well_founded_iff isWellFounded_iff #align has_well_founded WellFoundedRelation set_option linter.uppercaseLean3 false in diff --git a/Mathlib/RingTheory/Etale.lean b/Mathlib/RingTheory/Etale.lean index d6ba0d8dbd727..69ff6654b6149 100644 --- a/Mathlib/RingTheory/Etale.lean +++ b/Mathlib/RingTheory/Etale.lean @@ -71,9 +71,8 @@ variable {R A} theorem FormallyEtale.iff_unramified_and_smooth : FormallyEtale R A ↔ FormallyUnramified R A ∧ FormallySmooth R A := by - rw [FormallyUnramified_iff, FormallySmooth_iff, FormallyEtale_iff] - simp_rw [← forall_and] - rfl + rw [formallyUnramified_iff, formallySmooth_iff, formallyEtale_iff] + simp_rw [← forall_and, Function.Bijective] #align algebra.formally_etale.iff_unramified_and_smooth Algebra.FormallyEtale.iff_unramified_and_smooth instance (priority := 100) FormallyEtale.to_unramified [h : FormallyEtale R A] : diff --git a/Mathlib/RingTheory/Ideal/Cotangent.lean b/Mathlib/RingTheory/Ideal/Cotangent.lean index 981529c976a68..0a447594eab0a 100644 --- a/Mathlib/RingTheory/Ideal/Cotangent.lean +++ b/Mathlib/RingTheory/Ideal/Cotangent.lean @@ -252,8 +252,8 @@ lemma finrank_cotangentSpace_eq_zero (R) [Field R] : open Submodule in theorem finrank_cotangentSpace_le_one_iff [IsNoetherianRing R] : finrank (ResidueField R) (CotangentSpace R) ≤ 1 ↔ (maximalIdeal R).IsPrincipal := by - rw [Module.finrank_le_one_iff_top_isPrincipal, IsPrincipal_iff, - (maximalIdeal R).toCotangent_surjective.exists, IsPrincipal_iff] + rw [Module.finrank_le_one_iff_top_isPrincipal, isPrincipal_iff, + (maximalIdeal R).toCotangent_surjective.exists, isPrincipal_iff] simp_rw [← Set.image_singleton, eq_comm (a := ⊤), CotangentSpace.span_image_eq_top_iff, ← (map_injective_of_injective (injective_subtype _)).eq_iff, map_span, Set.image_singleton, Submodule.map_top, range_subtype, eq_comm (a := maximalIdeal R)] diff --git a/Mathlib/RingTheory/Nilpotent.lean b/Mathlib/RingTheory/Nilpotent.lean index d2a26a7c3269b..afa8f15e32a98 100644 --- a/Mathlib/RingTheory/Nilpotent.lean +++ b/Mathlib/RingTheory/Nilpotent.lean @@ -122,7 +122,7 @@ theorem Commute.IsNilpotent.add_isUnit [Ring R] {r : R} {u : Rˣ} (hnil : IsNilp simp /-- A structure that has zero and pow is reduced if it has no nonzero nilpotent elements. -/ -@[mk_iff isReduced_iff] +@[mk_iff] class IsReduced (R : Type*) [Zero R] [Pow R ℕ] : Prop where /-- A reduced structure has no nonzero nilpotent elements. -/ eq_zero : ∀ x : R, IsNilpotent x → x = 0 diff --git a/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean b/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean index 6c91a6536646e..697588e732457 100644 --- a/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean @@ -64,7 +64,7 @@ variable [CommSemiring R] {𝓟 : Ideal R} {f : R[X]} (hf : f.IsWeaklyEisenstein theorem map {A : Type v} [CommRing A] (φ : R →+* A) : (f.map φ).IsWeaklyEisensteinAt (𝓟.map φ) := by - refine' (IsWeaklyEisensteinAt_iff _ _).2 fun hn => _ + refine' (isWeaklyEisensteinAt_iff _ _).2 fun hn => _ rw [coeff_map] exact mem_map_of_mem _ (hf.mem (lt_of_lt_of_le hn (natDegree_map_le _ _))) #align polynomial.is_weakly_eisenstein_at.map Polynomial.IsWeaklyEisensteinAt.map diff --git a/Mathlib/RingTheory/PrincipalIdealDomain.lean b/Mathlib/RingTheory/PrincipalIdealDomain.lean index d5b05d9da86d0..3a1dbeaa435c4 100644 --- a/Mathlib/RingTheory/PrincipalIdealDomain.lean +++ b/Mathlib/RingTheory/PrincipalIdealDomain.lean @@ -69,7 +69,7 @@ instance top_isPrincipal : (⊤ : Submodule R R).IsPrincipal := variable (R) /-- A ring is a principal ideal ring if all (left) ideals are principal. -/ -@[mk_iff isPrincipalIdealRing_iff] +@[mk_iff] class IsPrincipalIdealRing (R : Type u) [Ring R] : Prop where principal : ∀ S : Ideal R, S.IsPrincipal #align is_principal_ideal_ring IsPrincipalIdealRing diff --git a/Mathlib/SetTheory/Game/PGame.lean b/Mathlib/SetTheory/Game/PGame.lean index 3695f3b348232..03db93db84227 100644 --- a/Mathlib/SetTheory/Game/PGame.lean +++ b/Mathlib/SetTheory/Game/PGame.lean @@ -1256,7 +1256,7 @@ theorem neg_ofLists (L R : List PGame) : #align pgame.neg_of_lists SetTheory.PGame.neg_ofLists theorem isOption_neg {x y : PGame} : IsOption x (-y) ↔ IsOption (-x) y := by - rw [IsOption_iff, IsOption_iff, or_comm] + rw [isOption_iff, isOption_iff, or_comm] cases y; apply or_congr <;> · apply exists_congr diff --git a/Mathlib/Tactic/MkIffOfInductiveProp.lean b/Mathlib/Tactic/MkIffOfInductiveProp.lean index c28374a2d10db..6efae87acb7bc 100644 --- a/Mathlib/Tactic/MkIffOfInductiveProp.lean +++ b/Mathlib/Tactic/MkIffOfInductiveProp.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl, David Renshaw import Lean import Std.Tactic.LeftRight import Mathlib.Lean.Meta +import Mathlib.Lean.Name import Mathlib.Tactic.Basic /-! @@ -17,20 +18,18 @@ the following type: ```lean ∀ {α : Type*} (R : α → α → Prop) (a : α) (l : List α), - Chain R a l ↔ l = [] ∨ ∃(b : α) (l' : List α), R a b ∧ Chain R b l ∧ l = b :: l' + Chain R a l ↔ l = [] ∨ ∃ (b : α) (l' : List α), R a b ∧ Chain R b l ∧ l = b :: l' ``` This tactic can be called using either the `mk_iff_of_inductive_prop` user command or the `mk_iff` attribute. -/ -set_option autoImplicit true - namespace Mathlib.Tactic.MkIff open Lean Meta Elab -/-- `select m n` runs `right` `m` times, and then `left` `(n-m)` times. +/-- `select m n` runs `right` `m` times; if `m < n`, then it also runs `left` once. Fails if `n < m`. -/ private def select (m n : Nat) (goal : MVarId) : MetaM MVarId := match m,n with @@ -47,7 +46,7 @@ private def select (m n : Nat) (goal : MVarId) : MetaM MVarId := /-- `compactRelation bs as_ps`: Produce a relation of the form: ```lean -R := λ as ∃ bs, Λ_i a_i = p_i[bs] +R := fun as ↦ ∃ bs, ⋀_i a_i = p_i[bs] ``` This relation is user-visible, so we compact it by removing each `b_j` where a `p_i = b_j`, and hence `a_i = b_j`. We need to take care when there are `p_i` and `p_j` with `p_i = p_j = b_k`. @@ -56,13 +55,14 @@ partial def compactRelation : List Expr → List (Expr × Expr) → List (Option Expr) × List (Expr × Expr) × (Expr → Expr) | [], as_ps => ([], as_ps, id) | b::bs, as_ps => - match as_ps.span (λ⟨_,p⟩ => ¬ p == b) with + match as_ps.span (fun ⟨_, p⟩ ↦ p != b) with | (_, []) => -- found nothing in ps equal to b - let (bs, as_ps', subst) := compactRelation bs as_ps - (b::bs, as_ps', subst) + let (bs, as_ps', subst) := compactRelation bs as_ps + (b::bs, as_ps', subst) | (ps₁, (a, _) :: ps₂) => -- found one that matches b. Remove it. let i := fun e ↦ e.replaceFVar b a - let (bs, as_ps', subst) := compactRelation (bs.map i) ((ps₁ ++ ps₂).map (λ⟨a, p⟩ => (a, i p))) + let (bs, as_ps', subst) := + compactRelation (bs.map i) ((ps₁ ++ ps₂).map (fun ⟨a, p⟩ ↦ (a, i p))) (none :: bs, as_ps', i ∘ subst) private def updateLambdaBinderInfoD! (e : Expr) : Expr := @@ -70,24 +70,25 @@ private def updateLambdaBinderInfoD! (e : Expr) : Expr := | .lam n domain body _ => .lam n domain body .default | _ => panic! "lambda expected" -/-- Generates an expression of the form `∃(args), inner`. `args` is assumed to be a list of fvars. -When possible, `p ∧ q` is used instead of `∃(_ : p), q`. -/ +/-- Generates an expression of the form `∃ (args), inner`. `args` is assumed to be a list of fvars. +When possible, `p ∧ q` is used instead of `∃ (_ : p), q`. -/ def mkExistsList (args : List Expr) (inner : Expr) : MetaM Expr := -args.foldrM (λarg i:Expr => do - let t ← inferType arg - let l := (← inferType t).sortLevel! - if arg.occurs i || l != Level.zero - then pure (mkApp2 (mkConst `Exists [l] : Expr) t - (updateLambdaBinderInfoD! <| ← mkLambdaFVars #[arg] i)) - else pure <| mkApp2 (mkConst `And [] : Expr) t i) - inner + args.foldrM + (fun arg i:Expr => do + let t ← inferType arg + let l := (← inferType t).sortLevel! + if arg.occurs i || l != Level.zero + then pure (mkApp2 (.const `Exists [l]) t + (updateLambdaBinderInfoD! <| ← mkLambdaFVars #[arg] i)) + else pure <| mkApp2 (mkConst `And) t i) + inner /-- `mkOpList op empty [x1, x2, ...]` is defined as `op x1 (op x2 ...)`. Returns `empty` if the list is empty. -/ def mkOpList (op : Expr) (empty : Expr) : List Expr → Expr | [] => empty | [e] => e - | (e :: es) => mkApp2 op e $ mkOpList op empty es + | (e :: es) => mkApp2 op e <| mkOpList op empty es /-- `mkAndList [x1, x2, ...]` is defined as `x1 ∧ (x2 ∧ ...)`, or `True` if the list is empty. -/ def mkAndList : List Expr → Expr := mkOpList (mkConst `And) (mkConst `True) @@ -96,7 +97,7 @@ def mkAndList : List Expr → Expr := mkOpList (mkConst `And) (mkConst `True) def mkOrList : List Expr → Expr := mkOpList (mkConst `Or) (mkConst `False) /-- Drops the final element of a list. -/ -def List.init : List α → List α +def List.init {α : Type*} : List α → List α | [] => [] | [_] => [] | a::l => a::init l @@ -120,7 +121,7 @@ structure Shape : Type where ∀ {α : Type u_1} {R : α → α → Prop} {a b : α} {l : List α}, R a b → List.Chain R b l → List.Chain R a (b :: l) ``` - and the `a : α` gets eliminated, so `compactRelation = [false,true,true,true,true]`. + and the `a : α` gets eliminated, so `variablesKept = [false,true,true,true,true]`. -/ variablesKept : List Bool @@ -133,37 +134,36 @@ structure Shape : Type where while proving the iff theorem, and a proposition representing the constructor. -/ def constrToProp (univs : List Level) (params : List Expr) (idxs : List Expr) (c : Name) : - MetaM (Shape × Expr) := -do let type := (← getConstInfo c).instantiateTypeLevelParams univs - let type' ← Meta.forallBoundedTelescope type (params.length) fun fvars ty ↦ do - pure $ ty.replaceFVars fvars params.toArray - - Meta.forallTelescope type' fun fvars ty ↦ do - let idxs_inst := ty.getAppArgs.toList.drop params.length - let (bs, eqs, subst) := compactRelation fvars.toList (idxs.zip idxs_inst) - let eqs ← eqs.mapM (λ⟨idx, inst⟩ => do - let ty ← idx.fvarId!.getType - let instTy ← inferType inst - let u := (← inferType ty).sortLevel! - if ← isDefEq ty instTy - then pure (mkApp3 (mkConst `Eq [u]) ty idx inst) - else pure (mkApp4 (mkConst `HEq [u]) ty idx instTy inst)) - let (n, r) ← match bs.filterMap id, eqs with - | [], [] => do - pure (some 0, (mkConst `True)) - | bs', [] => do - let t : Expr ← bs'.getLast!.fvarId!.getType - let l := (← inferType t).sortLevel! - if l == Level.zero then do - let r ← mkExistsList (List.init bs') t - pure (none, subst r) - else do - let r ← mkExistsList bs' (mkConst `True) - pure (some 0, subst r) - | bs', _ => do - let r ← mkExistsList bs' (mkAndList eqs) - pure (some eqs.length, subst r) - pure (⟨bs.map Option.isSome, n⟩, r) + MetaM (Shape × Expr) := do + let type := (← getConstInfo c).instantiateTypeLevelParams univs + let type' ← Meta.forallBoundedTelescope type (params.length) fun fvars ty ↦ do + pure <| ty.replaceFVars fvars params.toArray + Meta.forallTelescope type' fun fvars ty ↦ do + let idxs_inst := ty.getAppArgs.toList.drop params.length + let (bs, eqs, subst) := compactRelation fvars.toList (idxs.zip idxs_inst) + let eqs ← eqs.mapM (fun ⟨idx, inst⟩ ↦ do + let ty ← idx.fvarId!.getType + let instTy ← inferType inst + let u := (← inferType ty).sortLevel! + if ← isDefEq ty instTy + then pure (mkApp3 (.const `Eq [u]) ty idx inst) + else pure (mkApp4 (.const `HEq [u]) ty idx instTy inst)) + let (n, r) ← match bs.filterMap id, eqs with + | [], [] => do + pure (some 0, (mkConst `True)) + | bs', [] => do + let t : Expr ← bs'.getLast!.fvarId!.getType + let l := (← inferType t).sortLevel! + if l == Level.zero then do + let r ← mkExistsList (List.init bs') t + pure (none, subst r) + else do + let r ← mkExistsList bs' (mkConst `True) + pure (some 0, subst r) + | bs', _ => do + let r ← mkExistsList bs' (mkAndList eqs) + pure (some eqs.length, subst r) + pure (⟨bs.map Option.isSome, n⟩, r) /-- Splits the goal `n` times via `refine ⟨?_,?_⟩`, and then applies `constructor` to close the resulting subgoals. @@ -171,15 +171,15 @@ close the resulting subgoals. def splitThenConstructor (mvar : MVarId) (n : Nat) : MetaM Unit := match n with | 0 => do - let (subgoals',_) ← Term.TermElabM.run $ Tactic.run mvar do + let (subgoals',_) ← Term.TermElabM.run <| Tactic.run mvar do Tactic.evalTactic (← `(tactic| constructor)) let [] := subgoals' | throwError "expected no subgoals" pure () | n + 1 => do - let (subgoals,_) ← Term.TermElabM.run $ Tactic.run mvar do + let (subgoals,_) ← Term.TermElabM.run <| Tactic.run mvar do Tactic.evalTactic (← `(tactic| refine ⟨?_,?_⟩)) let [sg1, sg2] := subgoals | throwError "expected two subgoals" - let (subgoals',_) ← Term.TermElabM.run $ Tactic.run sg1 do + let (subgoals',_) ← Term.TermElabM.run <| Tactic.run sg1 do Tactic.evalTactic (← `(tactic| constructor)) let [] := subgoals' | throwError "expected no subgoals" splitThenConstructor sg2 n @@ -193,7 +193,7 @@ do let subgoals ← mvar'.cases h let _ ← (shape.zip subgoals.toList).enum.mapM fun ⟨p, ⟨⟨shape, t⟩, subgoal⟩⟩ ↦ do let vars := subgoal.fields - let si := (shape.zip vars.toList).filterMap (λ ⟨c,v⟩ => if c then some v else none) + let si := (shape.zip vars.toList).filterMap (fun ⟨c,v⟩ ↦ if c then some v else none) let mvar'' ← select p (subgoals.size - 1) subgoal.mvarId match t with | none => do @@ -256,7 +256,7 @@ def toInductive (mvar : MVarId) (cs : List Name) pure () | (n + 1) => do let subgoals ← nCasesSum n mvar h - let _ ← (cs.zip (subgoals.zip s)).mapM $ λ⟨constr_name, ⟨h, mv⟩, bs, e⟩ => do + let _ ← (cs.zip (subgoals.zip s)).mapM fun ⟨constr_name, ⟨h, mv⟩, bs, e⟩ ↦ do let n := (bs.filter id).length let (mvar', _fvars) ← match e with | none => nCasesProd (n-1) mv h @@ -272,18 +272,17 @@ def toInductive (mvar : MVarId) (cs : List Name) `subst` will change the dependent hypotheses, so that the `uniq` local names are wrong afterwards. Instead we revert them and pull them out one-by-one. -/ let (_, mv3) ← mv2.revert fvars'.toArray - let mv4 ← fvars'.foldlM (λ mv _ => do let ⟨fv, mv'⟩ ← mv.intro1 - subst mv' fv - ) mv3 + let mv4 ← fvars'.foldlM (fun mv _ ↦ do let ⟨fv, mv'⟩ ← mv.intro1; subst mv' fv) mv3 pure (mv4, fvars) mvar'.withContext do let fvarIds := (← getLCtx).getFVarIds.toList let gs := fvarIds.take gs.length let hs := (fvarIds.reverse.take n).reverse let m := gs.map some ++ listBoolMerge bs hs - let args ← m.mapM (λa => match a with - | some v => pure $ mkFVar v - | none => mkFreshExprMVar none) + let args ← m.mapM fun a ↦ + match a with + | some v => pure (mkFVar v) + | none => mkFreshExprMVar none let c ← mkConstWithFreshMVarLevels constr_name let e := mkAppN c args.toArray let t ← inferType e @@ -305,14 +304,13 @@ def mkIffOfInductivePropImpl (ind : Name) (rel : Name) (relStx : Syntax) : MetaM /- we use these names for our universe parameters, maybe we should construct a copy of them using `uniq_name` -/ - let (thmTy,shape) ← Meta.forallTelescope type fun fvars ty ↦ do + let (thmTy, shape) ← Meta.forallTelescope type fun fvars ty ↦ do if !ty.isProp then throwError "mk_iff only applies to prop-valued declarations" let lhs := mkAppN (mkConst ind univs) fvars let fvars' := fvars.toList let shape_rhss ← constrs.mapM (constrToProp univs (fvars'.take params) (fvars'.drop params)) let (shape, rhss) := shape_rhss.unzip - pure (← mkForallFVars fvars (mkApp2 (mkConst `Iff) lhs (mkOrList rhss)), - shape) + pure (← mkForallFVars fvars (mkApp2 (mkConst `Iff) lhs (mkOrList rhss)), shape) let mvar ← mkFreshExprMVar (some thmTy) let mvarId := mvar.mvarId! @@ -324,7 +322,7 @@ def mkIffOfInductivePropImpl (ind : Name) (rel : Name) (relStx : Syntax) : MetaM let ⟨mprFvar, mpr'⟩ ← mpr.intro1 toInductive mpr' constrs ((fvars.toList.take params).map .fvar) shape mprFvar - addDecl $ .thmDecl { + addDecl <| .thmDecl { name := rel levelParams := univNames type := thmTy @@ -410,7 +408,7 @@ initialize Lean.registerBuiltinAttribute { let (tgt, idStx) ← match stx with | `(attr| mk_iff $tgt:ident) => pure ((← mkDeclName (← getCurrNamespace) {} tgt.getId).1, tgt.raw) - | `(attr| mk_iff) => pure (decl.appendAfter "_iff", stx) + | `(attr| mk_iff) => pure (decl.decapitalize.appendAfter "_iff", stx) | _ => throwError "unrecognized syntax" mkIffOfInductivePropImpl decl tgt idStx } diff --git a/Mathlib/Topology/Bases.lean b/Mathlib/Topology/Bases.lean index 7cd5f90c3210d..552be4211a378 100644 --- a/Mathlib/Topology/Bases.lean +++ b/Mathlib/Topology/Bases.lean @@ -411,7 +411,7 @@ instance [SeparableSpace α] {s : Setoid α} : SeparableSpace (Quotient s) := /-- A topological space with discrete topology is separable iff it is countable. -/ theorem separableSpace_iff_countable [DiscreteTopology α] : SeparableSpace α ↔ Countable α := by - simp [SeparableSpace_iff, countable_univ_iff] + simp [separableSpace_iff, countable_univ_iff] /-- In a separable space, a family of nonempty disjoint open sets is countable. -/ theorem _root_.Set.PairwiseDisjoint.countable_of_isOpen [SeparableSpace α] {ι : Type*} diff --git a/Mathlib/Topology/CompletelyRegular.lean b/Mathlib/Topology/CompletelyRegular.lean index 54bbdfd4a5b76..2d3a61b59fe76 100644 --- a/Mathlib/Topology/CompletelyRegular.lean +++ b/Mathlib/Topology/CompletelyRegular.lean @@ -57,7 +57,7 @@ variable {X : Type u} [TopologicalSpace X] [T1Space X] /-- A space is completely regular if points can be separated from closed sets via continuous functions to the unit interval. -/ -@[mk_iff completelyRegularSpace_iff] +@[mk_iff] class CompletelyRegularSpace (X : Type u) [TopologicalSpace X] : Prop where completely_regular : ∀ (x : X), ∀ K : Set X, IsClosed K → x ∉ K → ∃ f : X → I, Continuous f ∧ f x = 0 ∧ EqOn f 1 K @@ -83,7 +83,7 @@ instance NormalSpace.instCompletelyRegularSpace [NormalSpace X] : CompletelyRegu exact ⟨g, cg, hgx, hgK⟩ /-- A T₃.₅ space is a completely regular space that is also T1. -/ -@[mk_iff t35Space_iff] +@[mk_iff] class T35Space (X : Type u) [TopologicalSpace X] extends T1Space X, CompletelyRegularSpace X : Prop instance T35Space.instT3space [T35Space X] : T3Space X := by diff --git a/Mathlib/Topology/Connected/TotallyDisconnected.lean b/Mathlib/Topology/Connected/TotallyDisconnected.lean index 850230f42c47c..db4bc6f348fdb 100644 --- a/Mathlib/Topology/Connected/TotallyDisconnected.lean +++ b/Mathlib/Topology/Connected/TotallyDisconnected.lean @@ -170,7 +170,7 @@ lemma Embedding.isTotallyDisconnected_image [TopologicalSpace β] {f : α → β lemma Embedding.isTotallyDisconnected_range [TopologicalSpace β] {f : α → β} (hf : Embedding f) : IsTotallyDisconnected (range f) ↔ TotallyDisconnectedSpace α := by - rw [TotallyDisconnectedSpace_iff, ← image_univ, hf.isTotallyDisconnected_image] + rw [totallyDisconnectedSpace_iff, ← image_univ, hf.isTotallyDisconnected_image] lemma totallyDisconnectedSpace_subtype_iff {s : Set α} : TotallyDisconnectedSpace s ↔ IsTotallyDisconnected s := by diff --git a/Mathlib/Topology/FiberBundle/Basic.lean b/Mathlib/Topology/FiberBundle/Basic.lean index 7a7b1ea958d91..b251e404f5359 100644 --- a/Mathlib/Topology/FiberBundle/Basic.lean +++ b/Mathlib/Topology/FiberBundle/Basic.lean @@ -216,7 +216,7 @@ for trivializations of `E`, expressing that a trivialization is in the designate bundle. This is needed because lemmas about the linearity of trivializations or the continuity (as functions to `F →L[R] F`, where `F` is the model fiber) of the transition functions are only expected to hold for trivializations in the designated atlas. -/ -@[mk_iff memTrivializationAtlas_iff] +@[mk_iff] class MemTrivializationAtlas [FiberBundle F E] (e : Trivialization F (π F E)) : Prop where out : e ∈ trivializationAtlas F E #align mem_trivialization_atlas MemTrivializationAtlas diff --git a/Mathlib/Topology/Maps.lean b/Mathlib/Topology/Maps.lean index 4eb13edccc84d..8929f76e94585 100644 --- a/Mathlib/Topology/Maps.lean +++ b/Mathlib/Topology/Maps.lean @@ -56,7 +56,7 @@ section Inducing /-- A function `f : α → β` between topological spaces is inducing if the topology on `α` is induced by the topology on `β` through `f`, meaning that a set `s : Set α` is open iff it is the preimage under `f` of some open set `t : Set β`. -/ -@[mk_iff inducing_iff] +@[mk_iff] structure Inducing [tα : TopologicalSpace α] [tβ : TopologicalSpace β] (f : α → β) : Prop where /-- The topology on the domain is equal to the induced topology. -/ induced : tα = tβ.induced f @@ -187,7 +187,7 @@ section Embedding /-- A function between topological spaces is an embedding if it is injective, and for all `s : Set α`, `s` is open iff it is the preimage of an open set. -/ -@[mk_iff embedding_iff] +@[mk_iff] structure Embedding [TopologicalSpace α] [TopologicalSpace β] (f : α → β) extends Inducing f : Prop where /-- A topological embedding is injective. -/ @@ -571,7 +571,7 @@ section OpenEmbedding variable [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] /-- An open embedding is an embedding with open image. -/ -@[mk_iff openEmbedding_iff] +@[mk_iff] structure OpenEmbedding (f : α → β) extends Embedding f : Prop where /-- The range of an open embedding is an open set. -/ open_range : IsOpen <| range f @@ -677,7 +677,7 @@ section ClosedEmbedding variable [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] /-- A closed embedding is an embedding with closed image. -/ -@[mk_iff closedEmbedding_iff] +@[mk_iff] structure ClosedEmbedding (f : α → β) extends Embedding f : Prop where /-- The range of a closed embedding is a closed set. -/ closed_range : IsClosed <| range f diff --git a/Mathlib/Topology/NoetherianSpace.lean b/Mathlib/Topology/NoetherianSpace.lean index b2af7c38c7dc0..9bc598546cb29 100644 --- a/Mathlib/Topology/NoetherianSpace.lean +++ b/Mathlib/Topology/NoetherianSpace.lean @@ -45,7 +45,7 @@ variable (α β : Type*) [TopologicalSpace α] [TopologicalSpace β] namespace TopologicalSpace /-- Type class for noetherian spaces. It is defined to be spaces whose open sets satisfies ACC. -/ -@[mk_iff noetherianSpace_iff] +@[mk_iff] class NoetherianSpace : Prop where wellFounded_opens : WellFounded ((· > ·) : Opens α → Opens α → Prop) #align topological_space.noetherian_space TopologicalSpace.NoetherianSpace diff --git a/Mathlib/Topology/QuasiSeparated.lean b/Mathlib/Topology/QuasiSeparated.lean index 8394b101eeca5..467f3dad7a4d1 100644 --- a/Mathlib/Topology/QuasiSeparated.lean +++ b/Mathlib/Topology/QuasiSeparated.lean @@ -43,7 +43,6 @@ def IsQuasiSeparated (s : Set α) : Prop := /-- A topological space is quasi-separated if the intersections of any pairs of compact open subsets are still compact. -/ --- Porting note: mk_iff currently generates `QuasiSeparatedSpace_iff`. Undesirable capitalization? @[mk_iff] class QuasiSeparatedSpace (α : Type*) [TopologicalSpace α] : Prop where /-- The intersection of two open compact subsets of a quasi-separated space is compact.-/ @@ -53,7 +52,7 @@ class QuasiSeparatedSpace (α : Type*) [TopologicalSpace α] : Prop where theorem isQuasiSeparated_univ_iff {α : Type*} [TopologicalSpace α] : IsQuasiSeparated (Set.univ : Set α) ↔ QuasiSeparatedSpace α := by - rw [QuasiSeparatedSpace_iff] + rw [quasiSeparatedSpace_iff] simp [IsQuasiSeparated] #align is_quasi_separated_univ_iff isQuasiSeparated_univ_iff diff --git a/Mathlib/Topology/Separation.lean b/Mathlib/Topology/Separation.lean index 66319310d70d6..f48b19e899032 100644 --- a/Mathlib/Topology/Separation.lean +++ b/Mathlib/Topology/Separation.lean @@ -916,7 +916,7 @@ theorem TopologicalSpace.subset_trans {s t : Set X} (ts : t ⊆ s) : /-- A T₂ space, also known as a Hausdorff space, is one in which for every `x ≠ y` there exists disjoint open sets around `x` and `y`. This is the most widely used of the separation axioms. -/ -@[mk_iff t2Space_iff] +@[mk_iff] class T2Space (X : Type u) [TopologicalSpace X] : Prop where /-- Every two points in a Hausdorff space admit disjoint open neighbourhoods. -/ t2 : Pairwise fun x y => ∃ u v : Set X, IsOpen u ∧ IsOpen v ∧ x ∈ u ∧ y ∈ v ∧ Disjoint u v @@ -1568,7 +1568,7 @@ section RegularSpace /-- A topological space is called a *regular space* if for any closed set `s` and `a ∉ s`, there exist disjoint open sets `U ⊇ s` and `V ∋ a`. We formulate this condition in terms of `Disjoint`ness of filters `𝓝ˢ s` and `𝓝 a`. -/ -@[mk_iff regularSpace_iff] +@[mk_iff] class RegularSpace (X : Type u) [TopologicalSpace X] : Prop where /-- If `a` is a point that does not belong to a closed set `s`, then `a` and `s` admit disjoint neighborhoods. -/ diff --git a/Mathlib/Topology/Sequences.lean b/Mathlib/Topology/Sequences.lean index 89c87c6a4a56c..ed829d43e719e 100644 --- a/Mathlib/Topology/Sequences.lean +++ b/Mathlib/Topology/Sequences.lean @@ -255,7 +255,7 @@ def IsSeqCompact (s : Set X) := /-- A space `X` is sequentially compact if every sequence in `X` has a converging subsequence. -/ -@[mk_iff seqCompactSpace_iff] +@[mk_iff] class SeqCompactSpace (X : Type*) [TopologicalSpace X] : Prop where seq_compact_univ : IsSeqCompact (univ : Set X) #align seq_compact_space SeqCompactSpace diff --git a/Mathlib/Topology/Sober.lean b/Mathlib/Topology/Sober.lean index db367bd092239..efc29ef2d7623 100644 --- a/Mathlib/Topology/Sober.lean +++ b/Mathlib/Topology/Sober.lean @@ -116,7 +116,7 @@ end genericPoint section Sober /-- A space is sober if every irreducible closed subset has a generic point. -/ -@[mk_iff quasiSober_iff] +@[mk_iff] class QuasiSober (α : Type*) [TopologicalSpace α] : Prop where sober : ∀ {S : Set α}, IsIrreducible S → IsClosed S → ∃ x, IsGenericPoint x S #align quasi_sober QuasiSober diff --git a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean index 71243a4599240..98ed716fff993 100644 --- a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean +++ b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean @@ -30,7 +30,7 @@ variable {α : Type u} {β : Type v} {γ : Type w} [UniformSpace α] [UniformSpa /-- A map `f : α → β` between uniform spaces is called *uniform inducing* if the uniformity filter on `α` is the pullback of the uniformity filter on `β` under `Prod.map f f`. If `α` is a separated space, then this implies that `f` is injective, hence it is a `UniformEmbedding`. -/ -@[mk_iff uniformInducing_iff] +@[mk_iff] structure UniformInducing (f : α → β) : Prop where /-- The uniformity filter on the domain is the pullback of the uniformity filter on the codomain under `Prod.map f f`. -/ @@ -131,7 +131,7 @@ protected theorem UniformInducing.injective [T0Space α] {f : α → β} (h : Un /-- A map `f : α → β` between uniform spaces is a *uniform embedding* if it is uniform inducing and injective. If `α` is a separated space, then the latter assumption follows from the former. -/ -@[mk_iff uniformEmbedding_iff] +@[mk_iff] structure UniformEmbedding (f : α → β) extends UniformInducing f : Prop where /-- A uniform embedding is injective. -/ inj : Function.Injective f diff --git a/test/MkIffOfInductive.lean b/test/MkIffOfInductive.lean index fee05d654b82c..fe6972aa3ca46 100644 --- a/test/MkIffOfInductive.lean +++ b/test/MkIffOfInductive.lean @@ -79,4 +79,4 @@ inductive ReflTransGen {α : Type _} (r : α → α → Prop) (a : α) : α → example {α : Type} (r: α → α → Prop) (a c : α) : ReflTransGen r a c ↔ c = a ∨ ∃ b : α, ReflTransGen r a b ∧ r b c := - ReflTransGen_iff r a c + reflTransGen_iff r a c From 3a5d9146a6079f13950c0dc02d07c365d7785843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Mon, 1 Jan 2024 21:12:38 +0000 Subject: [PATCH 300/353] feat(Algebra/Homology): right shifting cochains (#8937) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR, we study the behaviour of cochains (of the complex of homomorphisms) with respect to shifts (on the target). In particular, we obtain an additive equivalence `rightShiftAddEquiv K L n a n' h : Cochain K L n ≃+ Cochain K L⟦a⟧ n'` when `n' + a = n`. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- Mathlib.lean | 1 + .../HomotopyCategory/HomComplexShift.lean | 232 ++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 Mathlib/Algebra/Homology/HomotopyCategory/HomComplexShift.lean diff --git a/Mathlib.lean b/Mathlib.lean index 4d2803ffe58ed..89294635c5aa6 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -246,6 +246,7 @@ import Mathlib.Algebra.Homology.HomologySequence import Mathlib.Algebra.Homology.Homotopy import Mathlib.Algebra.Homology.HomotopyCategory import Mathlib.Algebra.Homology.HomotopyCategory.HomComplex +import Mathlib.Algebra.Homology.HomotopyCategory.HomComplexShift import Mathlib.Algebra.Homology.HomotopyCategory.Shift import Mathlib.Algebra.Homology.HomotopyCofiber import Mathlib.Algebra.Homology.ImageToKernel diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexShift.lean b/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexShift.lean new file mode 100644 index 0000000000000..12d6df70373be --- /dev/null +++ b/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexShift.lean @@ -0,0 +1,232 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.Algebra.Homology.HomotopyCategory.HomComplex +import Mathlib.Algebra.Homology.HomotopyCategory.Shift + +/-! Shifting cochains + +Let `C` be a preadditive category. Given two cochain complexes (indexed by `ℤ`), +the type of cochains `HomComplex.Cochain K L n` of degree `n` was introduced +in `Mathlib.Algebra.Homology.HomotopyCategory.HomComplex`. In this file, we +study how these cochains behave with respect to the shift on the complexes `K` +and `L`. + +When `n`, `a`, `n'` are integers such that `h : n' + a = n`, +we obtain `rightShiftAddEquiv K L n a n' h : Cochain K L n ≃+ Cochain K L⟦a⟧ n'`. +This definition does not involve signs, but the analogous definition for +the shift on the first variable `K` shall involve signs (TODO), as we follow the +conventions appearing in the introduction of +[Brian Conrad's book *Grothendieck duality and base change*][conrad2000]. + +## References +* [Brian Conrad, Grothendieck duality and base change][conrad2000] + +-/ + +open CategoryTheory Category Limits Preadditive + +universe v u + +variable {C : Type u} [Category.{v} C] [Preadditive C] {R : Type*} [Ring R] [Linear R C] + {K L M : CochainComplex C ℤ} {n : ℤ} + +namespace CochainComplex.HomComplex + +namespace Cochain + +variable (γ γ₁ γ₂ : Cochain K L n) + +/-- The map `Cochain K L n → Cochain K (L⟦a⟧) n'` when `n' + a = n`. -/ +def rightShift (a n' : ℤ) (hn' : n' + a = n) : Cochain K (L⟦a⟧) n' := + Cochain.mk (fun p q hpq => γ.v p (p + n) rfl ≫ + (L.shiftFunctorObjXIso a q (p + n) (by linarith)).inv) + +lemma rightShift_v (a n' : ℤ) (hn' : n' + a = n) (p q : ℤ) (hpq : p + n' = q) + (p' : ℤ) (hp' : p + n = p') : + (γ.rightShift a n' hn').v p q hpq = γ.v p p' hp' ≫ + (L.shiftFunctorObjXIso a q p' (by rw [← hp', ← hpq, ← hn', add_assoc])).inv := by + subst hp' + dsimp only [rightShift] + simp only [mk_v] + +/-- The map `Cochain K (L⟦a⟧) n' → Cochain K L n` when `n' + a = n`. -/ +def rightUnshift {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) : + Cochain K L n := + Cochain.mk (fun p q hpq => γ.v p (p + n') rfl ≫ + (L.shiftFunctorObjXIso a (p + n') q (by rw [← hpq, add_assoc, hn])).hom) + +lemma rightUnshift_v {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) + (p q : ℤ) (hpq : p + n = q) (p' : ℤ) (hp' : p + n' = p') : + (γ.rightUnshift n hn).v p q hpq = γ.v p p' hp' ≫ + (L.shiftFunctorObjXIso a p' q (by rw [← hpq, ← hn, ← add_assoc, hp'])).hom := by + subst hp' + dsimp only [rightUnshift] + simp only [mk_v] + +@[simp] +lemma rightUnshift_rightShift (a n' : ℤ) (hn' : n' + a = n) : + (γ.rightShift a n' hn').rightUnshift n hn' = γ := by + ext p q hpq + simp only [rightUnshift_v _ n hn' p q hpq (p + n') rfl, + γ.rightShift_v _ _ hn' p (p + n') rfl q hpq, + shiftFunctorObjXIso, assoc, Iso.inv_hom_id, comp_id] + +@[simp] +lemma rightShift_rightUnshift {a n' : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn' : n' + a = n) : + (γ.rightUnshift n hn').rightShift a n' hn' = γ := by + ext p q hpq + simp only [(γ.rightUnshift n hn').rightShift_v a n' hn' p q hpq (p + n) rfl, + γ.rightUnshift_v n hn' p (p + n) rfl q hpq, + shiftFunctorObjXIso, assoc, Iso.hom_inv_id, comp_id] + +@[simp] +lemma rightShift_add (a n' : ℤ) (hn' : n' + a = n) : + (γ₁ + γ₂).rightShift a n' hn' = γ₁.rightShift a n' hn' + γ₂.rightShift a n' hn' := by + ext p q hpq + dsimp + simp only [rightShift_v _ a n' hn' p q hpq _ rfl, add_v, add_comp] + +variable (K L) + +/-- The additive equivalence `Cochain K L n ≃+ Cochain K L⟦a⟧ n'` when `n' + a = n`. -/ +@[simps] +def rightShiftAddEquiv (n a n' : ℤ) (hn' : n' + a = n) : + Cochain K L n ≃+ Cochain K (L⟦a⟧) n' where + toFun γ := γ.rightShift a n' hn' + invFun γ := γ.rightUnshift n hn' + left_inv γ := by simp + right_inv γ := by simp + map_add' γ γ' := by simp + +variable {K L} + +@[simp] +lemma rightShift_zero (a n' : ℤ) (hn' : n' + a = n) : + (0 : Cochain K L n).rightShift a n' hn' = 0 := by + change rightShiftAddEquiv K L n a n' hn' 0 = 0 + apply _root_.map_zero + +@[simp] +lemma rightUnshift_zero (a n' : ℤ) (hn' : n' + a = n) : + (0 : Cochain K (L⟦a⟧) n').rightUnshift n hn' = 0 := by + change (rightShiftAddEquiv K L n a n' hn').symm 0 = 0 + apply _root_.map_zero + +@[simp] +lemma rightShift_neg (a n' : ℤ) (hn' : n' + a = n) : + (-γ).rightShift a n' hn' = -γ.rightShift a n' hn' := by + change rightShiftAddEquiv K L n a n' hn' (-γ) = _ + apply _root_.map_neg + +@[simp] +lemma rightUnshift_neg {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) : + (-γ).rightUnshift n hn = -γ.rightUnshift n hn := by + change (rightShiftAddEquiv K L n a n' hn).symm (-γ) = _ + apply _root_.map_neg + +@[simp] +lemma rightUnshift_add {n' a : ℤ} (γ₁ γ₂ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) : + (γ₁ + γ₂).rightUnshift n hn = γ₁.rightUnshift n hn + γ₂.rightUnshift n hn := by + change (rightShiftAddEquiv K L n a n' hn).symm (γ₁ + γ₂) = _ + apply _root_.map_add + +@[simp] +lemma rightShift_smul (a n' : ℤ) (hn' : n' + a = n) (x : R) : + (x • γ).rightShift a n' hn' = x • γ.rightShift a n' hn' := by + ext p q hpq + dsimp + simp only [rightShift_v _ a n' hn' p q hpq _ rfl, smul_v, Linear.smul_comp] + +variable (K L R) + +/-- The linear equivalence `Cochain K L n ≃+ Cochain K L⟦a⟧ n'` when `n' + a = n` and +the category is `R`-linear. -/ +@[simps!] +def rightShiftLinearEquiv (n a n' : ℤ) (hn' : n' + a = n) : + Cochain K L n ≃ₗ[R] Cochain K (L⟦a⟧) n' := + (rightShiftAddEquiv K L n a n' hn').toLinearEquiv (fun x γ => by simp) + +variable {K L R} + +@[simp] +lemma rightShift_units_smul (a n' : ℤ) (hn' : n' + a = n) (x : Rˣ) : + (x • γ).rightShift a n' hn' = x • γ.rightShift a n' hn' := by + apply rightShift_smul + +@[simp] +lemma rightUnshift_smul {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) (x : R) : + (x • γ).rightUnshift n hn = x • γ.rightUnshift n hn := by + change (rightShiftLinearEquiv R K L n a n' hn).symm (x • γ) = _ + apply map_smul + +@[simp] +lemma rightUnshift_units_smul {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) + (hn : n' + a = n) (x : Rˣ) : + (x • γ).rightUnshift n hn = x • γ.rightUnshift n hn := by + apply rightUnshift_smul + +lemma rightUnshift_comp {m : ℤ} {a : ℤ} (γ' : Cochain L (M⟦a⟧) m) {nm : ℤ} (hnm : n + m = nm) + (nm' : ℤ) (hnm' : nm + a = nm') (m' : ℤ) (hm' : m + a = m') : + (γ.comp γ' hnm).rightUnshift nm' hnm' = + γ.comp (γ'.rightUnshift m' hm') (by linarith) := by + ext p q hpq + rw [(γ.comp γ' hnm).rightUnshift_v nm' hnm' p q hpq (p + n + m) (by linarith), + γ.comp_v γ' hnm p (p + n) (p + n + m) rfl rfl, + comp_v _ _ (show n + m' = nm' by linarith) p (p + n) q (by linarith) (by linarith), + γ'.rightUnshift_v m' hm' (p + n) q (by linarith) (p + n + m) rfl, assoc] + +lemma δ_rightShift (a n' m' : ℤ) (hn' : n' + a = n) (m : ℤ) (hm' : m' + a = m) : + δ n' m' (γ.rightShift a n' hn') = a.negOnePow • (δ n m γ).rightShift a m' hm' := by + by_cases hnm : n + 1 = m + · have hnm' : n' + 1 = m' := by linarith + ext p q hpq + dsimp + rw [(δ n m γ).rightShift_v a m' hm' p q hpq _ rfl, + δ_v n m hnm _ p (p+m) rfl (p+n) (p+1) (by linarith) rfl, + δ_v n' m' hnm' _ p q hpq (p+n') (p+1) (by linarith) rfl, + γ.rightShift_v a n' hn' p (p+n') rfl (p+n) rfl, + γ.rightShift_v a n' hn' (p+1) q _ (p+m) (by linarith)] + simp only [shiftFunctorObjXIso, shiftFunctor_obj_d', + Linear.comp_units_smul, assoc, HomologicalComplex.XIsoOfEq_inv_comp_d, + add_comp, HomologicalComplex.d_comp_XIsoOfEq_inv, Linear.units_smul_comp, smul_add, + add_right_inj, smul_smul] + congr 1 + rw [← hm', add_comm m', Int.negOnePow_add, ← mul_assoc, + Int.units_mul_self, one_mul] + · have hnm' : ¬ n' + 1 = m' := fun _ => hnm (by linarith) + rw [δ_shape _ _ hnm', δ_shape _ _ hnm, rightShift_zero, smul_zero] + +lemma δ_rightUnshift {a n' : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) + (m m' : ℤ) (hm' : m' + a = m) : + δ n m (γ.rightUnshift n hn) = a.negOnePow • (δ n' m' γ).rightUnshift m hm' := by + obtain ⟨γ', rfl⟩ := (rightShiftAddEquiv K L n a n' hn).surjective γ + dsimp + simp only [rightUnshift_rightShift, γ'.δ_rightShift a n' m' hn m hm', rightUnshift_units_smul, + smul_smul, Int.units_mul_self, one_smul] + +end Cochain + +namespace Cocycle + +/-- The map `Cocycle K L n → Cocycle K (L⟦a⟧) n'` when `n' + a = n`. -/ +@[simps!] +def rightShift (γ : Cocycle K L n) (a n' : ℤ) (hn' : n' + a = n) : + Cocycle K (L⟦a⟧) n' := + Cocycle.mk (γ.1.rightShift a n' hn') _ rfl (by + simp only [Cochain.δ_rightShift _ a n' (n' + 1) hn' (n + 1) (by linarith), + δ_eq_zero, Cochain.rightShift_zero, smul_zero]) + +/-- The map `Cocycle K (L⟦a⟧) n' → Cocycle K L n` when `n' + a = n`. -/ +@[simps!] +def rightUnshift {n' a : ℤ} (γ : Cocycle K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) : + Cocycle K L n := + Cocycle.mk (γ.1.rightUnshift n hn) _ rfl (by + rw [Cochain.δ_rightUnshift _ n hn (n + 1) (n + 1 - a) (by linarith), + δ_eq_zero, Cochain.rightUnshift_zero, smul_zero]) + +end Cocycle + +end CochainComplex.HomComplex From bc21de103cd868ca3d64e04e9e46d340d976e503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Mon, 1 Jan 2024 21:12:39 +0000 Subject: [PATCH 301/353] refactor(Algebra/Homology): the category of bicomplexes (#9333) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR introduces the abbreviation `abbrev HomologicalComplex₂ := HomologicalComplex (HomologicalComplex C c₂) c₁` for bicomplexes. The content of the file `Algebra.Homology.Flip` is also moved to the new file `Algebra.Homology.HomologicalBicomplex`. --- Mathlib.lean | 2 +- Mathlib/Algebra/Homology/Flip.lean | 125 ----------------- .../Homology/HomologicalBicomplex.lean | 127 ++++++++++++++++++ .../Algebra/Homology/HomologicalComplex.lean | 2 +- 4 files changed, 129 insertions(+), 127 deletions(-) delete mode 100644 Mathlib/Algebra/Homology/Flip.lean create mode 100644 Mathlib/Algebra/Homology/HomologicalBicomplex.lean diff --git a/Mathlib.lean b/Mathlib.lean index 89294635c5aa6..2f1f1b2e3b072 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -236,8 +236,8 @@ import Mathlib.Algebra.Homology.ConcreteCategory import Mathlib.Algebra.Homology.DifferentialObject import Mathlib.Algebra.Homology.Exact import Mathlib.Algebra.Homology.ExactSequence -import Mathlib.Algebra.Homology.Flip import Mathlib.Algebra.Homology.Functor +import Mathlib.Algebra.Homology.HomologicalBicomplex import Mathlib.Algebra.Homology.HomologicalComplex import Mathlib.Algebra.Homology.HomologicalComplexBiprod import Mathlib.Algebra.Homology.HomologicalComplexLimits diff --git a/Mathlib/Algebra/Homology/Flip.lean b/Mathlib/Algebra/Homology/Flip.lean deleted file mode 100644 index 8e4ad84660353..0000000000000 --- a/Mathlib/Algebra/Homology/Flip.lean +++ /dev/null @@ -1,125 +0,0 @@ -/- -Copyright (c) 2021 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Mathlib.Algebra.Homology.HomologicalComplex - -#align_import algebra.homology.flip from "leanprover-community/mathlib"@"ff511590476ef357b6132a45816adc120d5d7b1d" - -/-! -# Flip a complex of complexes - -For now we don't have double complexes as a distinct thing, -but we can model them as complexes of complexes. - -Here we show how to flip a complex of complexes over the diagonal, -exchanging the horizontal and vertical directions. - --/ - - -universe v u - -open CategoryTheory CategoryTheory.Limits - -namespace HomologicalComplex - -variable {V : Type u} [Category.{v} V] [HasZeroMorphisms V] - -variable {ι : Type*} {c : ComplexShape ι} {ι' : Type*} {c' : ComplexShape ι'} - -/-- Flip a complex of complexes over the diagonal, -exchanging the horizontal and vertical directions. --/ -@[simps] -def flipObj (C : HomologicalComplex (HomologicalComplex V c) c') : - HomologicalComplex (HomologicalComplex V c') c where - X i := - { X := fun j => (C.X j).X i - d := fun j j' => (C.d j j').f i - shape := fun j j' w => by - simp_all only [not_false_eq_true, shape, zero_f] - d_comp_d' := fun j₁ j₂ j₃ _ _ => congr_hom (C.d_comp_d j₁ j₂ j₃) i } - d i i' := - { f := fun j => (C.X j).d i i' - comm' := fun j j' _ => ((C.d j j').comm i i').symm } - shape i i' w := by - ext j - exact (C.X j).shape i i' w -#align homological_complex.flip_obj HomologicalComplex.flipObj - -variable (V c c') - -/-- Flipping a complex of complexes over the diagonal, as a functor. -/ -@[simps] -def flip : - HomologicalComplex (HomologicalComplex V c) c' ⥤ HomologicalComplex (HomologicalComplex V c') c - where - obj C := flipObj C - map {C D} f := - { f := fun i => - { f := fun j => (f.f j).f i - comm' := fun j j' _ => congr_hom (f.comm j j') i } } -#align homological_complex.flip HomologicalComplex.flip - -/-- Auxiliary definition for `HomologicalComplex.flipEquivalence`. -/ -@[simps!] -def flipEquivalenceUnitIso : - 𝟭 (HomologicalComplex (HomologicalComplex V c) c') ≅ flip V c c' ⋙ flip V c' c := - NatIso.ofComponents - (fun C => - { hom := - { f := fun i => { f := fun j => 𝟙 ((C.X i).X j) } - comm' := fun i j _ => by - ext - dsimp - simp only [Category.id_comp, Category.comp_id] } - inv := - { f := fun i => { f := fun j => 𝟙 ((C.X i).X j) } - comm' := fun i j _ => by - ext - dsimp - simp only [Category.id_comp, Category.comp_id] } }) - fun {X Y} f => by - ext - dsimp - simp only [Category.id_comp, Category.comp_id] -#align homological_complex.flip_equivalence_unit_iso HomologicalComplex.flipEquivalenceUnitIso - -/-- Auxiliary definition for `HomologicalComplex.flipEquivalence`. -/ -@[simps!] -def flipEquivalenceCounitIso : - flip V c' c ⋙ flip V c c' ≅ 𝟭 (HomologicalComplex (HomologicalComplex V c') c) := - NatIso.ofComponents - (fun C => - { hom := - { f := fun i => { f := fun j => 𝟙 ((C.X i).X j) } - comm' := fun i j _ => by - ext - dsimp - simp only [Category.id_comp, Category.comp_id] } - inv := - { f := fun i => { f := fun j => 𝟙 ((C.X i).X j) } - comm' := fun i j _ => by - ext - dsimp - simp only [Category.id_comp, Category.comp_id] } }) - fun {X Y} f => by - ext - dsimp - simp only [Category.id_comp, Category.comp_id] -#align homological_complex.flip_equivalence_counit_iso HomologicalComplex.flipEquivalenceCounitIso - -/-- Flipping a complex of complexes over the diagonal, as an equivalence of categories. -/ -@[simps] -def flipEquivalence : - HomologicalComplex (HomologicalComplex V c) c' ≌ HomologicalComplex (HomologicalComplex V c') c - where - functor := flip V c c' - inverse := flip V c' c - unitIso := flipEquivalenceUnitIso V c c' - counitIso := flipEquivalenceCounitIso V c c' -#align homological_complex.flip_equivalence HomologicalComplex.flipEquivalence - -end HomologicalComplex diff --git a/Mathlib/Algebra/Homology/HomologicalBicomplex.lean b/Mathlib/Algebra/Homology/HomologicalBicomplex.lean new file mode 100644 index 0000000000000..b21e7182817c0 --- /dev/null +++ b/Mathlib/Algebra/Homology/HomologicalBicomplex.lean @@ -0,0 +1,127 @@ +/- +Copyright (c) 2021 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison, Joël Riou +-/ +import Mathlib.Algebra.Homology.HomologicalComplex + +#align_import algebra.homology.flip from "leanprover-community/mathlib"@"ff511590476ef357b6132a45816adc120d5d7b1d" + +/-! +# Bicomplexes + +Given a category `C` with zero morphisms and two complex shapes +`c₁ : ComplexShape I₁` and `c₂ : ComplexShape I₂`, we define +the type of bicomplexes `HomologicalComplex₂ C c₁ c₂` as an +abbreviation for `HomologicalComplex (HomologicalComplex C c₂) c₁`. +In particular, if `K : HomologicalComplex₂ C c₁ c₂`, then +for each `i₁ : I₁`, `K.X i₁` is a column of `K`. + +In this file, we obtain the equivalence of categories +`HomologicalComplex₂.flipEquivalence : HomologicalComplex₂ C c₁ c₂ ≌ HomologicalComplex₂ C c₂ c₁` +which is obtained by exchanging the horizontal and vertical directions. + +-/ + + +open CategoryTheory Limits + +variable (C : Type*) [Category C] [HasZeroMorphisms C] + {I₁ I₂ : Type*} (c₁ : ComplexShape I₁) (c₂ : ComplexShape I₂) + +/-- Given a category `C` and two complex shapes `c₁` and `c₂` on types `I₁` and `I₂`, +the associated type of bicomplexes `HomologicalComplex₂ C c₁ c₂` is +`K : HomologicalComplex (HomologicalComplex C c₂) c₁`. Then, the object in +position `⟨i₁, i₂⟩` can be obtained as `(K.X i₁).X i₂`. -/ +abbrev HomologicalComplex₂ := + HomologicalComplex (HomologicalComplex C c₂) c₁ + +namespace HomologicalComplex₂ + +open HomologicalComplex + +variable {C c₁ c₂} + +/-- The graded object indexed by `I₁ × I₂` induced by a bicomplex. -/ +def toGradedObject (K : HomologicalComplex₂ C c₁ c₂) : + GradedObject (I₁ × I₂) C := + fun ⟨i₁, i₂⟩ => (K.X i₁).X i₂ + +lemma shape_f (K : HomologicalComplex₂ C c₁ c₂) (i₁ i₁' : I₁) (h : ¬ c₁.Rel i₁ i₁') (i₂ : I₂) : + (K.d i₁ i₁').f i₂ = 0 := by + rw [K.shape _ _ h, zero_f] + +@[reassoc (attr := simp)] +lemma d_f_comp_d_f (K : HomologicalComplex₂ C c₁ c₂) + (i₁ i₁' i₁'' : I₁) (i₂ : I₂) : + (K.d i₁ i₁').f i₂ ≫ (K.d i₁' i₁'').f i₂ = 0 := by + rw [← comp_f, d_comp_d, zero_f] + +@[reassoc] +lemma d_comm (K : HomologicalComplex₂ C c₁ c₂) (i₁ i₁' : I₁) (i₂ i₂' : I₂) : + (K.d i₁ i₁').f i₂ ≫ (K.X i₁').d i₂ i₂' = (K.X i₁).d i₂ i₂' ≫ (K.d i₁ i₁').f i₂' := by + simp + +@[reassoc (attr := simp)] +lemma comm_f {K L : HomologicalComplex₂ C c₁ c₂} (f : K ⟶ L) (i₁ i₁' : I₁) (i₂ : I₂) : + (f.f i₁).f i₂ ≫ (L.d i₁ i₁').f i₂ = (K.d i₁ i₁').f i₂ ≫ (f.f i₁').f i₂ := + congr_hom (f.comm i₁ i₁') i₂ + +/-- Flip a complex of complexes over the diagonal, +exchanging the horizontal and vertical directions. +-/ +@[simps] +def flip (K : HomologicalComplex₂ C c₁ c₂) : HomologicalComplex₂ C c₂ c₁ where + X i := + { X := fun j => (K.X j).X i + d := fun j j' => (K.d j j').f i + shape := fun j j' w => K.shape_f _ _ w i } + d i i' := { f := fun j => (K.X j).d i i' } + shape i i' w := by + ext j + exact (K.X j).shape i i' w +#align homological_complex.flip_obj HomologicalComplex₂.flip + +variable (C c₁ c₂) + +/-- Flipping a complex of complexes over the diagonal, as a functor. -/ +@[simps] +def flipFunctor : + HomologicalComplex₂ C c₁ c₂ ⥤ HomologicalComplex₂ C c₂ c₁ where + obj K := K.flip + map {K L} f := + { f := fun i => + { f := fun j => (f.f j).f i + comm' := by intros; simp } + comm' := by intros; ext; simp } +#align homological_complex.flip HomologicalComplex₂.flipFunctor + +/-- Auxiliary definition for `HomologicalComplex₂.flipEquivalence`. -/ +@[simps!] +def flipEquivalenceUnitIso : + 𝟭 (HomologicalComplex₂ C c₁ c₂) ≅ flipFunctor C c₁ c₂ ⋙ flipFunctor C c₂ c₁ := + NatIso.ofComponents (fun K => HomologicalComplex.Hom.isoOfComponents (fun i₁ => + HomologicalComplex.Hom.isoOfComponents (fun i₂ => Iso.refl _) + (by aesop_cat)) (by aesop_cat)) (by aesop_cat) +#align homological_complex.flip_equivalence_unit_iso HomologicalComplex₂.flipEquivalenceUnitIso + +/-- Auxiliary definition for `HomologicalComplex₂.flipEquivalence`. -/ +@[simps!] +def flipEquivalenceCounitIso : + flipFunctor C c₂ c₁ ⋙ flipFunctor C c₁ c₂ ≅ 𝟭 (HomologicalComplex₂ C c₂ c₁) := + NatIso.ofComponents (fun K => HomologicalComplex.Hom.isoOfComponents (fun i₂ => + HomologicalComplex.Hom.isoOfComponents (fun i₁ => Iso.refl _) + (by aesop_cat)) (by aesop_cat)) (by aesop_cat) +#align homological_complex.flip_equivalence_counit_iso HomologicalComplex₂.flipEquivalenceCounitIso + +/-- Flipping a complex of complexes over the diagonal, as an equivalence of categories. -/ +@[simps] +def flipEquivalence : + HomologicalComplex₂ C c₁ c₂ ≌ HomologicalComplex₂ C c₂ c₁ where + functor := flipFunctor C c₁ c₂ + inverse := flipFunctor C c₂ c₁ + unitIso := flipEquivalenceUnitIso C c₁ c₂ + counitIso := flipEquivalenceCounitIso C c₁ c₂ +#align homological_complex.flip_equivalence HomologicalComplex₂.flipEquivalence + +end HomologicalComplex₂ diff --git a/Mathlib/Algebra/Homology/HomologicalComplex.lean b/Mathlib/Algebra/Homology/HomologicalComplex.lean index 9a4e4617b6176..6ca2a073cd072 100644 --- a/Mathlib/Algebra/Homology/HomologicalComplex.lean +++ b/Mathlib/Algebra/Homology/HomologicalComplex.lean @@ -276,7 +276,7 @@ theorem id_f (C : HomologicalComplex V c) (i : ι) : Hom.f (𝟙 C) i = 𝟙 (C. rfl #align homological_complex.id_f HomologicalComplex.id_f -@[simp] +@[simp, reassoc] theorem comp_f {C₁ C₂ C₃ : HomologicalComplex V c} (f : C₁ ⟶ C₂) (g : C₂ ⟶ C₃) (i : ι) : (f ≫ g).f i = f.f i ≫ g.f i := rfl From 16877b9c3231330d2432ed9cd8d748e50f1f4759 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Mon, 1 Jan 2024 22:36:27 +0000 Subject: [PATCH 302/353] chore: use string gaps (#9193) For error messages that span multiple lines, now we can use the new "string gap" escape sequence (a `\` at the end of the line, which causes all the whitespace at the beginning of the next line ignored), rather than using append operations or hacks involving `{` and `}` for `s!` and `m!` strings. Style-wise, we suggest for long messages that the body of the message start on the next line if possible, by starting the message with a string gap sequence. This eliminates needing to decide whether to indent continuing lines at the `"` or at the next column. For example: ```lean logError m!"\ Tactic 'more_magic' cannot \ apply expression{indentD e}\n\ due to some reason or another." ``` Note that to get whitespace to appear between one line and the next, you include it before the `\`. --- Cache/Requests.lean | 4 +- ImportGraph/Main.lean | 16 +-- Mathlib/Data/Matrix/Notation.lean | 6 +- Mathlib/Data/PNat/Xgcd.lean | 6 +- Mathlib/Lean/Expr/Basic.lean | 4 +- Mathlib/Mathport/Notation.lean | 15 +-- Mathlib/Mathport/Rename.lean | 16 +-- .../Constructions/BorelSpace/Basic.lean | 10 +- Mathlib/Tactic/Cases.lean | 8 +- Mathlib/Tactic/CategoryTheory/Coherence.lean | 4 +- .../Tactic/CategoryTheory/Elementwise.lean | 12 +- Mathlib/Tactic/Change.lean | 5 +- Mathlib/Tactic/ComputeDegree.lean | 9 +- Mathlib/Tactic/Core.lean | 4 +- Mathlib/Tactic/DeriveFintype.lean | 4 +- Mathlib/Tactic/Eqns.lean | 4 +- Mathlib/Tactic/FinCases.lean | 4 +- Mathlib/Tactic/GCongr/Core.lean | 14 +-- Mathlib/Tactic/LibrarySearch.lean | 4 +- Mathlib/Tactic/MoveAdd.lean | 5 +- Mathlib/Tactic/Nontriviality/Core.lean | 4 +- Mathlib/Tactic/ProxyType.lean | 20 +-- Mathlib/Tactic/Recall.lean | 6 +- Mathlib/Tactic/RewriteSearch.lean | 10 +- Mathlib/Tactic/Rewrites.lean | 3 +- Mathlib/Tactic/Says.lean | 4 +- Mathlib/Tactic/Simps/Basic.lean | 119 +++++++++--------- Mathlib/Tactic/Simps/NotationClass.lean | 4 +- Mathlib/Tactic/TermCongr.lean | 36 +++--- Mathlib/Tactic/ToAdditive.lean | 87 ++++++------- Mathlib/Tactic/Variable.lean | 26 ++-- Mathlib/Tactic/Widget/Calc.lean | 9 +- Mathlib/Util/AssertExists.lean | 8 +- Mathlib/Util/Imports.lean | 4 +- test/GCongr/inequalities.lean | 3 +- test/eqns.lean | 2 +- 36 files changed, 254 insertions(+), 245 deletions(-) diff --git a/Cache/Requests.lean b/Cache/Requests.lean index 207d358bdc2df..ec8da2439e229 100644 --- a/Cache/Requests.lean +++ b/Cache/Requests.lean @@ -47,8 +47,8 @@ def mkGetConfigContent (hashMap : IO.HashMap) : IO String := do -- Note we append a '.part' to the filenames here, -- which `downloadFiles` then removes when the download is successful. - pure $ acc ++ s!"url = {← mkFileURL fileName none}\n-o { - (IO.CACHEDIR / (fileName ++ ".part")).toString.quote}\n" + pure $ acc ++ s!"url = {← mkFileURL fileName none}\n\ + -o {(IO.CACHEDIR / (fileName ++ ".part")).toString.quote}\n" /-- Calls `curl` to download a single file from the server to `CACHEDIR` (`.cache`) -/ def downloadFile (hash : UInt64) : IO Bool := do diff --git a/ImportGraph/Main.lean b/ImportGraph/Main.lean index 98a1db984f125..0b86f35143303 100644 --- a/ImportGraph/Main.lean +++ b/ImportGraph/Main.lean @@ -78,9 +78,9 @@ def importGraphCLI (args : Cli.Parsed) : IO UInt32 := do /-- Setting up command line options and help text for `lake exe graph`. -/ def graph : Cmd := `[Cli| graph VIA importGraphCLI; ["0.0.1"] - "Generate representations of a Lean import graph." ++ - "By default generates the import graph up to `Mathlib`." ++ - "If you are working in a downstream project, use `lake exe graph --to MyProject`." + "Generate representations of a Lean import graph. \ + By default generates the import graph up to `Mathlib`. \ + If you are working in a downstream project, use `lake exe graph --to MyProject`." FLAGS: reduce; "Remove transitively redundant edges." @@ -90,11 +90,11 @@ def graph : Cmd := `[Cli| "include-deps"; "Include used files from other projects (e.g. lake packages)" ARGS: - ...outputs : String; "Filename(s) for the output. " ++ - "If none are specified, generates `import_graph.dot`. " ++ - "Automatically chooses the format based on the file extension. " ++ - "Currently `.dot` is supported, " ++ - "and if you have `graphviz` installed then any supported output format is allowed." + ...outputs : String; "Filename(s) for the output. \ + If none are specified, generates `import_graph.dot`. \ + Automatically chooses the format based on the file extension. \ + Currently `.dot` is supported, \ + and if you have `graphviz` installed then any supported output format is allowed." ] /-- `lake exe graph` -/ diff --git a/Mathlib/Data/Matrix/Notation.lean b/Mathlib/Data/Matrix/Notation.lean index 7a1eaef0a01b3..13f2a3527df5b 100644 --- a/Mathlib/Data/Matrix/Notation.lean +++ b/Mathlib/Data/Matrix/Notation.lean @@ -103,9 +103,9 @@ macro_rules let n := if h : 0 < m then rows[0].size else 0 let rowVecs ← rows.mapM fun row : Array Term => do unless row.size = n do - Macro.throwErrorAt (mkNullNode row) - s!"Rows must be of equal length; this row has {row.size} items, the previous rows {" - "}have {n}" + Macro.throwErrorAt (mkNullNode row) s!"\ + Rows must be of equal length; this row has {row.size} items, \ + the previous rows have {n}" `(![$row,*]) `(@Matrix.of (Fin $(quote m)) (Fin $(quote n)) _ ![$rowVecs,*]) | `(!![$[;%$semicolons]*]) => do diff --git a/Mathlib/Data/PNat/Xgcd.lean b/Mathlib/Data/PNat/Xgcd.lean index 047a251db8206..c43183d9b8b21 100644 --- a/Mathlib/Data/PNat/Xgcd.lean +++ b/Mathlib/Data/PNat/Xgcd.lean @@ -70,9 +70,9 @@ instance : SizeOf XgcdType := reflects the matrix/vector interpretation as above. -/ instance : Repr XgcdType where reprPrec - | g, _ => s!"[[[ {repr (g.wp + 1)}, {(repr g.x)} ], [" ++ - s!"{repr g.y}, {repr (g.zp + 1)}]], [" ++ - s!"{repr (g.ap + 1)}, {repr (g.bp + 1)}]]" + | g, _ => s!"[[[{repr (g.wp + 1)}, {repr g.x}], \ + [{repr g.y}, {repr (g.zp + 1)}]], \ + [{repr (g.ap + 1)}, {repr (g.bp + 1)}]]" /-- Another `mk` using ℕ and ℕ+ -/ def mk' (w : ℕ+) (x : ℕ) (y : ℕ) (z : ℕ+) (a : ℕ+) (b : ℕ+) : XgcdType := diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean index 68cbeaf94e739..eaab712e9ff82 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -422,8 +422,8 @@ def reduceProjStruct? (e : Expr) : MetaM (Option Expr) := do if hs : sidx < sfields.size then return some (sfields[sidx]'hs) else - throwError m!"ill-formed expression, {cname} is the {pinfo.i + 1}-th projection function { - ""}but {sarg} does not have enough arguments" + throwError m!"ill-formed expression, {cname} is the {pinfo.i + 1}-th projection function \ + but {sarg} does not have enough arguments" else return none diff --git a/Mathlib/Mathport/Notation.lean b/Mathlib/Mathport/Notation.lean index 9afa98330f8b6..86f6e6b78a12e 100644 --- a/Mathlib/Mathport/Notation.lean +++ b/Mathlib/Mathport/Notation.lean @@ -590,13 +590,14 @@ elab (name := notation3) doc:(docComment)? attrs?:(Parser.Term.attributes)? attr elabCommand <| ← `(command| attribute [$attrKind delab $(mkIdent key)] $(Lean.mkIdent delabName)) else - logWarning s!"Was not able to generate a pretty printer for this notation.{ - ""} If you do not expect it to be pretty printable, then you can use{ - ""} `notation3 (prettyPrint := false)`.{ - ""} If the notation expansion refers to section variables, be sure to do `local notation3`.{ - ""} Otherwise, you might be able to adjust the notation expansion to make it matchable;{ - ""} pretty printing relies on deriving an expression matcher from the expansion.{ - ""} (Use `set_option trace.notation3 true` to get some debug information.)" + logWarning s!"\ + Was not able to generate a pretty printer for this notation. \ + If you do not expect it to be pretty printable, then you can use \ + `notation3 (prettyPrint := false)`. \ + If the notation expansion refers to section variables, be sure to do `local notation3`. \ + Otherwise, you might be able to adjust the notation expansion to make it matchable; \ + pretty printing relies on deriving an expression matcher from the expansion. \ + (Use `set_option trace.notation3 true` to get some debug information.)" initialize Std.Linter.UnreachableTactic.addIgnoreTacticKind ``«notation3» diff --git a/Mathlib/Mathport/Rename.lean b/Mathlib/Mathport/Rename.lean index 14c2ce5471dc1..c87acc945db71 100644 --- a/Mathlib/Mathport/Rename.lean +++ b/Mathlib/Mathport/Rename.lean @@ -160,17 +160,17 @@ def suspiciousLean3Name (s : String) : Bool := Id.run do let note := "(add `set_option align.precheck false` to suppress this message)" let inner := match ← try some <$> resolveGlobalConstWithInfos id4 catch _ => pure none with | none => m!"" - | some cs => m!" Did you mean:\n\n{ - ("\n":MessageData).joinSep (cs.map fun c' => m!" #align {id3} {c'}") - }\n\n#align inputs have to be fully qualified.{"" - } (Double check the lean 3 name too, we can't check that!)" + | some cs => m!" Did you mean:\n\n\ + {("\n":MessageData).joinSep (cs.map fun c' => m!" #align {id3} {c'}")}\n\n\ + #align inputs have to be fully qualified. \ + (Double check the lean 3 name too, we can't check that!)" throwErrorAt id4 "Declaration {c} not found.{inner}\n{note}" if Linter.getLinterValue linter.uppercaseLean3 (← getOptions) then if id3.getId.anyS suspiciousLean3Name then - Linter.logLint linter.uppercaseLean3 id3 $ - "Lean 3 names are usually lowercase. This might be a typo.\n" ++ - "If the Lean 3 name is correct, then above this line, add:\n" ++ - "set_option linter.uppercaseLean3 false in\n" + Linter.logLint linter.uppercaseLean3 id3 + "Lean 3 names are usually lowercase. This might be a typo.\n\ + If the Lean 3 name is correct, then above this line, add:\n\ + set_option linter.uppercaseLean3 false in\n" withRef id3 <| ensureUnused id3.getId liftCoreM <| addNameAlignment id3.getId id4.getId | _ => throwUnsupportedSyntax diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index 8f0d99b868349..450fd905a4a82 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -243,11 +243,11 @@ def borelToRefl (e : Expr) (i : FVarId) : TacticM Unit := do liftMetaTactic fun m => return [← subst m i] catch _ => let et ← synthInstance (← mkAppOptM ``TopologicalSpace #[e]) - throwError - (m!"`‹TopologicalSpace {e}› := {et}" ++ MessageData.ofFormat Format.line ++ - m!"depends on" ++ MessageData.ofFormat Format.line ++ - m!"{Expr.fvar i} : MeasurableSpace {e}`" ++ MessageData.ofFormat Format.line ++ - "so `borelize` isn't avaliable") + throwError m!"\ + `‹TopologicalSpace {e}› := {et}\n\ + depends on\n\ + {Expr.fvar i} : MeasurableSpace {e}`\n\ + so `borelize` isn't avaliable" evalTactic <| ← `(tactic| refine_lift letI : MeasurableSpace $te := borel $te diff --git a/Mathlib/Tactic/Cases.lean b/Mathlib/Tactic/Cases.lean index c6a66c311a9ba..425ea805c77c8 100644 --- a/Mathlib/Tactic/Cases.lean +++ b/Mathlib/Tactic/Cases.lean @@ -75,11 +75,11 @@ elab (name := induction') "induction' " tgts:(Parser.Tactic.casesTarget,+) let mut s ← getFVarSetToGeneralize targets forbidden for v in genArgs do if forbidden.contains v then - throwError "variable cannot be generalized {"" - }because target depends on it{indentExpr (mkFVar v)}" + throwError "variable cannot be generalized \ + because target depends on it{indentExpr (mkFVar v)}" if s.contains v then - throwError "unnecessary 'generalizing' argument, {"" - }variable '{mkFVar v}' is generalized automatically" + throwError "unnecessary 'generalizing' argument, \ + variable '{mkFVar v}' is generalized automatically" s := s.insert v let (fvarIds, g) ← g.revert (← sortFVarIds s.toArray) g.withContext do diff --git a/Mathlib/Tactic/CategoryTheory/Coherence.lean b/Mathlib/Tactic/CategoryTheory/Coherence.lean index 2458843d8c4ec..ffa3d3e9dea24 100644 --- a/Mathlib/Tactic/CategoryTheory/Coherence.lean +++ b/Mathlib/Tactic/CategoryTheory/Coherence.lean @@ -329,8 +329,8 @@ def coherence_loop (maxSteps := 37) : TacticM Unit := -- Otherwise, rearrange so we have a maximal prefix of each side -- that is built out of unitors and associators: evalTactic (← `(tactic| liftable_prefixes)) <|> - exception' ("Something went wrong in the `coherence` tactic: " ++ - "is the target an equation in a monoidal category?") + exception' "Something went wrong in the `coherence` tactic: \ + is the target an equation in a monoidal category?" -- The goal should now look like `f₀ ≫ f₁ = g₀ ≫ g₁`, liftMetaTactic MVarId.congrCore -- and now we have two goals `f₀ = g₀` and `f₁ = g₁`. diff --git a/Mathlib/Tactic/CategoryTheory/Elementwise.lean b/Mathlib/Tactic/CategoryTheory/Elementwise.lean index c892dac0de665..e9920aa866288 100644 --- a/Mathlib/Tactic/CategoryTheory/Elementwise.lean +++ b/Mathlib/Tactic/CategoryTheory/Elementwise.lean @@ -84,9 +84,9 @@ def elementwiseExpr (src : Name) (type pf : Expr) (simpSides := true) : -- First simplify using elementwise-specific lemmas let mut eqPf' ← simpType (simpOnlyNames elementwiseThms (config := { decide := false })) eqPf if (← inferType eqPf') == .const ``True [] then - throwError "elementwise lemma for {src} is trivial after applying ConcreteCategory {"" - }lemmas, which can be caused by how applications are unfolded. {"" - }Using elementwise is unnecessary." + throwError "elementwise lemma for {src} is trivial after applying ConcreteCategory \ + lemmas, which can be caused by how applications are unfolded. \ + Using elementwise is unnecessary." if simpSides then let ctx := { ← Simp.Context.mkDefault with config.decide := false } let (ty', eqPf'') ← simpEq (fun e => return (← simp e ctx).1) (← inferType eqPf') eqPf' @@ -94,9 +94,9 @@ def elementwiseExpr (src : Name) (type pf : Expr) (simpSides := true) : forallTelescope ty' fun _ ty' => do if let some (_, lhs, rhs) := ty'.eq? then if ← Std.Tactic.Lint.isSimpEq lhs rhs then - throwError "applying simp to both sides reduces elementwise lemma for {src} {"" - }to the trivial equality {ty'}. {"" - }Either add `nosimp` or remove the `elementwise` attribute." + throwError "applying simp to both sides reduces elementwise lemma for {src} \ + to the trivial equality {ty'}. \ + Either add `nosimp` or remove the `elementwise` attribute." eqPf' ← mkExpectedTypeHint eqPf'' ty' if let some (w, instConcr) := instConcr? then return (← Meta.mkLambdaFVars (fvars.push instConcr) eqPf', w) diff --git a/Mathlib/Tactic/Change.lean b/Mathlib/Tactic/Change.lean index 982f37e4084b7..a14ddb334200d 100644 --- a/Mathlib/Tactic/Change.lean +++ b/Mathlib/Tactic/Change.lean @@ -39,8 +39,9 @@ elab_rules : tactic | some sop => do let tgt ← getMainTarget let ex ← withRef sop <| elabTermEnsuringType sop (← inferType tgt) - if !(← isDefEq ex tgt) then throwErrorAt sop "The term{indentD ex}\nis not defeq to the goal:{ - indentD tgt}" + if !(← isDefEq ex tgt) then throwErrorAt sop "\ + The term{indentD ex}\n\ + is not defeq to the goal:{indentD tgt}" instantiateMVars ex let dstx ← delabToRefinableSyntax expr addSuggestion tk (← `(tactic| change $dstx)) (origSpan? := stx) diff --git a/Mathlib/Tactic/ComputeDegree.lean b/Mathlib/Tactic/ComputeDegree.lean index 1044c6b9db4df..a731eec11f844 100644 --- a/Mathlib/Tactic/ComputeDegree.lean +++ b/Mathlib/Tactic/ComputeDegree.lean @@ -445,11 +445,10 @@ elab_rules : tactic | `(tactic| compute_degree $[!%$bang]?) => focus <| withMain | _ => none let twoH := twoHeadsArgs gt match twoH with - | (_, .anonymous, _) => throwError - (m!"'compute_degree' inapplicable. The goal{indentD gt}\nis expected to be '≤' or '='.") - | (.anonymous, _, _) => throwError - (m!"'compute_degree' inapplicable. The LHS must be an application of { - ""}'natDegree', 'degree', or 'coeff'.") + | (_, .anonymous, _) => throwError m!"'compute_degree' inapplicable. \ + The goal{indentD gt}\nis expected to be '≤' or '='." + | (.anonymous, _, _) => throwError m!"'compute_degree' inapplicable. \ + The LHS must be an application of 'natDegree', 'degree', or 'coeff'." | _ => let lem := dispatchLemma twoH trace[Tactic.compute_degree] f!"'compute_degree' first applies lemma '{lem.getString}'" diff --git a/Mathlib/Tactic/Core.lean b/Mathlib/Tactic/Core.lean index d0b89a09f5755..79d349fad19e7 100644 --- a/Mathlib/Tactic/Core.lean +++ b/Mathlib/Tactic/Core.lean @@ -251,8 +251,8 @@ def getPackageDir (pkg : String) : IO System.FilePath := do let root? ← sp.findM? fun p => (p / pkg).isDir <||> ((p / pkg).withExtension "lean").pathExists if let some root := root? then return root - throw <| IO.userError s!"Could not find {pkg} directory. { - ""}Make sure the LEAN_SRC_PATH environment variable is set correctly." + throw <| IO.userError s!"Could not find {pkg} directory. \ + Make sure the LEAN_SRC_PATH environment variable is set correctly." /-- Returns the mathlib root directory. -/ def getMathlibDir := getPackageDir "Mathlib" diff --git a/Mathlib/Tactic/DeriveFintype.lean b/Mathlib/Tactic/DeriveFintype.lean index 2790a2cc19194..d475463b92670 100644 --- a/Mathlib/Tactic/DeriveFintype.lean +++ b/Mathlib/Tactic/DeriveFintype.lean @@ -133,8 +133,8 @@ def mkFintypeEnum (declName : Name) : CommandElabM Unit := do type := listType value := enumList } setProtected enumListName - addDocString enumListName s!"A list enumerating every element of the type, { - ""}which are all zero-argument constructors. (Generated by the `Fintype` deriving handler.)" + addDocString enumListName s!"A list enumerating every element of the type, \ + which are all zero-argument constructors. (Generated by the `Fintype` deriving handler.)" do -- Prove that this list is in `toCtorIdx` order trace[Elab.Deriving.fintype] "proving {toCtorThmName}" let goalStx ← `(term| ∀ (x : $(← Term.exprToSyntax <| mkConst declName levels)), diff --git a/Mathlib/Tactic/Eqns.lean b/Mathlib/Tactic/Eqns.lean index e3c1808672c4b..e8ea5e7a6dc19 100644 --- a/Mathlib/Tactic/Eqns.lean +++ b/Mathlib/Tactic/Eqns.lean @@ -38,8 +38,8 @@ initialize eqnsAttribute : NameMapExtension (Array Name) ← add := fun | declName, `(attr| eqns $[$names]*) => do if let some _ := Meta.eqnsExt.getState (← getEnv) |>.map.find? declName then - throwError "There already exist stored eqns for '{declName}' registering new equations{ - "\n"}will not have the desired effect." + throwError "There already exist stored eqns for '{declName}'; registering new equations \ + will not have the desired effect." names.mapM resolveGlobalConstNoOverloadWithInfo | _, _ => Lean.Elab.throwUnsupportedSyntax } diff --git a/Mathlib/Tactic/FinCases.lean b/Mathlib/Tactic/FinCases.lean index f7324d4da07f1..c28b00169668f 100644 --- a/Mathlib/Tactic/FinCases.lean +++ b/Mathlib/Tactic/FinCases.lean @@ -30,8 +30,8 @@ def getMemType {m : Type → Type} [Monad m] [MonadError m] (e : Expr) : m (Opti | (``List, #[α]) => return α | (``Multiset, #[α]) => return α | (``Finset, #[α]) => return α - | _ => throwError ("Hypothesis must be of type `x ∈ (A : List α)`, `x ∈ (A : Finset α)`," - ++ " or `x ∈ (A : Multiset α)`") + | _ => throwError "Hypothesis must be of type `x ∈ (A : List α)`, `x ∈ (A : Finset α)`, \ + or `x ∈ (A : Multiset α)`" | _ => return none /-- diff --git a/Mathlib/Tactic/GCongr/Core.lean b/Mathlib/Tactic/GCongr/Core.lean index 0caf2fc67f3bf..c15ad39a29fef 100644 --- a/Mathlib/Tactic/GCongr/Core.lean +++ b/Mathlib/Tactic/GCongr/Core.lean @@ -155,9 +155,9 @@ initialize registerBuiltinAttribute { add := fun decl _ kind ↦ MetaM.run' do let declTy := (← getConstInfo decl).type withReducible <| forallTelescopeReducing declTy fun xs targetTy => do - let fail := throwError - "@[gcongr] attribute only applies to lemmas proving { - ""}x₁ ~₁ x₁' → ... xₙ ~ₙ xₙ' → f x₁ ... xₙ ∼ f x₁' ... xₙ', got {declTy}" + let fail := throwError "\ + @[gcongr] attribute only applies to lemmas proving \ + x₁ ~₁ x₁' → ... xₙ ~ₙ xₙ' → f x₁ ... xₙ ∼ f x₁' ... xₙ', got {declTy}" -- verify that conclusion of the lemma is of the form `rel (head x₁ ... xₙ) (head y₁ ... yₙ)` let .app (.app rel lhs) rhs ← whnf targetTy | fail let some relName := rel.getAppFn.constName? | fail @@ -404,8 +404,8 @@ partial def _root_.Lean.MVarId.gcongr let some (sErr, e) := ex? -- B. If there is a template, and there was no `@[gcongr]` lemma which matched the template, -- fail. - | throwError "gcongr failed, no @[gcongr] lemma applies for the template portion {"" - }{template} and the relation {rel}" + | throwError "gcongr failed, no @[gcongr] lemma applies for the template portion \ + {template} and the relation {rel}" -- B. If there is a template, and there was a `@[gcongr]` lemma which matched the template, but -- it was not possible to `apply` that lemma, then report the error message from `apply`-ing that -- lemma. @@ -512,5 +512,5 @@ elab_rules : tactic | unsolvedGoalStates => do let unsolvedGoals ← @List.mapM MetaM _ _ _ MVarId.getType unsolvedGoalStates let g := Lean.MessageData.joinSep (unsolvedGoals.map Lean.MessageData.ofExpr) Format.line - throwError "rel failed, cannot prove goal by 'substituting' the listed relationships. {"" - }The steps which could not be automatically justified were: \n{g}" + throwError "rel failed, cannot prove goal by 'substituting' the listed relationships. \ + The steps which could not be automatically justified were:\n{g}" diff --git a/Mathlib/Tactic/LibrarySearch.lean b/Mathlib/Tactic/LibrarySearch.lean index 5b53531bb0ec7..3a99072021bb0 100644 --- a/Mathlib/Tactic/LibrarySearch.lean +++ b/Mathlib/Tactic/LibrarySearch.lean @@ -275,8 +275,8 @@ elab_rules : tactic | `(tactic| apply? $[using $[$required],*]?) => do exact? (← getRef) required false elab tk:"library_search" : tactic => do - logWarning ("`library_search` has been renamed to `apply?`" ++ - " (or `exact?` if you only want solutions closing the goal)") + logWarning "`library_search` has been renamed to `apply?` \ + (or `exact?` if you only want solutions closing the goal)" exact? tk none false open Elab Term in diff --git a/Mathlib/Tactic/MoveAdd.lean b/Mathlib/Tactic/MoveAdd.lean index 99e38ea26f949..b160937169965 100644 --- a/Mathlib/Tactic/MoveAdd.lean +++ b/Mathlib/Tactic/MoveAdd.lean @@ -388,8 +388,9 @@ def unifyMovements (data : Array (Expr × Bool × Syntax)) (tgt : Expr) : let atoms := (ops.map Prod.fst).flatten.toList.filter (!isBVar ·) -- `instr` are the unified user-provided terms, `neverMatched` are non-unified ones let (instr, neverMatched) ← pairUp data.toList atoms - let dbgMsg := #[m!"Matching of input variables:\n* pre-match: { - data.map (Prod.snd ∘ Prod.snd)}\n* post-match: {instr}", + let dbgMsg := #[m!"Matching of input variables:\n\ + * pre-match: {data.map (Prod.snd ∘ Prod.snd)}\n\ + * post-match: {instr}", m!"\nMaximum number of iterations: {ops.size}"] -- if there are `neverMatched` terms, return the parsed terms and the syntax let errMsg := neverMatched.map fun (t, a, stx) => (if a then m!"← {t}" else m!"{t}", stx) diff --git a/Mathlib/Tactic/Nontriviality/Core.lean b/Mathlib/Tactic/Nontriviality/Core.lean index 0d6a1fadbed47..b1fed972e004c 100644 --- a/Mathlib/Tactic/Nontriviality/Core.lean +++ b/Mathlib/Tactic/Nontriviality/Core.lean @@ -109,8 +109,8 @@ syntax (name := nontriviality) "nontriviality" (ppSpace colGt term)? if let some (α, _) := tgt.eq? then return α if let some (α, _) := tgt.app4? ``LE.le then return α if let some (α, _) := tgt.app4? ``LT.lt then return α - throwError "The goal is not an (in)equality, so you'll need to specify the desired {"" - }`Nontrivial α` instance by invoking `nontriviality α`.") + throwError "The goal is not an (in)equality, so you'll need to specify the desired \ + `Nontrivial α` instance by invoking `nontriviality α`.") let .sort u ← whnf (← inferType α) | unreachable! let some v := u.dec | throwError "not a type{indentExpr α}" let α : Q(Type v) := α diff --git a/Mathlib/Tactic/ProxyType.lean b/Mathlib/Tactic/ProxyType.lean index 3051eda2efa32..5aca18d189eee 100644 --- a/Mathlib/Tactic/ProxyType.lean +++ b/Mathlib/Tactic/ProxyType.lean @@ -196,10 +196,10 @@ def ensureProxyEquiv (config : ProxyEquivConfig) (indVal : InductiveVal) : TermE setReducibleAttribute config.proxyName setProtected config.proxyName -- Add a docstring - addDocString config.proxyName s!"A \"proxy type\" equivalent to `{indVal.name}` that is { - ""}constructed from `Unit`, `PLift`, `Sigma`, `Empty`, and `Sum`. { - ""}See `{config.proxyEquivName}` for the equivalence. { - ""}(Generated by the `proxy_equiv%` elaborator.)" + addDocString config.proxyName s!"A \"proxy type\" equivalent to `{indVal.name}` that is \ + constructed from `Unit`, `PLift`, `Sigma`, `Empty`, and `Sum`. \ + See `{config.proxyEquivName}` for the equivalence. \ + (Generated by the `proxy_equiv%` elaborator.)" trace[Elab.ProxyType] "defined {config.proxyName}" -- Create the `Equiv` @@ -232,12 +232,12 @@ def ensureProxyEquiv (config : ProxyEquivConfig) (indVal : InductiveVal) : TermE type := (← inferType equiv') value := equiv' } setProtected config.proxyEquivName - addDocString config.proxyEquivName s!"An equivalence between the \"proxy type\" { - ""}`{config.proxyName}` and `{indVal.name}`. The proxy type is a reducible definition { - ""}that represents the inductive type using `Unit`, `PLift`, `Sigma`, `Empty`, and `Sum` { - ""}(and whatever other inductive types appear within the inductive type), and the { - ""}intended use is to define typeclass instances uses pre-existing instances on these. { - ""}(Generated by the `proxy_equiv%` elaborator.)" + addDocString config.proxyEquivName s!"An equivalence between the \"proxy type\" \ + `{config.proxyName}` and `{indVal.name}`. The proxy type is a reducible definition \ + that represents the inductive type using `Unit`, `PLift`, `Sigma`, `Empty`, and `Sum` \ + (and whatever other inductive types appear within the inductive type), and the \ + intended use is to define typeclass instances uses pre-existing instances on these. \ + (Generated by the `proxy_equiv%` elaborator.)" trace[Elab.ProxyType] "defined {config.proxyEquivName}" /-- Helper function for `proxy_equiv% type : expectedType` elaborators. diff --git a/Mathlib/Tactic/Recall.lean b/Mathlib/Tactic/Recall.lean index 872218bef3a8e..31569dbba1b52 100644 --- a/Mathlib/Tactic/Recall.lean +++ b/Mathlib/Tactic/Recall.lean @@ -57,9 +57,9 @@ elab_rules : command throwTypeMismatchError none info.type newInfo.type declConst let newVal := newInfo.value?.get!.instantiateLevelParams newInfo.levelParams mvs unless (← isDefEq infoVal newVal) do - let err := - m!"value mismatch{indentExpr declConst}\nhas value{indentExpr newVal}\n" ++ - m!"but is expected to have value{indentExpr infoVal}" + let err := m!"\ + value mismatch{indentExpr declConst}\nhas value{indentExpr newVal}\n\ + but is expected to have value{indentExpr infoVal}" throwErrorAt val err else let (binders, type?) := expandOptDeclSig sig diff --git a/Mathlib/Tactic/RewriteSearch.lean b/Mathlib/Tactic/RewriteSearch.lean index ba11a43575115..10774fbe1fda8 100644 --- a/Mathlib/Tactic/RewriteSearch.lean +++ b/Mathlib/Tactic/RewriteSearch.lean @@ -143,11 +143,11 @@ def toString (n : SearchNode) : MetaM String := do | some (_, e, true) => do let pp ← ppExpr e; pure s!"rw [← {pp}]" | some (_, e, false) => do let pp ← ppExpr e; pure s!"rw [{pp}]" | none => pure "" - return s!"depth: {n.history.size}\n" ++ - s!"history: {n.history.map fun p => hash p % 10000}\n" ++ - tac ++ "\n" ++ - "-- " ++ n.ppGoal ++ "\n" ++ - s!"distance: {n.dist?.get!}+{n.history.size}, {n.ppGoal.length}" + return s!"depth: {n.history.size}\n\ + history: {n.history.map fun p => hash p % 10000}\n\ + {tac}\n\ + -- {n.ppGoal}\n\ + distance: {n.dist?.get!}+{n.history.size}, {n.ppGoal.length}" /-- Construct a `SearchNode`. -/ def mk (history : Array (Nat × Expr × Bool)) (goal : MVarId) (ctx : Option MetavarContext := none) : diff --git a/Mathlib/Tactic/Rewrites.lean b/Mathlib/Tactic/Rewrites.lean index fb1869a4e04fe..2f7371145e076 100644 --- a/Mathlib/Tactic/Rewrites.lean +++ b/Mathlib/Tactic/Rewrites.lean @@ -344,8 +344,7 @@ elab_rules : tactic | let results ← rewrites hyps lems goal target (stopAtRfl := false) forbidden reportOutOfHeartbeats `rewrites tk if results.isEmpty then - throwError "Could not find any lemmas which can rewrite the hypothesis { - ← f.getUserName}" + throwError "Could not find any lemmas which can rewrite the hypothesis {← f.getUserName}" for r in results do withMCtx r.mctx do addRewriteSuggestion tk [(r.expr, r.symm)] r.result.eNew (loc? := .some (.fvar f)) (origSpan? := ← getRef) diff --git a/Mathlib/Tactic/Says.lean b/Mathlib/Tactic/Says.lean index c0c874507a2c7..3bff30ea421a7 100644 --- a/Mathlib/Tactic/Says.lean +++ b/Mathlib/Tactic/Says.lean @@ -32,8 +32,8 @@ namespace Mathlib.Tactic.Says register_option says.verify : Bool := { defValue := false group := "says" - descr := "For every appearance of the `X says Y` combinator, " ++ - "re-verify that running `X` produces `Try this: Y`." } + descr := "For every appearance of the `X says Y` combinator, \ + re-verify that running `X` produces `Try this: Y`." } register_option says.no_verify_in_CI : Bool := { defValue := false diff --git a/Mathlib/Tactic/Simps/Basic.lean b/Mathlib/Tactic/Simps/Basic.lean index bf8227a2bae45..1e8297e6b47d7 100644 --- a/Mathlib/Tactic/Simps/Basic.lean +++ b/Mathlib/Tactic/Simps/Basic.lean @@ -574,11 +574,11 @@ def applyProjectionRules (projs : Array ParsedProjectionData) (rules : Array Pro proj else projs.push {strName := nm, newName := nm, strStx := stx, newStx := stx, isPrefix := true} trace[simps.debug] "Projection info after applying the rules: {projs}." - unless (projs.map (·.newName)).toList.Nodup do throwError - "Invalid projection names. Two projections have the same name.\n{"" - }This is likely because a custom composition of projections was given the same name as an {"" - }existing projection. Solution: rename the existing projection (before naming the {"" - }custom projection)." + unless (projs.map (·.newName)).toList.Nodup do throwError "\ + Invalid projection names. Two projections have the same name.\n\ + This is likely because a custom composition of projections was given the same name as an \ + existing projection. Solution: rename the existing projection (before naming the \ + custom projection)." pure projs /-- Auxiliary function for `getRawProjections`. @@ -609,12 +609,13 @@ def findProjection (str : Name) (proj : ParsedProjectionData) let customProjType ← MetaM.run' (inferType customProj) let rawExprType ← MetaM.run' (inferType rawExpr) if (← MetaM.run' (isDefEq customProjType rawExprType)) then - throwError "Invalid custom projection:{indentExpr customProj}\n{"" - }Expression is not definitionally equal to {indentExpr rawExpr}" else - throwError "Invalid custom projection:\n {customProj}\n{"" - }Expression has different type than {str ++ proj.strName}. Given type:{ - indentExpr customProjType}\nExpected type:{indentExpr rawExprType - }\nNote: make sure order of implicit arguments is exactly the same." + throwError "Invalid custom projection:{indentExpr customProj}\n\ + Expression is not definitionally equal to {indentExpr rawExpr}" + else + throwError "Invalid custom projection:{indentExpr customProj}\n\ + Expression has different type than {str ++ proj.strName}. Given type:\ + {indentExpr customProjType}\nExpected type:{indentExpr rawExprType}\n\ + Note: make sure order of implicit arguments is exactly the same." | _ => _ ← MetaM.run' <| TermElabM.run' <| addTermInfo proj.newStx rawExpr pure {proj with expr? := some rawExpr, projNrs := nrs} @@ -628,9 +629,9 @@ def checkForUnusedCustomProjs (stx : Syntax) (str : Name) (projs : Array ParsedP let customDeclarations := env.constants.map₂.foldl (init := #[]) fun xs nm _ => if (str ++ `Simps).isPrefixOf nm && !nm.isInternalDetail then xs.push nm else xs if nrCustomProjections < customDeclarations.size then - Linter.logLintIf linter.simpsUnusedCustomDeclarations stx - m!"Not all of the custom declarations {customDeclarations} are used. Double check the { - ""}spelling, and use `?` to get more information." + Linter.logLintIf linter.simpsUnusedCustomDeclarations stx m!"\ + Not all of the custom declarations {customDeclarations} are used. Double check the \ + spelling, and use `?` to get more information." /-- If a structure has a field that corresponds to a coercion to functions or sets, or corresponds to notation, find the custom projection that uses this coercion or notation. @@ -648,8 +649,8 @@ def findAutomaticProjectionsAux (str : Name) (proj : ParsedProjectionData) (args let findArgs ← unsafe evalConst findArgType findArgs let classArgs ← try findArgs str className args catch ex => - trace[simps.debug] "Projection {proj.strName} is likely unrelated to the projection of { - className}:\n{ex.toMessageData}" + trace[simps.debug] "Projection {proj.strName} is likely unrelated to the projection of \ + {className}:\n{ex.toMessageData}" return none let classArgs ← classArgs.mapM fun e => match e with | none => mkFreshExprMVar none @@ -661,8 +662,8 @@ def findAutomaticProjectionsAux (str : Name) (proj : ParsedProjectionData) (args let eInstType ← try withoutErrToSorry (elabAppArgs (← Term.mkConst className) #[] classArgs none true false) catch ex => - trace[simps.debug] "Projection doesn't have the right type for the automatic projection:\n{ - ex.toMessageData}" + trace[simps.debug] "Projection doesn't have the right type for the automatic projection:\n\ + {ex.toMessageData}" return none return ← withLocalDeclD `self eStr fun instStr ↦ do trace[simps.debug] "found projection {proj.strName}. Trying to synthesize {eInstType}." @@ -689,13 +690,13 @@ def findAutomaticProjections (str : Name) (projs : Array ParsedProjectionData) : let projs ← projs.mapM fun proj => do if let some (projExpr, projName) := ← findAutomaticProjectionsAux str proj args then unless ← isDefEq projExpr proj.expr?.get! do - throwError "The projection {proj.newName} is not definitionally equal to an application { - ""}of {projName}:{indentExpr proj.expr?.get!}\nvs{indentExpr projExpr}" + throwError "The projection {proj.newName} is not definitionally equal to an application \ + of {projName}:{indentExpr proj.expr?.get!}\nvs{indentExpr projExpr}" if proj.isCustom then - trace[simps.verbose] "Warning: Projection {proj.newName} is given manually by the user, { - ""}but it can be generated automatically." + trace[simps.verbose] "Warning: Projection {proj.newName} is given manually by the user, \ + but it can be generated automatically." return proj - trace[simps.verbose] "Using {indentExpr projExpr}\n for projection {proj.newName}." + trace[simps.verbose] "Using {indentExpr projExpr}\nfor projection {proj.newName}." return { proj with expr? := some projExpr } return proj return projs @@ -1019,8 +1020,8 @@ partial def addProjections (nm : Name) (type lhs rhs : Expr) throwError "Invalid `simps` attribute. Target {str} is not a structure" if !todoNext.isEmpty && str ∉ cfg.notRecursive then let firstTodo := todoNext.head!.1 - throwError "Invalid simp lemma {nm.appendAfter firstTodo}.\nProjection { - (firstTodo.splitOn "_")[1]!} doesn't exist, because target {str} is not a structure." + throwError "Invalid simp lemma {nm.appendAfter firstTodo}.\nProjection \ + {(firstTodo.splitOn "_")[1]!} doesn't exist, because target {str} is not a structure." if cfg.fullyApplied then addProjection stxProj univs nm tgt lhsAp rhsAp newArgs cfg else @@ -1044,37 +1045,38 @@ partial def addProjections (nm : Name) (type lhs rhs : Expr) -- if I'm about to run into an error, try to set the transparency for `rhsMd` higher. if cfg.rhsMd == .reducible && (mustBeStr || !todoNext.isEmpty || !toApply.isEmpty) then trace[simps.debug] "Using relaxed reducibility." - Linter.logLintIf linter.simpsNoConstructor ref - m!"The definition {nm} is not a constructor application. Please use `@[simps!]` instead.{ - ""}\n\nExplanation: `@[simps]` uses the definition to find what the simp lemmas should { - ""}be. If the definition is a constructor, then this is easy, since the values of the { - ""}projections are just the arguments to the constructor. If the definition is not a { - ""}constructor, then `@[simps]` will unfold the right-hand side until it has found a { - ""}constructor application, and uses those values.\n\n{ - ""}This might not always result in the simp-lemmas you want, so you are advised to use { - ""}`@[simps?]` to double-check whether `@[simps]` generated satisfactory lemmas.\n{ - ""}Note 1: `@[simps!]` also calls the `simp` tactic, and this can be expensive in certain { - ""}cases.\n{ - ""}Note 2: `@[simps!]` is equivalent to `@[simps (config := \{rhsMd := .default, { - ""}simpRhs := true})]`. You can also try `@[simps (config := \{rhsMd := .default})]` { - ""}to still unfold the definitions, but avoid calling `simp` on the resulting statement.\n{ - ""}Note 3: You need `simps!` if not all fields are given explicitly in this definition, { - ""}even if the definition is a constructor application. For example, if you give a { - ""}`MulEquiv` by giving the corresponding `Equiv` and the proof that it respects { - ""}multiplication, then you need to mark it as `@[simps!]`, since the attribute needs to { - ""}unfold the corresponding `Equiv` to get to the `toFun` field." + Linter.logLintIf linter.simpsNoConstructor ref m!"\ + The definition {nm} is not a constructor application. Please use `@[simps!]` instead.\n\ + \n\ + Explanation: `@[simps]` uses the definition to find what the simp lemmas should \ + be. If the definition is a constructor, then this is easy, since the values of the \ + projections are just the arguments to the constructor. If the definition is not a \ + constructor, then `@[simps]` will unfold the right-hand side until it has found a \ + constructor application, and uses those values.\n\n\ + This might not always result in the simp-lemmas you want, so you are advised to use \ + `@[simps?]` to double-check whether `@[simps]` generated satisfactory lemmas.\n\ + Note 1: `@[simps!]` also calls the `simp` tactic, and this can be expensive in certain \ + cases.\n\ + Note 2: `@[simps!]` is equivalent to `@[simps (config := \{rhsMd := .default, \ + simpRhs := true})]`. You can also try `@[simps (config := \{rhsMd := .default})]` \ + to still unfold the definitions, but avoid calling `simp` on the resulting statement.\n\ + Note 3: You need `simps!` if not all fields are given explicitly in this definition, \ + even if the definition is a constructor application. For example, if you give a \ + `MulEquiv` by giving the corresponding `Equiv` and the proof that it respects \ + multiplication, then you need to mark it as `@[simps!]`, since the attribute needs to \ + unfold the corresponding `Equiv` to get to the `toFun` field." let nms ← addProjections nm type lhs rhs args mustBeStr { cfg with rhsMd := .default, simpRhs := true } todo toApply return if addThisProjection then nms.push nm else nms if !toApply.isEmpty then - throwError "Invalid simp lemma {nm}.\nThe given definition is not a constructor {"" - }application:{indentExpr rhsWhnf}" + throwError "Invalid simp lemma {nm}.\nThe given definition is not a constructor \ + application:{indentExpr rhsWhnf}" if mustBeStr then - throwError "Invalid `simps` attribute. The body is not a constructor application:{ - indentExpr rhsWhnf}" + throwError "Invalid `simps` attribute. The body is not a constructor application:\ + {indentExpr rhsWhnf}" if !todoNext.isEmpty then - throwError "Invalid simp lemma {nm.appendAfter todoNext.head!.1}.\n{"" - }The given definition is not a constructor application:{indentExpr rhsWhnf}" + throwError "Invalid simp lemma {nm.appendAfter todoNext.head!.1}.\n\ + The given definition is not a constructor application:{indentExpr rhsWhnf}" if !addThisProjection then if cfg.fullyApplied then addProjection stxProj univs nm tgt lhsAp rhsEta newArgs cfg @@ -1090,8 +1092,8 @@ partial def addProjections (nm : Name) (type lhs rhs : Expr) let some ⟨newRhs, _⟩ := projInfo[idx]? | throwError "unreachable: index of composite projection is out of bounds." let newType ← inferType newRhs - trace[simps.debug] "Applying a custom composite projection. Todo: {toApply}. Current lhs:{ - indentExpr lhsAp}" + trace[simps.debug] "Applying a custom composite projection. Todo: {toApply}. Current lhs:\ + {indentExpr lhsAp}" return ← addProjections nm newType lhsAp newRhs newArgs false cfg todo rest trace[simps.debug] "Not in the middle of applying a custom composite projection" /- We stop if no further projection is specified or if we just reduced an eta-expansion and we @@ -1105,11 +1107,14 @@ partial def addProjections (nm : Name) (type lhs rhs : Expr) fun proj ↦ !(proj.getString ++ "_").isPrefixOf x then let simpLemma := nm.appendAfter x let neededProj := (x.splitOn "_")[0]! - throwError "Invalid simp lemma {simpLemma}. Structure {str} does not have projection {"" - }{neededProj}.\nThe known projections are:\n {projs}\nYou can also see this information {"" - }by running\n `initialize_simps_projections? {str}`.\nNote: these projection names might {"" - }be customly defined for `simps`, and could differ from the projection names of the {"" - }structure." + throwError "Invalid simp lemma {simpLemma}. \ + Structure {str} does not have projection {neededProj}.\n\ + The known projections are:\ + {indentD <| toMessageData projs}\n\ + You can also see this information by running\ + \n `initialize_simps_projections? {str}`.\n\ + Note: these projection names might be customly defined for `simps`, \ + and could differ from the projection names of the structure." let nms ← projInfo.concatMapM fun ⟨newRhs, proj, projExpr, projNrs, isDefault, isPrefix⟩ ↦ do let newType ← inferType newRhs let newTodo := todo.filterMap diff --git a/Mathlib/Tactic/Simps/NotationClass.lean b/Mathlib/Tactic/Simps/NotationClass.lean index 5c16cb4328b21..c86ffb059e124 100644 --- a/Mathlib/Tactic/Simps/NotationClass.lean +++ b/Mathlib/Tactic/Simps/NotationClass.lean @@ -53,8 +53,8 @@ def defaultfindArgs : findArgType := λ _ className args => do else if args.size == 1 then return mkArray arity args[0]! else - throwError "initialize_simps_projections cannot automatically find arguments for class { - className}" + throwError "initialize_simps_projections cannot automatically find arguments for class \ + {className}" /-- Find arguments by duplicating the first argument. Used for `pow`. -/ def copyFirst : findArgType := λ _ _ args => return (args.push <| args[0]?.getD default).map some diff --git a/Mathlib/Tactic/TermCongr.lean b/Mathlib/Tactic/TermCongr.lean index 702e0a0a7dc5e..8194e30a1f9e9 100644 --- a/Mathlib/Tactic/TermCongr.lean +++ b/Mathlib/Tactic/TermCongr.lean @@ -282,8 +282,8 @@ Throws an error if the `lhs` and `rhs` have non-defeq types. If `pf? = none`, this returns the `rfl` proof. -/ def CongrResult.eq (res : CongrResult) : MetaM Expr := do unless ← isDefEq (← inferType res.lhs) (← inferType res.rhs) do - throwError "Expecting{indentD res.lhs}\nand{indentD res.rhs}\n{"" - }to have definitionally equal types." + throwError "Expecting{indentD res.lhs}\nand{indentD res.rhs}\n\ + to have definitionally equal types." match res.pf? with | some pf => pf .eq | none => mkEqRefl res.lhs @@ -369,11 +369,11 @@ where let some (_, lhs', _, rhs') := (← whnf pfTy).sides? | panic! "Unexpectedly did not generate an eq or heq" unless ← isDefEq lhs lhs' do - throwError "Congruence hole has type{indentD pfTy}\n{"" - }but its left-hand side is not definitionally equal to the expected value{indentD lhs}" + throwError "Congruence hole has type{indentD pfTy}\n\ + but its left-hand side is not definitionally equal to the expected value{indentD lhs}" unless ← isDefEq rhs rhs' do - throwError "Congruence hole has type{indentD pfTy}\n{"" - }but its right-hand side is not definitionally equal to the expected value{indentD rhs}" + throwError "Congruence hole has type{indentD pfTy}\n\ + but its right-hand side is not definitionally equal to the expected value{indentD rhs}" return pf /-- Force the lhs and rhs to be defeq. For when `dsimp`-like congruence is necessary. @@ -383,8 +383,8 @@ def CongrResult.defeq (res : CongrResult) : MetaM CongrResult := do return res else unless ← isDefEq res.lhs res.rhs do - throwError "Cannot generate congruence because we need{indentD res.lhs}\n{"" - }to be definitionally equal to{indentD res.rhs}" + throwError "Cannot generate congruence because we need{indentD res.lhs}\n\ + to be definitionally equal to{indentD res.rhs}" -- Propagate types into any proofs that we're dropping: discard <| res.eq return {res with pf? := none} @@ -417,8 +417,8 @@ def CongrResult.mkDefault' (mvarCounterSaved : Nat) (lhs rhs : Expr) : MetaM Con /-- Throw an internal error. -/ def throwCongrEx (lhs rhs : Expr) (msg : MessageData) : MetaM α := do - throwError "congr(...) failed with left-hand side{indentD lhs}\n{"" - }and right-hand side {indentD rhs}\n{msg}" + throwError "congr(...) failed with left-hand side{indentD lhs}\n\ + and right-hand side {indentD rhs}\n{msg}" /-- If `lhs` or `rhs` is a congruence hole, then process it. Only process ones that are at least as new as `mvarCounterSaved` @@ -436,11 +436,11 @@ def mkCongrOfCHole? (mvarCounterSaved : Nat) (lhs rhs : Expr) : MetaM (Option Co throwCongrEx lhs rhs "Elaborated types of congruence holes are not defeq." if let some (_, lhsVal, _, rhsVal) := (← whnf <| ← inferType pf1).sides? then unless ← isDefEq val1 lhsVal do - throwError "Left-hand side of congruence hole is{indentD lhsVal}\n{"" - }but is expected to be{indentD val1}" + throwError "Left-hand side of congruence hole is{indentD lhsVal}\n\ + but is expected to be{indentD val1}" unless ← isDefEq val2 rhsVal do - throwError "Right-hand side of congruence hole is{indentD rhsVal}\n{"" - }but is expected to be{indentD val2}" + throwError "Right-hand side of congruence hole is{indentD rhsVal}\n\ + but is expected to be{indentD val2}" return some <| CongrResult.mk' val1 val2 pf1 | some .., none => throwCongrEx lhs rhs "Right-hand side lost its congruence hole annotation." @@ -616,11 +616,11 @@ def elabTermCongr : Term.TermElab := fun stx expectedType? => do let rhs ← elaboratePattern t expRhsTy false -- Note: these defeq checks can leak congruence holes. unless ← isDefEq expLhs lhs do - throwError "Left-hand side of elaborated pattern{indentD lhs}\n{"" - }is not definitionally equal to left-hand side of expected type{indentD expectedType}" + throwError "Left-hand side of elaborated pattern{indentD lhs}\n\ + is not definitionally equal to left-hand side of expected type{indentD expectedType}" unless ← isDefEq expRhs rhs do - throwError "Right-hand side of elaborated pattern{indentD rhs}\n{"" - }is not definitionally equal to right-hand side of expected type{indentD expectedType}" + throwError "Right-hand side of elaborated pattern{indentD rhs}\n\ + is not definitionally equal to right-hand side of expected type{indentD expectedType}" Term.synthesizeSyntheticMVars (mayPostpone := true) let res ← mkCongrOf 0 mvarCounterSaved lhs rhs let expectedType' ← whnf expectedType diff --git a/Mathlib/Tactic/ToAdditive.lean b/Mathlib/Tactic/ToAdditive.lean index 6320f881ccf17..83bb87dd8afea 100644 --- a/Mathlib/Tactic/ToAdditive.lean +++ b/Mathlib/Tactic/ToAdditive.lean @@ -115,14 +115,14 @@ register_option linter.toAdditiveReorder : Bool := { certain attributes -/ register_option linter.existingAttributeWarning : Bool := { defValue := true - descr := "Linter, mostly used by `@[to_additive]`, that checks that the source declaration " ++ - "doesn't have certain attributes" } + descr := "Linter, mostly used by `@[to_additive]`, that checks that the source declaration \ + doesn't have certain attributes" } /-- Linter to check that the `to_additive` attribute is not given manually -/ register_option linter.toAdditiveGenerateName : Bool := { defValue := true - descr := "Linter used by `@[to_additive]` that checks if `@[to_additive]` automatically " ++ - "generates the user-given name" } + descr := "Linter used by `@[to_additive]` that checks if `@[to_additive]` automatically \ + generates the user-given name" } /-- Linter to check whether the user correctly specified that the additive declaration already exists -/ @@ -157,17 +157,17 @@ applying `@[to_additive]`. It is applied automatically by the `(reorder := ...)` initialize reorderAttr : NameMapExtension (List $ List Nat) ← registerNameMapAttribute { name := `to_additive_reorder - descr := - "Auxiliary attribute for `to_additive` that stores arguments that need to be reordered. - This should not appear in any file. - We keep it as an attribute for now so that mathport can still use it, and it can generate a - warning." + descr := "\ + Auxiliary attribute for `to_additive` that stores arguments that need to be reordered. \ + This should not appear in any file. \ + We keep it as an attribute for now so that mathport can still use it, and it can generate a \ + warning." add := fun | _, stx@`(attr| to_additive_reorder $[$[$reorders:num]*],*) => do - Linter.logLintIf linter.toAdditiveReorder stx - m!"Using this attribute is deprecated. Use `@[to_additive (reorder := )]` {"" - }instead.\nThat will also generate the additive version with the arguments swapped, {"" - }so you are probably able to remove the manually written additive declaration." + Linter.logLintIf linter.toAdditiveReorder stx m!"\ + Using this attribute is deprecated. Use `@[to_additive (reorder := )]` instead.\n\n\ + That will also generate the additive version with the arguments swapped, \ + so you are probably able to remove the manually written additive declaration." pure <| reorders.toList.map (·.toList.map (·.raw.isNatLit?.get! - 1)) | _, _ => throwUnsupportedSyntax } @@ -194,8 +194,8 @@ Warning: interactions between this and the `(reorder := ...)` argument are not w initialize relevantArgAttr : NameMapExtension Nat ← registerNameMapAttribute { name := `to_additive_relevant_arg - descr := "Auxiliary attribute for `to_additive` stating" ++ - " which arguments are the types with a multiplicative structure." + descr := "Auxiliary attribute for `to_additive` stating \ + which arguments are the types with a multiplicative structure." add := fun | _, `(attr| to_additive_relevant_arg $id) => pure <| id.1.isNatLit?.get!.pred | _, _ => throwUnsupportedSyntax } @@ -390,8 +390,8 @@ where /-- Implementation of `applyReplacementFun`. -/ if let some fxd := additiveTest findTranslation? ignore gAllArgs[relevantArgId]! then Id.run <| do if trace then - dbg_trace s!"The application of {nm} contains the fixed type {fxd - }, so it is not changed" + dbg_trace s!"The application of {nm} contains the fixed type \ + {fxd}, so it is not changed" gf else r gf @@ -409,8 +409,8 @@ where /-- Implementation of `applyReplacementFun`. -/ if let some changedArgNrs := changeNumeral? nm then if additiveTest findTranslation? ignore firstArg |>.isNone then if trace then - dbg_trace s!"applyReplacementFun: We change the numerals in this expression. { - ""}However, we will still recurse into all the non-numeral arguments." + dbg_trace s!"applyReplacementFun: We change the numerals in this expression. \ + However, we will still recurse into all the non-numeral arguments." -- In this case, we still update all arguments of `g` that are not numerals, -- since all other arguments can contain subexpressions like -- `(fun x ↦ ℕ) (1 : G)`, and we have to update the `(1 : G)` to `(0 : G)` @@ -426,8 +426,8 @@ where /-- Implementation of `applyReplacementFun`. -/ | .proj n₀ idx e => do let n₁ := n₀.mapPrefix findTranslation? if trace then - dbg_trace s!"applyReplacementFun: in projection {e}.{idx} of type {n₀}, {"" - }replace type with {n₁}" + dbg_trace s!"applyReplacementFun: in projection {e}.{idx} of type {n₀}, \ + replace type with {n₁}" return some <| .proj n₁ idx <| ← r e | _ => return none @@ -545,9 +545,9 @@ partial def transformDeclAux -- if this declaration is not `pre` and not an internal declaration, we return an error, -- since we should have already translated this declaration. if src != pre && !src.isInternalDetail then - throwError "The declaration {pre} depends on the declaration {src} which is in the namespace { - pre}, but does not have the `@[to_additive]` attribute. This is not supported.\n{"" - }Workaround: move {src} to a different namespace." + throwError "The declaration {pre} depends on the declaration {src} which is in the namespace \ + {pre}, but does not have the `@[to_additive]` attribute. This is not supported.\n\ + Workaround: move {src} to a different namespace." -- we find the additive name of `src` let tgt ← findTargetName env src pre tgt_pre -- we skip if we already transformed this declaration before. @@ -584,9 +584,9 @@ partial def transformDeclAux -- and emit a more helpful error message if it fails discard <| MetaM.run' <| inferType value catch - | Exception.error _ msg => throwError "@[to_additive] failed. - Type mismatch in additive declaration. For help, see the docstring - of `to_additive.attr`, section `Troubleshooting`. + | Exception.error _ msg => throwError "@[to_additive] failed. \ + Type mismatch in additive declaration. For help, see the docstring \ + of `to_additive.attr`, section `Troubleshooting`. \ Failed to add declaration\n{tgt}:\n{msg}" | _ => panic! "unreachable" if isNoncomputable env src then @@ -618,13 +618,14 @@ def warnExt [Inhabited σ] (stx : Syntax) (ext : PersistentEnvExtension α β σ (thisAttr attrName src tgt : Name) : CoreM Unit := do if f (ext.getState (← getEnv)) src then Linter.logLintIf linter.existingAttributeWarning stx <| - m!"The source declaration {src} was given attribute {attrName} before calling @[{thisAttr}]. { - ""}The preferred method is to use `@[{thisAttr} (attr := {attrName})]` to apply the { - ""}attribute to both {src} and the target declaration {tgt}." ++ + m!"The source declaration {src} was given attribute {attrName} before calling @[{thisAttr}]. \ + The preferred method is to use `@[{thisAttr} (attr := {attrName})]` to apply the \ + attribute to both {src} and the target declaration {tgt}." ++ if thisAttr == `to_additive then - m!"\nSpecial case: If this declaration was generated by @[to_additive] { - ""}itself, you can use @[to_additive (attr := to_additive, {attrName})] on the original { - ""}declaration." else "" + m!"\nSpecial case: If this declaration was generated by @[to_additive] \ + itself, you can use @[to_additive (attr := to_additive, {attrName})] on the original \ + declaration." + else "" /-- Warn the user when the multiplicative declaration has a simple scoped attribute. -/ def warnAttr [Inhabited β] (stx : Syntax) (attr : SimpleScopedEnvExtension α β) @@ -841,9 +842,9 @@ def targetName (cfg : Config) (src : Name) : CoreM Name := do let pre := pre.mapPrefix <| findTranslation? (← getEnv) let (pre1, pre2) := pre.splitAt (depth - 1) if cfg.tgt == pre2.str tgt_auto && !cfg.allowAutoName && cfg.tgt != src then - Linter.logLintIf linter.toAdditiveGenerateName cfg.ref - m!"to_additive correctly autogenerated target name for {src}. {"\n" - }You may remove the explicit argument {cfg.tgt}." + Linter.logLintIf linter.toAdditiveGenerateName cfg.ref m!"\ + to_additive correctly autogenerated target name for {src}.\n\ + You may remove the explicit argument {cfg.tgt}." let res := if cfg.tgt == .anonymous then pre.str tgt_auto else pre1 ++ cfg.tgt -- we allow translating to itself if `tgt == src`, which is occasionally useful for `additiveTest` if res == src && cfg.tgt != src then @@ -915,11 +916,11 @@ partial def applyAttributes (stx : Syntax) (rawAttrs : Array Syntax) (thisAttr s if linter.existingAttributeWarning.get (← getOptions) then let appliedAttrs ← getAllSimpAttrs src if appliedAttrs.size > 0 then - Linter.logLintIf linter.existingAttributeWarning stx <| - m!"The source declaration {src} was given the simp-attribute(s) {appliedAttrs} before { - ""}calling @[{thisAttr}]. The preferred method is to use { - ""}`@[{thisAttr} (attr := {appliedAttrs})]` to apply the attribute to both { - src} and the target declaration {tgt}." + Linter.logLintIf linter.existingAttributeWarning stx m!"\ + The source declaration {src} was given the simp-attribute(s) {appliedAttrs} before \ + calling @[{thisAttr}]. The preferred method is to use \ + `@[{thisAttr} (attr := {appliedAttrs})]` to apply the attribute to both \ + {src} and the target declaration {tgt}." warnAttr stx Std.Tactic.Ext.extExtension (fun b n => (b.tree.values.any fun t => t.declName = n)) thisAttr `ext src tgt warnAttr stx Std.Tactic.reflExt (·.values.contains ·) thisAttr `refl src tgt @@ -1015,8 +1016,8 @@ partial def addToAdditiveAttr (src : Name) (cfg : Config) (kind := AttributeKind if cfg.existing == some !alreadyExists && !(← isInductive src) then Linter.logLintIf linter.toAdditiveExisting cfg.ref <| if alreadyExists then - m!"The additive declaration already exists. Please specify this explicitly using { - ""}`@[to_additive existing]`." + m!"The additive declaration already exists. Please specify this explicitly using \ + `@[to_additive existing]`." else "The additive declaration doesn't exist. Please remove the option `existing`." if cfg.reorder != [] then diff --git a/Mathlib/Tactic/Variable.lean b/Mathlib/Tactic/Variable.lean index 40ca7d7cd437c..492733e07cb7f 100644 --- a/Mathlib/Tactic/Variable.lean +++ b/Mathlib/Tactic/Variable.lean @@ -161,21 +161,21 @@ partial def completeBinders' (maxSteps : Nat) (gas : Nat) TermElabM (TSyntaxArray ``bracketedBinder × Array Bool) := do if 0 < gas && i < binders.size then let binder := binders[i]! - trace[«variable?»] - "Have {(← getLCtx).getFVarIds.size} fvars and {(← getLocalInstances).size} local instances{ - ""}. Looking at{indentD binder}" + trace[«variable?»] "\ + Have {(← getLCtx).getFVarIds.size} fvars and {(← getLocalInstances).size} local instances. \ + Looking at{indentD binder}" let sub? ← getSubproblem binder (bracketedBinderType binder).get! if let some (goalMsg, binder') := sub? then trace[«variable?»] m!"new subproblem:{indentD binder'}" if binders.any (stop := i) (· == binder') then let binders' := binders.extract 0 i - throwErrorAt binder - "Binder{indentD binder}\nwas not able to satisfy one of its dependencies using { - ""}the pre-existing binder{indentD binder'}\n\n{ - ""}This might be due to differences in implicit arguments, which are not represented { - ""}in binders since they are generated by pretty printing unsatisfied dependencies.\n\n{ - ""}Current variable command:{indentD (← `(command| variable $binders'*))}\n\n{ - ""}Local context for the unsatisfied dependency:{goalMsg}" + throwErrorAt binder "\ + Binder{indentD binder}\nwas not able to satisfy one of its dependencies using \ + the pre-existing binder{indentD binder'}\n\n\ + This might be due to differences in implicit arguments, which are not represented \ + in binders since they are generated by pretty printing unsatisfied dependencies.\n\n\ + Current variable command:{indentD (← `(command| variable $binders'*))}\n\n\ + Local context for the unsatisfied dependency:{goalMsg}" let binders := binders.insertAt! i binder' completeBinders' maxSteps (gas - 1) checkRedundant binders toOmit i else @@ -215,9 +215,9 @@ partial def completeBinders' (maxSteps : Nat) (gas : Nat) else if gas == 0 && i < binders.size then let binders' := binders.extract 0 i - logErrorAt binders[i]! m!"Maximum recursion depth for variables! reached. This might be a { - ""}bug, or you can try adjusting `set_option variable?.maxSteps {maxSteps}`{ - ""}\n\nCurrent variable command:{indentD (← `(command| variable $binders'*))}" + logErrorAt binders[i]! m!"Maximum recursion depth for variables! reached. This might be a \ + bug, or you can try adjusting `set_option variable?.maxSteps {maxSteps}`\n\n\ + Current variable command:{indentD (← `(command| variable $binders'*))}" return (binders, toOmit) where isVariableAlias (type : Expr) : MetaM Bool := do diff --git a/Mathlib/Tactic/Widget/Calc.lean b/Mathlib/Tactic/Widget/Calc.lean index 0e2a1c8d4b2cf..abc5859ec2dbf 100644 --- a/Mathlib/Tactic/Widget/Calc.lean +++ b/Mathlib/Tactic/Widget/Calc.lean @@ -86,11 +86,12 @@ def suggestSteps (pos : Array Lean.SubExpr.GoalsLocation) (goalType : Expr) (par let insertedCode := match isSelectedLeft, isSelectedRight with | true, true => if params.isFirst then - s!"{lhsStr} {relStr} {newLhsStr} := by sorry\n{spc}_ {relStr} {newRhsStr} := by sorry\n" ++ - s!"{spc}_ {relStr} {rhsStr} := by sorry" + s!"{lhsStr} {relStr} {newLhsStr} := by sorry\n{spc}_ {relStr} {newRhsStr} := by sorry\n\ + {spc}_ {relStr} {rhsStr} := by sorry" else - s!"_ {relStr} {newLhsStr} := by sorry\n{spc}_ {relStr} {newRhsStr} := by sorry\n" ++ - s!"{spc}_ {relStr} {rhsStr} := by sorry" + s!"_ {relStr} {newLhsStr} := by sorry\n{spc}\ + _ {relStr} {newRhsStr} := by sorry\n{spc}\ + _ {relStr} {rhsStr} := by sorry" | false, true => if params.isFirst then s!"{lhsStr} {relStr} {newRhsStr} := by sorry\n{spc}_ {relStr} {rhsStr} := by sorry" diff --git a/Mathlib/Util/AssertExists.lean b/Mathlib/Util/AssertExists.lean index 4c901b2d562da..41691c9dad605 100644 --- a/Mathlib/Util/AssertExists.lean +++ b/Mathlib/Util/AssertExists.lean @@ -49,7 +49,7 @@ You should *not* delete the `assert_not_exists` statement without careful discus -/ elab "assert_not_exists " n:ident : command => do let [] ← try resolveGlobalConstWithInfos n catch _ => return - | throw <| .error n <| m!"Declaration {n} is not allowed to be imported by this file.\n\n{ - ""}These invariants are maintained by `assert_not_exists` statements, { - ""}and exist in order to ensure that \"complicated\" parts of the library { - ""}are not accidentally introduced as dependencies of \"simple\" parts of the library." + | throw <| .error n m!"Declaration {n} is not allowed to be imported by this file.\n\n\ + These invariants are maintained by `assert_not_exists` statements, \ + and exist in order to ensure that \"complicated\" parts of the library \ + are not accidentally introduced as dependencies of \"simple\" parts of the library." diff --git a/Mathlib/Util/Imports.lean b/Mathlib/Util/Imports.lean index 7bbe6ecf4f006..146934733ce73 100644 --- a/Mathlib/Util/Imports.lean +++ b/Mathlib/Util/Imports.lean @@ -190,8 +190,8 @@ elab "#redundant_imports" : command => do if redundant.isEmpty then logInfo "No transitively redundant imports found." else - logInfo <| "Found the following transitively redundant imports:\n" ++ - m!"{Format.joinSep redundant.toList "\n"}" + logInfo m!"Found the following transitively redundant imports:\n\ + {Format.joinSep redundant.toList "\n"}" /-- Return the names of the modules in which constants used in the current file were defined, diff --git a/test/GCongr/inequalities.lean b/test/GCongr/inequalities.lean index cb613c457d211..70caad895e639 100644 --- a/test/GCongr/inequalities.lean +++ b/test/GCongr/inequalities.lean @@ -104,7 +104,8 @@ example {x : ℤ} (hx : x ≥ 12) (h : Even x) : Even x := by example {a b x c d : ℝ} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 1 ≤ x + 1) : x * a + c ≤ x * b + d := by success_if_fail_with_msg - "rel failed, cannot prove goal by 'substituting' the listed relationships. The steps which could not be automatically justified were: \n0 ≤ x\nc ≤ d" + "rel failed, cannot prove goal by 'substituting' the listed relationships. \ + The steps which could not be automatically justified were:\n0 ≤ x\nc ≤ d" (rel [h1]) have : 0 ≤ x := by linarith rel [h1, h2] diff --git a/test/eqns.lean b/test/eqns.lean index 1b263d7c7b7f1..25c6c791108d1 100644 --- a/test/eqns.lean +++ b/test/eqns.lean @@ -22,7 +22,7 @@ theorem t_def : t = 1 := rfl theorem t_def' : t = 1 := by rw [t] /-- -error: There already exist stored eqns for 't' registering new equations +error: There already exist stored eqns for 't'; registering new equations will not have the desired effect. -/ #guard_msgs(error) in From 2a17457d3236d97eec6687377c01a74fe2961ab7 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 1 Jan 2024 22:36:28 +0000 Subject: [PATCH 303/353] feat: missing lemmas about `Finsupp.update` (#9316) --- Mathlib/Data/Finsupp/Defs.lean | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Mathlib/Data/Finsupp/Defs.lean b/Mathlib/Data/Finsupp/Defs.lean index 0e254c3be2776..e5ccb62273dd2 100644 --- a/Mathlib/Data/Finsupp/Defs.lean +++ b/Mathlib/Data/Finsupp/Defs.lean @@ -600,6 +600,23 @@ theorem support_update_ne_zero [DecidableEq α] (h : b ≠ 0) : congr; apply Subsingleton.elim #align finsupp.support_update_ne_zero Finsupp.support_update_ne_zero +theorem support_update_subset [DecidableEq α] [DecidableEq M] : + support (f.update a b) ⊆ insert a f.support := by + rw [support_update] + split_ifs + · exact (erase_subset _ _).trans (subset_insert _ _) + · rfl + +theorem update_comm (f : α →₀ M) {a₁ a₂ : α} (h : a₁ ≠ a₂) (m₁ m₂ : M) : + update (update f a₁ m₁) a₂ m₂ = update (update f a₂ m₂) a₁ m₁ := + letI := Classical.decEq α + FunLike.coe_injective <| Function.update_comm h _ _ _ + +@[simp] theorem update_idem (f : α →₀ M) (a : α) (b c : M) : + update (update f a b) a c = update f a c := + letI := Classical.decEq α + FunLike.coe_injective <| Function.update_idem _ _ _ + end Update /-! ### Declarations about `erase` -/ @@ -673,6 +690,28 @@ theorem erase_zero (a : α) : erase a (0 : α →₀ M) = 0 := by classical rw [← support_eq_empty, support_erase, support_zero, erase_empty] #align finsupp.erase_zero Finsupp.erase_zero +theorem erase_eq_update_zero (f : α →₀ M) (a : α) : f.erase a = update f a 0 := + letI := Classical.decEq α + ext fun _ => (Function.update_apply _ _ _ _).symm + +-- The name matches `Finset.erase_insert_of_ne` +theorem erase_update_of_ne (f : α →₀ M) {a a' : α} (ha : a ≠ a') (b : M) : + erase a (update f a' b) = update (erase a f) a' b := by + rw [erase_eq_update_zero, erase_eq_update_zero, update_comm _ ha] + +-- not `simp` as `erase_of_not_mem_support` can prove this +theorem erase_idem (f : α →₀ M) (a : α) : + erase a (erase a f) = erase a f := by + rw [erase_eq_update_zero, erase_eq_update_zero, update_idem] + +@[simp] theorem update_erase_eq_update (f : α →₀ M) (a : α) (b : M) : + update (erase a f) a b = update f a b := by + rw [erase_eq_update_zero, update_idem] + +@[simp] theorem erase_update_eq_erase (f : α →₀ M) (a : α) (b : M) : + erase a (update f a b) = erase a f := by + rw [erase_eq_update_zero, erase_eq_update_zero, update_idem] + end Erase /-! ### Declarations about `onFinset` -/ From 4f83eae3dab88d0420554013e954bdf1d1808ddf Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 2 Jan 2024 05:36:50 +0000 Subject: [PATCH 304/353] chore(MeasureTheory): golf (#9374) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder/golf lemmas, add `ae_restrict_iff₀`. Also remove 3 lemmas that are no longer needed and can be proved in 1 line each. --- .../MeasureTheory/Integral/SetIntegral.lean | 30 ------------- Mathlib/MeasureTheory/Measure/Restrict.lean | 42 +++++++++---------- 2 files changed, 20 insertions(+), 52 deletions(-) diff --git a/Mathlib/MeasureTheory/Integral/SetIntegral.lean b/Mathlib/MeasureTheory/Integral/SetIntegral.lean index 2f91e4be9a4c1..3d306e4453607 100644 --- a/Mathlib/MeasureTheory/Integral/SetIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/SetIntegral.lean @@ -403,36 +403,6 @@ theorem set_integral_eq_integral_of_forall_compl_eq_zero (h : ∀ x, x ∉ s → set_integral_eq_integral_of_ae_compl_eq_zero (eventually_of_forall h) #align measure_theory.set_integral_eq_integral_of_forall_compl_eq_zero MeasureTheory.set_integral_eq_integral_of_forall_compl_eq_zero -lemma ae_restrict_eq_const_iff_ae_eq_const_of_mem {E : Type*} [MeasurableSpace E] - [MeasurableSingletonClass E] {f : α → E} (c : E) {s : Set α} - (f_mble : NullMeasurable f (μ.restrict s)) : - f =ᵐ[Measure.restrict μ s] (fun _ ↦ c) ↔ ∀ᵐ x ∂μ, x ∈ s → f x = c := by - simp only [Measure.ae, MeasurableSet.compl_iff, EventuallyEq, Filter.Eventually, - Pi.zero_apply, Filter.mem_mk, mem_setOf_eq] - rw [Measure.restrict_apply₀] - · constructor <;> intro h <;> rw [← h] <;> congr <;> ext x <;> aesop - · apply NullMeasurableSet.compl - convert f_mble (MeasurableSet.singleton c) - -lemma ae_restrict_eq_const_iff_ae_eq_const_of_mem' {E : Type*} (c : E) (f : α → E) {s : Set α} - (s_mble : MeasurableSet s) : - f =ᵐ[Measure.restrict μ s] (fun _ ↦ c) ↔ ∀ᵐ x ∂μ, x ∈ s → f x = c := by - simp only [Measure.ae, MeasurableSet.compl_iff, EventuallyEq, Filter.Eventually, - Pi.zero_apply, Filter.mem_mk, mem_setOf_eq] - rw [Measure.restrict_apply_eq_zero'] - · constructor <;> intro h <;> rw [← h] <;> congr <;> ext x <;> aesop - · exact s_mble - -/-- If a function equals zero almost everywhere w.r.t. restriction of the measure to `sᶜ`, then its -integral on `s` coincides with its integral on the whole space. -/ -lemma set_integral_eq_integral_of_ae_restrict_eq_zero (hs : f =ᵐ[μ.restrict sᶜ] 0) : - ∫ ω in s, f ω ∂μ = ∫ ω, f ω ∂μ := by - borelize E - refine set_integral_eq_integral_of_ae_compl_eq_zero ?_ - have f_mble : NullMeasurable f (μ.restrict sᶜ) := - NullMeasurable.congr measurable_const.nullMeasurable hs.symm - simpa only [mem_compl_iff] using (ae_restrict_eq_const_iff_ae_eq_const_of_mem 0 f_mble).mp hs - theorem set_integral_neg_eq_set_integral_nonpos [LinearOrder E] {f : α → E} (hf : AEStronglyMeasurable f μ) : ∫ x in {x | f x < 0}, f x ∂μ = ∫ x in {x | f x ≤ 0}, f x ∂μ := by diff --git a/Mathlib/MeasureTheory/Measure/Restrict.lean b/Mathlib/MeasureTheory/Measure/Restrict.lean index ae91cfbedab67..8a5b7cc6fad59 100644 --- a/Mathlib/MeasureTheory/Measure/Restrict.lean +++ b/Mathlib/MeasureTheory/Measure/Restrict.lean @@ -619,10 +619,14 @@ theorem ae_restrict_uIoc_iff [LinearOrder α] {a b : α} {P : α → Prop} : by rw [ae_restrict_uIoc_eq, eventually_sup] #align measure_theory.ae_restrict_uIoc_iff MeasureTheory.ae_restrict_uIoc_iff -theorem ae_restrict_iff {p : α → Prop} (hp : MeasurableSet { x | p x }) : +theorem ae_restrict_iff₀ {p : α → Prop} (hp : NullMeasurableSet { x | p x } (μ.restrict s)) : (∀ᵐ x ∂μ.restrict s, p x) ↔ ∀ᵐ x ∂μ, x ∈ s → p x := by - simp only [ae_iff, ← compl_setOf, Measure.restrict_apply hp.compl] + simp only [ae_iff, ← compl_setOf, Measure.restrict_apply₀ hp.compl] rw [iff_iff_eq]; congr with x; simp [and_comm] + +theorem ae_restrict_iff {p : α → Prop} (hp : MeasurableSet { x | p x }) : + (∀ᵐ x ∂μ.restrict s, p x) ↔ ∀ᵐ x ∂μ, x ∈ s → p x := + ae_restrict_iff₀ hp.nullMeasurableSet #align measure_theory.ae_restrict_iff MeasureTheory.ae_restrict_iff theorem ae_imp_of_ae_restrict {s : Set α} {p : α → Prop} (h : ∀ᵐ x ∂μ.restrict s, p x) : @@ -631,10 +635,15 @@ theorem ae_imp_of_ae_restrict {s : Set α} {p : α → Prop} (h : ∀ᵐ x ∂μ simpa [setOf_and, inter_comm] using measure_inter_eq_zero_of_restrict h #align measure_theory.ae_imp_of_ae_restrict MeasureTheory.ae_imp_of_ae_restrict -theorem ae_restrict_iff' {p : α → Prop} (hs : MeasurableSet s) : +theorem ae_restrict_iff'₀ {p : α → Prop} (hs : NullMeasurableSet s μ) : (∀ᵐ x ∂μ.restrict s, p x) ↔ ∀ᵐ x ∂μ, x ∈ s → p x := by - simp only [ae_iff, ← compl_setOf, restrict_apply_eq_zero' hs] + simp only [ae_iff, ← compl_setOf, restrict_apply₀' hs] rw [iff_iff_eq]; congr with x; simp [and_comm] +#align measure_theory.ae_restrict_iff'₀ MeasureTheory.ae_restrict_iff'₀ + +theorem ae_restrict_iff' {p : α → Prop} (hs : MeasurableSet s) : + (∀ᵐ x ∂μ.restrict s, p x) ↔ ∀ᵐ x ∂μ, x ∈ s → p x := + ae_restrict_iff'₀ hs.nullMeasurableSet #align measure_theory.ae_restrict_iff' MeasureTheory.ae_restrict_iff' theorem _root_.Filter.EventuallyEq.restrict {f g : α → δ} {s : Set α} (hfg : f =ᵐ[μ] g) : @@ -645,26 +654,18 @@ theorem _root_.Filter.EventuallyEq.restrict {f g : α → δ} {s : Set α} (hfg exact Measure.absolutelyContinuous_of_le Measure.restrict_le_self #align filter.eventually_eq.restrict Filter.EventuallyEq.restrict +theorem ae_restrict_mem₀ (hs : NullMeasurableSet s μ) : ∀ᵐ x ∂μ.restrict s, x ∈ s := + (ae_restrict_iff'₀ hs).2 (Filter.eventually_of_forall fun _ => id) +#align measure_theory.ae_restrict_mem₀ MeasureTheory.ae_restrict_mem₀ + theorem ae_restrict_mem (hs : MeasurableSet s) : ∀ᵐ x ∂μ.restrict s, x ∈ s := - (ae_restrict_iff' hs).2 (Filter.eventually_of_forall fun _ => id) + ae_restrict_mem₀ hs.nullMeasurableSet #align measure_theory.ae_restrict_mem MeasureTheory.ae_restrict_mem -theorem ae_restrict_mem₀ (hs : NullMeasurableSet s μ) : ∀ᵐ x ∂μ.restrict s, x ∈ s := by - rcases hs.exists_measurable_subset_ae_eq with ⟨t, hts, htm, ht_eq⟩ - rw [← restrict_congr_set ht_eq] - exact (ae_restrict_mem htm).mono hts -#align measure_theory.ae_restrict_mem₀ MeasureTheory.ae_restrict_mem₀ - theorem ae_restrict_of_ae {s : Set α} {p : α → Prop} (h : ∀ᵐ x ∂μ, p x) : ∀ᵐ x ∂μ.restrict s, p x := - Eventually.filter_mono (ae_mono Measure.restrict_le_self) h + h.filter_mono (ae_mono Measure.restrict_le_self) #align measure_theory.ae_restrict_of_ae MeasureTheory.ae_restrict_of_ae -theorem ae_restrict_iff'₀ {p : α → Prop} (hs : NullMeasurableSet s μ) : - (∀ᵐ x ∂μ.restrict s, p x) ↔ ∀ᵐ x ∂μ, x ∈ s → p x := by - refine' ⟨fun h => ae_imp_of_ae_restrict h, fun h => _⟩ - filter_upwards [ae_restrict_mem₀ hs, ae_restrict_of_ae h] with x hx h'x using h'x hx -#align measure_theory.ae_restrict_iff'₀ MeasureTheory.ae_restrict_iff'₀ - theorem ae_restrict_of_ae_restrict_of_subset {s t : Set α} {p : α → Prop} (hst : s ⊆ t) (h : ∀ᵐ x ∂μ.restrict t, p x) : ∀ᵐ x ∂μ.restrict s, p x := h.filter_mono (ae_mono <| Measure.restrict_mono hst (le_refl μ)) @@ -680,7 +681,6 @@ theorem ae_of_ae_restrict_of_ae_restrict_compl (t : Set α) {p : α → Prop} _ ≤ μ.restrict t { x | ¬p x } + μ.restrict tᶜ { x | ¬p x } := (add_le_add (le_restrict_apply _ _) (le_restrict_apply _ _)) _ = 0 := by rw [ae_iff.1 ht, ae_iff.1 htc, zero_add] - #align measure_theory.ae_of_ae_restrict_of_ae_restrict_compl MeasureTheory.ae_of_ae_restrict_of_ae_restrict_compl theorem mem_map_restrict_ae_iff {β} {s : Set α} {t : Set β} {f : α → β} (hs : MeasurableSet s) : @@ -780,9 +780,7 @@ lemma NullMeasurable.measure_preimage_eq_measure_restrict_preimage_of_ae_compl_e {t : Set β} (t_mble : MeasurableSet t) (ht : b ∉ t) : μ (f ⁻¹' t) = μ.restrict s (f ⁻¹' t) := by rw [Measure.restrict_apply₀ (f_mble t_mble)] - simp only [EventuallyEq, Filter.Eventually, Pi.zero_apply, Measure.ae, - MeasurableSet.compl_iff, Filter.mem_mk, mem_setOf_eq] at hs - rw [Measure.restrict_apply₀] at hs + rw [EventuallyEq, ae_iff, Measure.restrict_apply₀] at hs · apply le_antisymm _ (measure_mono (inter_subset_left _ _)) apply (measure_mono (Eq.symm (inter_union_compl (f ⁻¹' t) s)).le).trans apply (measure_union_le _ _).trans From a4e04c21f4c3cfeac08776068109d107da5d63f5 Mon Sep 17 00:00:00 2001 From: Newell Jensen Date: Tue, 2 Jan 2024 07:02:46 +0000 Subject: [PATCH 305/353] feat: Prove isomorphism implies equality of normal closure subgroups (#9185) feat: Prove isomorphism implies equality of normal closure subgroups Co-authored-by: Riccardo Brasca riccardo.brasca@gmail.com Co-authored-by: Newell Jensen Co-authored-by: Eric Wieser --- Mathlib/GroupTheory/Subgroup/Basic.lean | 39 ++++++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/Mathlib/GroupTheory/Subgroup/Basic.lean b/Mathlib/GroupTheory/Subgroup/Basic.lean index b90f04a0e61dd..9c7b655d1f690 100644 --- a/Mathlib/GroupTheory/Subgroup/Basic.lean +++ b/Mathlib/GroupTheory/Subgroup/Basic.lean @@ -1502,18 +1502,28 @@ theorem mem_map_iff_mem {f : G →* N} (hf : Function.Injective f) {K : Subgroup #align add_subgroup.mem_map_iff_mem AddSubgroup.mem_map_iff_mem @[to_additive] -theorem map_equiv_eq_comap_symm (f : G ≃* N) (K : Subgroup G) : +theorem map_equiv_eq_comap_symm' (f : G ≃* N) (K : Subgroup G) : K.map f.toMonoidHom = K.comap f.symm.toMonoidHom := SetLike.coe_injective (f.toEquiv.image_eq_preimage K) -#align subgroup.map_equiv_eq_comap_symm Subgroup.map_equiv_eq_comap_symm -#align add_subgroup.map_equiv_eq_comap_symm AddSubgroup.map_equiv_eq_comap_symm +#align subgroup.map_equiv_eq_comap_symm Subgroup.map_equiv_eq_comap_symm' +#align add_subgroup.map_equiv_eq_comap_symm AddSubgroup.map_equiv_eq_comap_symm' + +@[to_additive] +theorem map_equiv_eq_comap_symm (f : G ≃* N) (K : Subgroup G) : + K.map f = K.comap (G := N) f.symm := + map_equiv_eq_comap_symm' _ _ @[to_additive] theorem comap_equiv_eq_map_symm (f : N ≃* G) (K : Subgroup G) : + K.comap (G := N) f = K.map f.symm := + (map_equiv_eq_comap_symm f.symm K).symm + +@[to_additive] +theorem comap_equiv_eq_map_symm' (f : N ≃* G) (K : Subgroup G) : K.comap f.toMonoidHom = K.map f.symm.toMonoidHom := (map_equiv_eq_comap_symm f.symm K).symm -#align subgroup.comap_equiv_eq_map_symm Subgroup.comap_equiv_eq_map_symm -#align add_subgroup.comap_equiv_eq_map_symm AddSubgroup.comap_equiv_eq_map_symm +#align subgroup.comap_equiv_eq_map_symm Subgroup.comap_equiv_eq_map_symm' +#align add_subgroup.comap_equiv_eq_map_symm AddSubgroup.comap_equiv_eq_map_symm' @[to_additive] theorem map_symm_eq_iff_map_eq {H : Subgroup N} {e : G ≃* N} : @@ -2054,21 +2064,21 @@ theorem characteristic_iff_le_comap : H.Characteristic ↔ ∀ ϕ : G ≃* G, H @[to_additive] theorem characteristic_iff_map_eq : H.Characteristic ↔ ∀ ϕ : G ≃* G, H.map ϕ.toMonoidHom = H := by - simp_rw [map_equiv_eq_comap_symm] + simp_rw [map_equiv_eq_comap_symm'] exact characteristic_iff_comap_eq.trans ⟨fun h ϕ => h ϕ.symm, fun h ϕ => h ϕ.symm⟩ #align subgroup.characteristic_iff_map_eq Subgroup.characteristic_iff_map_eq #align add_subgroup.characteristic_iff_map_eq AddSubgroup.characteristic_iff_map_eq @[to_additive] theorem characteristic_iff_map_le : H.Characteristic ↔ ∀ ϕ : G ≃* G, H.map ϕ.toMonoidHom ≤ H := by - simp_rw [map_equiv_eq_comap_symm] + simp_rw [map_equiv_eq_comap_symm'] exact characteristic_iff_comap_le.trans ⟨fun h ϕ => h ϕ.symm, fun h ϕ => h ϕ.symm⟩ #align subgroup.characteristic_iff_map_le Subgroup.characteristic_iff_map_le #align add_subgroup.characteristic_iff_map_le AddSubgroup.characteristic_iff_map_le @[to_additive] theorem characteristic_iff_le_map : H.Characteristic ↔ ∀ ϕ : G ≃* G, H ≤ H.map ϕ.toMonoidHom := by - simp_rw [map_equiv_eq_comap_symm] + simp_rw [map_equiv_eq_comap_symm'] exact characteristic_iff_le_comap.trans ⟨fun h ϕ => h ϕ.symm, fun h ϕ => h ϕ.symm⟩ #align subgroup.characteristic_iff_le_map Subgroup.characteristic_iff_le_map #align add_subgroup.characteristic_iff_le_map AddSubgroup.characteristic_iff_le_map @@ -3506,6 +3516,19 @@ instance (priority := 100) Subgroup.normal_subgroupOf {H N : Subgroup G} [N.Norm #align subgroup.normal_subgroup_of Subgroup.normal_subgroupOf #align add_subgroup.normal_add_subgroup_of AddSubgroup.normal_addSubgroupOf +theorem Subgroup.map_normalClosure (s : Set G) (f : G →* N) (hf : Surjective f) : + (normalClosure s).map f = normalClosure (f '' s) := by + have : Normal (map f (normalClosure s)) := Normal.map inferInstance f hf + apply le_antisymm + · simp [map_le_iff_le_comap, normalClosure_le_normal, coe_comap, + ← Set.image_subset_iff, subset_normalClosure] + · exact normalClosure_le_normal (Set.image_subset f subset_normalClosure) + +theorem Subgroup.comap_normalClosure (s : Set N) (f : G ≃* N) : + normalClosure (f ⁻¹' s) = (normalClosure s).comap f := by + have := Set.preimage_equiv_eq_image_symm s f.toEquiv + simp_all [comap_equiv_eq_map_symm, map_normalClosure s f.symm f.symm.surjective] + namespace MonoidHom /-- The `MonoidHom` from the preimage of a subgroup to itself. -/ From 089e95fb3b3ae586e821f77cd172c1bc01f70acd Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Tue, 2 Jan 2024 08:29:00 +0000 Subject: [PATCH 306/353] doc(FormalMultilinearSeries): clarify relationship between `shift`, `sum`, derivative and Taylor series (#9373) Co-authored-by: Junyan Xu --- Mathlib/Analysis/Calculus/ContDiff/Defs.lean | 10 ++++++++-- Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean | 10 ++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean index afb0c159cfd80..915132f0b7193 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean @@ -180,7 +180,10 @@ variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Type uE} [NormedAdd /-- `HasFTaylorSeriesUpToOn n f p s` registers the fact that `p 0 = f` and `p (m+1)` is a derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a predicate analogous to -`HasFDerivWithinAt` but for higher order derivatives. -/ +`HasFDerivWithinAt` but for higher order derivatives. + +Notice that `p` does not sum up to `f` on the diagonal (`FormalMultilinearSeries.sum`), even if +`f` is analytic and `n = ∞`: an additional `1/m!` factor on the `m`th term is necessary for that. -/ structure HasFTaylorSeriesUpToOn (n : ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F) (s : Set E) : Prop where zero_eq : ∀ x ∈ s, (p x 0).uncurry0 = f x @@ -1218,7 +1221,10 @@ theorem ContDiffOn.continuousOn_fderiv_of_isOpen (h : ContDiffOn 𝕜 n f s) (hs /-- `HasFTaylorSeriesUpTo n f p` registers the fact that `p 0 = f` and `p (m+1)` is a derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a predicate analogous to -`HasFDerivAt` but for higher order derivatives. -/ +`HasFDerivAt` but for higher order derivatives. + +Notice that `p` does not sum up to `f` on the diagonal (`FormalMultilinearSeries.sum`), even if +`f` is analytic and `n = ∞`: an addition `1/m!` factor on the `m`th term is necessary for that. -/ structure HasFTaylorSeriesUpTo (n : ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F) : Prop where zero_eq : ∀ x, (p x 0).uncurry0 = f x diff --git a/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean b/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean index fb767647d72df..72c46fb6f5b5c 100644 --- a/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean +++ b/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean @@ -162,14 +162,16 @@ variable [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 variable (p : FormalMultilinearSeries 𝕜 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. -/ +as multilinear maps into `E →L[𝕜] F`. If `p` is the Taylor series (`HasFTaylorSeriesUpTo`) of a +function, then `p.shift` is the Taylor series of the derivative of the function. Note that the +`p.sum` of a Taylor series `p` does not give the original function; for a formal multilinear +series that sums to the derivative of `p.sum`, see `HasFPowerSeriesOnBall.fderiv`. -/ def shift : FormalMultilinearSeries 𝕜 E (E →L[𝕜] F) := fun n => (p n.succ).curryRight #align formal_multilinear_series.shift FormalMultilinearSeries.shift /-- 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. -/ +corresponds to starting from a Taylor series (`HasFTaylorSeriesUpTo`) for the derivative of a +function, and building a Taylor series for the function itself. -/ def unshift (q : FormalMultilinearSeries 𝕜 E (E →L[𝕜] F)) (z : F) : FormalMultilinearSeries 𝕜 E F | 0 => (continuousMultilinearCurryFin0 𝕜 E F).symm z | n + 1 => -- porting note: added type hint here and explicit universes to fix compile From 7d58fa3955c424de04895b4379b4c21d2eb97501 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Wed, 3 Jan 2024 15:13:20 +0000 Subject: [PATCH 307/353] chore: switch cache to Lean FRO R2 bucket (#9409) This will use a new, fresh cache from this commit onward. We are still working on reviving the old cache for old commits. Co-authored-by: Mario Carneiro --- .github/workflows/bors.yml | 6 ++--- .github/workflows/build.yml | 6 ++--- .github/workflows/build.yml.in | 6 ++--- .github/workflows/build_fork.yml | 6 ++--- Cache/IO.lean | 4 +-- Cache/Requests.lean | 46 +++++++++++++++++--------------- test/LibrarySearch/basic.lean | 4 +++ test/RewriteSearch/Basic.lean | 4 +++ 8 files changed, 46 insertions(+), 36 deletions(-) diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index 089ab5a5fdbac..709a1d2062d7c 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -193,7 +193,7 @@ jobs: # try twice in case of network errors lake exe cache put || (sleep 1; lake exe cache put) || true env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check the cache run: | @@ -220,7 +220,7 @@ jobs: lake build Archive lake exe cache put Archive.lean || (sleep 1; lake exe cache put Archive.lean) env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: build counterexamples run: | @@ -228,7 +228,7 @@ jobs: lake build Counterexamples lake exe cache put Counterexamples.lean || (sleep 1; lake exe cache put Counterexamples.lean) env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check declarations in db files run: | diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73bff93a3971c..8a213e9eadfec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -200,7 +200,7 @@ jobs: # try twice in case of network errors lake exe cache put || (sleep 1; lake exe cache put) || true env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check the cache run: | @@ -227,7 +227,7 @@ jobs: lake build Archive lake exe cache put Archive.lean || (sleep 1; lake exe cache put Archive.lean) env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: build counterexamples run: | @@ -235,7 +235,7 @@ jobs: lake build Counterexamples lake exe cache put Counterexamples.lean || (sleep 1; lake exe cache put Counterexamples.lean) env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check declarations in db files run: | diff --git a/.github/workflows/build.yml.in b/.github/workflows/build.yml.in index dc651c15afb33..9962a6ca0349e 100644 --- a/.github/workflows/build.yml.in +++ b/.github/workflows/build.yml.in @@ -179,7 +179,7 @@ jobs: # try twice in case of network errors lake exe cache put || (sleep 1; lake exe cache put) || true env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check the cache run: | @@ -206,7 +206,7 @@ jobs: lake build Archive lake exe cache put Archive.lean || (sleep 1; lake exe cache put Archive.lean) env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: build counterexamples run: | @@ -214,7 +214,7 @@ jobs: lake build Counterexamples lake exe cache put Counterexamples.lean || (sleep 1; lake exe cache put Counterexamples.lean) env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check declarations in db files run: | diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index df3944b78ba34..af59a8d3d6eea 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -197,7 +197,7 @@ jobs: # try twice in case of network errors lake exe cache put || (sleep 1; lake exe cache put) || true env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check the cache run: | @@ -224,7 +224,7 @@ jobs: lake build Archive lake exe cache put Archive.lean || (sleep 1; lake exe cache put Archive.lean) env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: build counterexamples run: | @@ -232,7 +232,7 @@ jobs: lake build Counterexamples lake exe cache put Counterexamples.lean || (sleep 1; lake exe cache put Counterexamples.lean) env: - MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} + MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check declarations in db files run: | diff --git a/Cache/IO.lean b/Cache/IO.lean index d93c88eb09d46..3edbe33241409 100644 --- a/Cache/IO.lean +++ b/Cache/IO.lean @@ -349,8 +349,8 @@ def unpackCache (hashMap : HashMap) (force : Bool) : IO Unit := do /-- Retrieves the azure token from the environment -/ def getToken : IO String := do - let some token ← IO.getEnv "MATHLIB_CACHE_SAS" - | throw $ IO.userError "environment variable MATHLIB_CACHE_SAS must be set to upload caches" + let some token ← IO.getEnv "MATHLIB_CACHE_S3_TOKEN" + | throw $ IO.userError "environment variable MATHLIB_CACHE_S3_TOKEN must be set to upload caches" return token instance : Ord FilePath where diff --git a/Cache/Requests.lean b/Cache/Requests.lean index ec8da2439e229..7ac04b50d8dde 100644 --- a/Cache/Requests.lean +++ b/Cache/Requests.lean @@ -10,9 +10,9 @@ set_option autoImplicit true namespace Cache.Requests -/-- Azure blob URL -/ +/-- FRO cache public URL -/ def URL : String := - "https://lakecache.blob.core.windows.net/mathlib4" + "https://mathlib4.lean-cache.cloud" open System (FilePath) @@ -21,10 +21,8 @@ Given a file name like `"1234.tar.gz"`, makes the URL to that file on the server The `f/` prefix means that it's a common file for caching. -/ -def mkFileURL (fileName : String) (token : Option String) : IO String := - return match token with - | some token => s!"{URL}/f/{fileName}?{token}" - | none => s!"{URL}/f/{fileName}" +def mkFileURL (fileName : String) : String := + s!"{URL}/f/{fileName}" section Get @@ -47,13 +45,13 @@ def mkGetConfigContent (hashMap : IO.HashMap) : IO String := do -- Note we append a '.part' to the filenames here, -- which `downloadFiles` then removes when the download is successful. - pure $ acc ++ s!"url = {← mkFileURL fileName none}\n\ + pure $ acc ++ s!"url = {mkFileURL fileName}\n\ -o {(IO.CACHEDIR / (fileName ++ ".part")).toString.quote}\n" /-- Calls `curl` to download a single file from the server to `CACHEDIR` (`.cache`) -/ def downloadFile (hash : UInt64) : IO Bool := do let fileName := hash.asLTar - let url ← mkFileURL fileName none + let url := mkFileURL fileName let path := IO.CACHEDIR / fileName let partFileName := fileName ++ ".part" let partPath := IO.CACHEDIR / partFileName @@ -161,25 +159,26 @@ end Get section Put +/-- FRO cache S3 URL -/ +def UPLOAD_URL : String := + "https://a09a7664adc082e00f294ac190827820.r2.cloudflarestorage.com/mathlib4" + /-- Formats the config file for `curl`, containing the list of files to be uploaded -/ -def mkPutConfigContent (fileNames : Array String) (token : String) : IO String := do +def mkPutConfigContent (fileNames : Array String) : IO String := do let l ← fileNames.data.mapM fun fileName : String => do - pure s!"-T {(IO.CACHEDIR / fileName).toString}\nurl = {← mkFileURL fileName (some token)}" + pure s!"-T {(IO.CACHEDIR / fileName).toString}\nurl = {UPLOAD_URL}/f/{fileName}" return "\n".intercalate l /-- Calls `curl` to send a set of cached files to the server -/ def putFiles (fileNames : Array String) (overwrite : Bool) (token : String) : IO Unit := do + -- TODO: reimplement using HEAD requests? + let _ := overwrite let size := fileNames.size if size > 0 then - IO.FS.writeFile IO.CURLCFG (← mkPutConfigContent fileNames token) + IO.FS.writeFile IO.CURLCFG (← mkPutConfigContent fileNames) IO.println s!"Attempting to upload {size} file(s)" - if overwrite then - discard $ IO.runCurl #["-X", "PUT", "-H", "x-ms-blob-type: BlockBlob", "--parallel", - "-K", IO.CURLCFG.toString] - else - discard $ IO.runCurl #["-X", "PUT", "-H", "x-ms-blob-type: BlockBlob", - "-H", "If-None-Match: *", "--parallel", "-K", IO.CURLCFG.toString] - IO.FS.removeFile IO.CURLCFG + discard $ IO.runCurl #["-X", "PUT", "--aws-sigv4", "aws:amz:auto:s3", "--user", token, + "--parallel", "-K", IO.CURLCFG.toString] else IO.println "No files to upload" end Put @@ -197,18 +196,20 @@ Sends a commit file to the server, containing the hashes of the respective commi The file name is the current Git hash and the `c/` prefix means that it's a commit file. -/ def commit (hashMap : IO.HashMap) (overwrite : Bool) (token : String) : IO Unit := do + -- TODO: reimplement using HEAD requests? + let _ := overwrite let hash ← getGitCommitHash let path := IO.CACHEDIR / hash IO.mkDir IO.CACHEDIR IO.FS.writeFile path $ ("\n".intercalate $ hashMap.hashes.toList.map toString) ++ "\n" - let params := if overwrite - then #["-X", "PUT", "-H", "x-ms-blob-type: BlockBlob"] - else #["-X", "PUT", "-H", "x-ms-blob-type: BlockBlob", "-H", "If-None-Match: *"] - discard $ IO.runCurl $ params ++ #["-T", path.toString, s!"{URL}/c/{hash}?{token}"] + discard $ IO.runCurl $ #["-T", path.toString, "--aws-sigv4", "aws:amz:auto:s3", + "--user", token, s!"{UPLOAD_URL}/c/{hash}"] IO.FS.removeFile path end Commit +-- TODO: unused, not adapted to the FRO cache yet +/- section Collect inductive QueryType @@ -248,5 +249,6 @@ def getFilesInfo (q : QueryType) : IO $ List (String × String) := do | _ => formatError end Collect +-/ end Cache.Requests diff --git a/test/LibrarySearch/basic.lean b/test/LibrarySearch/basic.lean index 5a101cdd77164..075b98f17fccd 100644 --- a/test/LibrarySearch/basic.lean +++ b/test/LibrarySearch/basic.lean @@ -7,6 +7,8 @@ import Mathlib.Data.Real.Basic set_option autoImplicit true +/- FIXME: tests are flaky after #9409 + -- Enable this option for tracing: -- set_option trace.Tactic.librarySearch true -- And this option to trace all candidate lemmas before application. @@ -236,3 +238,5 @@ example (P Q : Prop) (h : P → Q) (h' : ¬Q) : ¬P := by -- first -- | exact? says exact le_antisymm hxy hyx -- | exact? says exact ge_antisymm hyx hxy + +-/ diff --git a/test/RewriteSearch/Basic.lean b/test/RewriteSearch/Basic.lean index d06ecc1d270af..3135fdfa83ca3 100644 --- a/test/RewriteSearch/Basic.lean +++ b/test/RewriteSearch/Basic.lean @@ -8,6 +8,8 @@ set_option autoImplicit true -- You can get timing information (very useful if tweaking the search algorithm!) using -- set_option profiler true +/- FIXME: tests are flaky after #9409 + /-- info: Try this: rw [@List.length_append, Nat.add_comm] -/ #guard_msgs in example (xs ys : List α) : (xs ++ ys).length = ys.length + xs.length := by @@ -53,3 +55,5 @@ example (n : Nat) : makeSingleton n = [0] := by · simp only [makeSingleton] · -- At one point, this failed with: unknown free variable '_uniq.62770' rw_search + +-/ From e23b08714daf24b36bff71d3387f034cd19c1a38 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Wed, 3 Jan 2024 17:22:35 +0000 Subject: [PATCH 308/353] doc(AlgebraicIndependent): remove outdated TODO and add new (#9396) The TODO item was already completed as [IsTranscendenceBasis.isAlgebraic](https://leanprover-community.github.io/mathlib4_docs/Mathlib/RingTheory/AlgebraicIndependent.html#IsTranscendenceBasis.isAlgebraic). However, transcendence degree is nowhere to be found even though it appears in the tags. Co-authored-by: Junyan Xu Co-authored-by: Chris Hughes --- Mathlib/RingTheory/AlgebraicIndependent.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mathlib/RingTheory/AlgebraicIndependent.lean b/Mathlib/RingTheory/AlgebraicIndependent.lean index ebec50746402c..0ae5c8068b4ed 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent.lean @@ -31,7 +31,8 @@ This file defines algebraic independence of a family of element of an `R` algebr * [Stacks: Transcendence](https://stacks.math.columbia.edu/tag/030D) ## TODO -Prove that a ring is an algebraic extension of the subalgebra generated by a transcendence basis. +Define the transcendence degree and show it is independent of the choice of a +transcendence basis. ## Tags transcendence basis, transcendence degree, transcendence From 26c28adfd0e2ebe738b1e9e210e7e6f3ad53b9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 3 Jan 2024 20:40:42 +0000 Subject: [PATCH 309/353] chore: Tag `abs_le_abs_of_nonneg` as `gcongr` (#9391) From LeanAPAP --- Mathlib/Algebra/Order/Group/Abs.lean | 1 + Mathlib/Analysis/Asymptotics/SuperpolynomialDecay.lean | 2 +- Mathlib/Analysis/Calculus/Taylor.lean | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Mathlib/Algebra/Order/Group/Abs.lean b/Mathlib/Algebra/Order/Group/Abs.lean index b9979e3cf35ec..c8ba880a1665f 100644 --- a/Mathlib/Algebra/Order/Group/Abs.lean +++ b/Mathlib/Algebra/Order/Group/Abs.lean @@ -120,6 +120,7 @@ theorem abs_of_neg (h : a < 0) : |a| = -a := abs_of_nonpos h.le #align abs_of_neg abs_of_neg +@[gcongr] theorem abs_le_abs_of_nonneg (ha : 0 ≤ a) (hab : a ≤ b) : |a| ≤ |b| := by rwa [abs_of_nonneg ha, abs_of_nonneg (ha.trans hab)] #align abs_le_abs_of_nonneg abs_le_abs_of_nonneg diff --git a/Mathlib/Analysis/Asymptotics/SuperpolynomialDecay.lean b/Mathlib/Analysis/Asymptotics/SuperpolynomialDecay.lean index bbeb1efa25d28..94afb6b144e90 100644 --- a/Mathlib/Analysis/Asymptotics/SuperpolynomialDecay.lean +++ b/Mathlib/Analysis/Asymptotics/SuperpolynomialDecay.lean @@ -182,7 +182,7 @@ theorem SuperpolynomialDecay.trans_eventually_abs_le (hf : SuperpolynomialDecay (eventually_of_forall fun x => abs_nonneg _) (hfg.mono fun x hx => _) calc |k x ^ z * g x| = |k x ^ z| * |g x| := abs_mul (k x ^ z) (g x) - _ ≤ |k x ^ z| * |f x| := by gcongr; exact hx + _ ≤ |k x ^ z| * |f x| := by gcongr _ * ?_; exact hx _ = |k x ^ z * f x| := (abs_mul (k x ^ z) (f x)).symm #align asymptotics.superpolynomial_decay.trans_eventually_abs_le Asymptotics.SuperpolynomialDecay.trans_eventually_abs_le diff --git a/Mathlib/Analysis/Calculus/Taylor.lean b/Mathlib/Analysis/Calculus/Taylor.lean index 770a826763612..78fe076ec705e 100644 --- a/Mathlib/Analysis/Calculus/Taylor.lean +++ b/Mathlib/Analysis/Calculus/Taylor.lean @@ -335,7 +335,7 @@ theorem taylor_mean_remainder_bound {f : ℝ → E} {a b C x : ℝ} {n : ℕ} (h gcongr · rw [abs_mul, abs_pow, abs_inv, Nat.abs_cast] gcongr - rw [abs_of_nonneg, abs_of_nonneg] <;> linarith + exact sub_nonneg.2 hyx.le -- Estimate the iterated derivative by `C` · exact hC y ⟨hay, hyx.le.trans hx.2⟩ -- Apply the mean value theorem for vector valued functions: From d8fe3beb64fdd736c3d562533942697c1e3235b0 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 4 Jan 2024 12:45:33 +1100 Subject: [PATCH 310/353] update dependencies --- lake-manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index 0348b0bdb165b..cb26596280b37 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "dddfaf4346e3355a5ca9119fabda05b47eefe8f5", + "rev": "7d9933234960ee2787933cf40c7036e931ead249", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "nightly-testing", @@ -13,7 +13,7 @@ {"url": "https://github.com/leanprover-community/quote4", "type": "git", "subDir": null, - "rev": "ccba5d35d07a448fab14c0e391c8105df6e2564c", + "rev": "1c88406514a636d241903e2e288d21dc6d861e01", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -31,7 +31,7 @@ {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, - "rev": "25eb33d3e327dea8f390d2e382dc4808cd6b74f7", + "rev": "bf61e90de075abfa27f638922e7aafafdce77c44", "name": "proofwidgets", "manifestFile": "lake-manifest.json", "inputRev": "v0.0.24-pre2", From 570a85ce6f479ac461960288102a793f941bd8b8 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Thu, 4 Jan 2024 01:46:08 +0000 Subject: [PATCH 311/353] chore: rename Finset.card_doubleton to Finset.card_pair (#9379) --- Mathlib/Combinatorics/SimpleGraph/Clique.lean | 4 ++-- Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean | 4 ++-- Mathlib/Data/Finset/Card.lean | 8 +++++--- .../NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean | 2 +- Mathlib/NumberTheory/NumberField/Embeddings.lean | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Clique.lean b/Mathlib/Combinatorics/SimpleGraph/Clique.lean index 68f5da1095ef9..d8f5c9de53809 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Clique.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Clique.lean @@ -339,7 +339,7 @@ theorem cliqueFree_two : G.CliqueFree 2 ↔ G = ⊥ := by classical constructor · simp_rw [← edgeSet_eq_empty, Set.eq_empty_iff_forall_not_mem, Sym2.forall, mem_edgeSet] - exact fun h a b hab => h _ ⟨by simpa [hab.ne], card_doubleton hab.ne⟩ + exact fun h a b hab => h _ ⟨by simpa [hab.ne], card_pair hab.ne⟩ · rintro rfl exact cliqueFree_bot le_rfl #align simple_graph.clique_free_two SimpleGraph.cliqueFree_two @@ -396,7 +396,7 @@ theorem cliqueFreeOn_of_card_lt {s : Finset α} (h : s.card < n) : G.CliqueFreeO @[simp] theorem cliqueFreeOn_two : G.CliqueFreeOn s 2 ↔ s.Pairwise (G.Adjᶜ) := by classical - refine' ⟨fun h a ha b hb _ hab => h _ ⟨by simpa [hab.ne], card_doubleton hab.ne⟩, _⟩ + refine' ⟨fun h a ha b hb _ hab => h _ ⟨by simpa [hab.ne], card_pair hab.ne⟩, _⟩ · push_cast exact Set.insert_subset_iff.2 ⟨ha, Set.singleton_subset_iff.2 hb⟩ simp only [CliqueFreeOn, isNClique_iff, card_eq_two, coe_subset, not_and, not_exists] diff --git a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean index 2034a17d1cd43..1b7b38103a880 100644 --- a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean @@ -136,7 +136,7 @@ theorem sum_incMatrix_apply_of_mem_edgeSet : refine' e.ind _ intro a b h rw [mem_edgeSet] at h - rw [← Nat.cast_two, ← card_doubleton h.ne] + rw [← Nat.cast_two, ← card_pair h.ne] simp only [incMatrix_apply', sum_boole, mk'_mem_incidenceSet_iff, h, true_and_iff] congr 2 ext e @@ -157,7 +157,7 @@ theorem incMatrix_transpose_mul_diag [DecidableRel G.Adj] : · revert h refine' e.ind _ intro v w h - rw [← Nat.cast_two, ← card_doubleton (G.ne_of_adj h)] + rw [← Nat.cast_two, ← card_pair (G.ne_of_adj h)] simp only [mk'_mem_incidenceSet_iff, G.mem_edgeSet.mp h, true_and, mem_univ, forall_true_left, forall_eq_or_imp, forall_eq, and_self, mem_singleton, ne_eq] congr 2 diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean index 44a1850032bb5..aaea413bfd511 100644 --- a/Mathlib/Data/Finset/Card.lean +++ b/Mathlib/Data/Finset/Card.lean @@ -149,9 +149,11 @@ theorem card_insert_eq_ite : card (insert a s) = if a ∈ s then s.card else s.c #align finset.card_insert_eq_ite Finset.card_insert_eq_ite @[simp] -theorem card_doubleton (h : a ≠ b) : ({a, b} : Finset α).card = 2 := by +theorem card_pair (h : a ≠ b) : ({a, b} : Finset α).card = 2 := by rw [card_insert_of_not_mem (not_mem_singleton.2 h), card_singleton] -#align finset.card_doubleton Finset.card_doubleton +#align finset.card_doubleton Finset.card_pair + +@[deprecated] alias card_doubleton := Finset.card_pair /-- $\#(s \setminus \{a\}) = \#s - 1$ if $a \in s$. -/ @[simp] @@ -694,7 +696,7 @@ theorem card_eq_two : s.card = 2 ↔ ∃ x y, x ≠ y ∧ s = {x, y} := by rintro ⟨a, _, hab, rfl, b, rfl⟩ exact ⟨a, b, not_mem_singleton.1 hab, rfl⟩ · rintro ⟨x, y, h, rfl⟩ - exact card_doubleton h + exact card_pair h #align finset.card_eq_two Finset.card_eq_two theorem card_eq_three : s.card = 3 ↔ ∃ x y z, x ≠ y ∧ x ≠ z ∧ y ≠ z ∧ s = {x, y, z} := by diff --git a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean index aa50a12f53dbb..1bd35a305704a 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean @@ -264,7 +264,7 @@ theorem quadraticChar_card_sqrts (hF : ringChar F ≠ 2) (a : F) : simp only [neg_sq] norm_cast rw [h₁, List.toFinset_cons, List.toFinset_cons, List.toFinset_nil] - exact Finset.card_doubleton (Ne.symm (mt (Ring.eq_self_iff_eq_zero_of_char_ne_two hF).mp h₀)) + exact Finset.card_pair (Ne.symm (mt (Ring.eq_self_iff_eq_zero_of_char_ne_two hF).mp h₀)) · rw [quadraticChar_neg_one_iff_not_isSquare.mpr h] simp only [Int.coe_nat_eq_zero, Finset.card_eq_zero, Set.toFinset_card, Fintype.card_ofFinset, Set.mem_setOf_eq, add_left_neg] diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index ea4fd3e1f0b21..fa4ddb33c813f 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -461,7 +461,7 @@ theorem card_filter_mk_eq [NumberField K] (w : InfinitePlace K) : split_ifs with hw · rw [ComplexEmbedding.isReal_iff.mp (isReal_iff.mp hw), Finset.union_idempotent, Finset.card_singleton] - · refine Finset.card_doubleton ?_ + · refine Finset.card_pair ?_ rwa [Ne.def, eq_comm, ← ComplexEmbedding.isReal_iff, ← isReal_iff] open scoped BigOperators From 6117aba61f2e9e01bb5a94867e0602a118ba3d56 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 4 Jan 2024 03:16:59 +0000 Subject: [PATCH 312/353] chore: bump dependencies (#9424) Co-authored-by: Scott Morrison --- Mathlib/Data/BitVec/Lemmas.lean | 1 - Mathlib/Data/Nat/Basic.lean | 3 --- lake-manifest.json | 4 ++-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Mathlib/Data/BitVec/Lemmas.lean b/Mathlib/Data/BitVec/Lemmas.lean index 6000cfe2541c2..05b9069399627 100644 --- a/Mathlib/Data/BitVec/Lemmas.lean +++ b/Mathlib/Data/BitVec/Lemmas.lean @@ -140,7 +140,6 @@ variable (x y : Fin (2^w)) lemma ofFin_zero : ofFin (0 : Fin (2^w)) = 0 := rfl lemma ofFin_one : ofFin (1 : Fin (2^w)) = 1 := by simp only [OfNat.ofNat, BitVec.ofNat, and_pow_two_is_mod] - rfl lemma ofFin_nsmul (n : ℕ) (x : Fin (2^w)) : ofFin (n • x) = n • ofFin x := rfl lemma ofFin_zsmul (z : ℤ) (x : Fin (2^w)) : ofFin (z • x) = z • ofFin x := rfl diff --git a/Mathlib/Data/Nat/Basic.lean b/Mathlib/Data/Nat/Basic.lean index 6770f954b07a0..d1e8dea049591 100644 --- a/Mathlib/Data/Nat/Basic.lean +++ b/Mathlib/Data/Nat/Basic.lean @@ -774,9 +774,6 @@ protected theorem mul_dvd_mul_iff_right {a b c : ℕ} (hc : 0 < c) : a * c ∣ b exists_congr fun d => by rw [Nat.mul_right_comm, mul_left_inj' hc.ne'] #align nat.mul_dvd_mul_iff_right Nat.mul_dvd_mul_iff_right -@[simp] -- TODO: move to Std4 -theorem dvd_one {a : ℕ} : a ∣ 1 ↔ a = 1 := - ⟨eq_one_of_dvd_one, fun h ↦ h.symm ▸ Nat.dvd_refl _⟩ #align nat.dvd_one Nat.dvd_one @[simp] diff --git a/lake-manifest.json b/lake-manifest.json index e3edebe28c403..5f36b7078600b 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "ee49cf8fada1bf5a15592c399a925c401848227f", + "rev": "d8610e1bcb91c013c3d868821c0ef28bf693be07", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -13,7 +13,7 @@ {"url": "https://github.com/leanprover-community/quote4", "type": "git", "subDir": null, - "rev": "ccba5d35d07a448fab14c0e391c8105df6e2564c", + "rev": "1c88406514a636d241903e2e288d21dc6d861e01", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", From 7c0310106360d5bede3c6ce86ef6d369e5efb6f0 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Thu, 4 Jan 2024 04:39:26 +0000 Subject: [PATCH 313/353] fix: partial revert of #9409 (re-enable Azure cache) (#9419) As [reported on Zulip](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/The.20cache.20doesn't.20work/near/411058849), we're still working out some issues in the new cache provider. Since Azure is back online, let's move back to them while we work out the issues with cloudflare. The code is now set up to be able to toggle between both. Co-authored-by: Mario Carneiro --- .github/workflows/bors.yml | 3 ++ .github/workflows/build.yml | 3 ++ .github/workflows/build.yml.in | 3 ++ .github/workflows/build_fork.yml | 3 ++ Cache/IO.lean | 19 +++++---- Cache/Main.lean | 8 ++-- Cache/Requests.lean | 68 +++++++++++++++++++++++--------- test/LibrarySearch/basic.lean | 4 -- test/RewriteSearch/Basic.lean | 4 -- 9 files changed, 75 insertions(+), 40 deletions(-) diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index 709a1d2062d7c..de909506295b8 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -193,6 +193,7 @@ jobs: # try twice in case of network errors lake exe cache put || (sleep 1; lake exe cache put) || true env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check the cache @@ -220,6 +221,7 @@ jobs: lake build Archive lake exe cache put Archive.lean || (sleep 1; lake exe cache put Archive.lean) env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: build counterexamples @@ -228,6 +230,7 @@ jobs: lake build Counterexamples lake exe cache put Counterexamples.lean || (sleep 1; lake exe cache put Counterexamples.lean) env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check declarations in db files diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8a213e9eadfec..facc3d356f508 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -200,6 +200,7 @@ jobs: # try twice in case of network errors lake exe cache put || (sleep 1; lake exe cache put) || true env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check the cache @@ -227,6 +228,7 @@ jobs: lake build Archive lake exe cache put Archive.lean || (sleep 1; lake exe cache put Archive.lean) env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: build counterexamples @@ -235,6 +237,7 @@ jobs: lake build Counterexamples lake exe cache put Counterexamples.lean || (sleep 1; lake exe cache put Counterexamples.lean) env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check declarations in db files diff --git a/.github/workflows/build.yml.in b/.github/workflows/build.yml.in index 9962a6ca0349e..cffd2c5b5cd46 100644 --- a/.github/workflows/build.yml.in +++ b/.github/workflows/build.yml.in @@ -179,6 +179,7 @@ jobs: # try twice in case of network errors lake exe cache put || (sleep 1; lake exe cache put) || true env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check the cache @@ -206,6 +207,7 @@ jobs: lake build Archive lake exe cache put Archive.lean || (sleep 1; lake exe cache put Archive.lean) env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: build counterexamples @@ -214,6 +216,7 @@ jobs: lake build Counterexamples lake exe cache put Counterexamples.lean || (sleep 1; lake exe cache put Counterexamples.lean) env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check declarations in db files diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index af59a8d3d6eea..95b38877f245c 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -197,6 +197,7 @@ jobs: # try twice in case of network errors lake exe cache put || (sleep 1; lake exe cache put) || true env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check the cache @@ -224,6 +225,7 @@ jobs: lake build Archive lake exe cache put Archive.lean || (sleep 1; lake exe cache put Archive.lean) env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: build counterexamples @@ -232,6 +234,7 @@ jobs: lake build Counterexamples lake exe cache put Counterexamples.lean || (sleep 1; lake exe cache put Counterexamples.lean) env: + MATHLIB_CACHE_SAS: ${{ secrets.MATHLIB_CACHE_SAS }} MATHLIB_CACHE_S3_TOKEN: ${{ secrets.MATHLIB_CACHE_S3_TOKEN }} - name: check declarations in db files diff --git a/Cache/IO.lean b/Cache/IO.lean index 3edbe33241409..166aff8f5ea31 100644 --- a/Cache/IO.lean +++ b/Cache/IO.lean @@ -157,7 +157,8 @@ where /-- Runs a terminal command and retrieves its output -/ def runCmd (cmd : String) (args : Array String) (throwFailure := true) : IO String := do let out ← IO.Process.output { cmd := cmd, args := args } - if out.exitCode != 0 && throwFailure then throw $ IO.userError out.stderr + if (out.exitCode != 0 || !out.stderr.isEmpty) && throwFailure then + throw $ IO.userError out.stderr else return out.stdout def runCurl (args : Array String) (throwFailure := true) : IO String := do @@ -286,7 +287,7 @@ def allExist (paths : List (FilePath × Bool)) : IO Bool := do pure true /-- Compresses build files into the local cache and returns an array with the compressed files -/ -def packCache (hashMap : HashMap) (overwrite : Bool) (comment : Option String := none) : +def packCache (hashMap : HashMap) (overwrite verbose : Bool) (comment : Option String := none) : IO $ Array String := do mkDir CACHEDIR IO.println "Compressing cache" @@ -305,10 +306,14 @@ def packCache (hashMap : HashMap) (overwrite : Bool) (comment : Option String := | unreachable! runCmd (← getLeanTar) $ #[zipPath.toString, trace] ++ (if let some c := comment then #["-c", s!"git=mathlib4@{c}"] else #[]) ++ args - acc := acc.push zip + acc := acc.push (path, zip) for task in tasks do _ ← IO.ofExcept task.get - return acc + acc := acc.qsort (·.1.1 < ·.1.1) + if verbose then + for (path, zip) in acc do + println! "packing {path} as {zip}" + return acc.map (·.2) /-- Gets the set of all cached files -/ def getLocalCacheSet : IO $ Lean.RBTree String compare := do @@ -347,12 +352,6 @@ def unpackCache (hashMap : HashMap) (force : Bool) : IO Unit := do IO.println s!"unpacked in {(← IO.monoMsNow) - now} ms" else IO.println "No cache files to decompress" -/-- Retrieves the azure token from the environment -/ -def getToken : IO String := do - let some token ← IO.getEnv "MATHLIB_CACHE_S3_TOKEN" - | throw $ IO.userError "environment variable MATHLIB_CACHE_S3_TOKEN must be set to upload caches" - return token - instance : Ord FilePath where compare x y := compare x.toString y.toString diff --git a/Cache/Main.lean b/Cache/Main.lean index 92d7fa943bbe6..766c78db56806 100644 --- a/Cache/Main.lean +++ b/Cache/Main.lean @@ -86,16 +86,16 @@ def main (args : List String) : IO Unit := do getFiles (← hashMemo.filterByFilePaths (toPaths args)) true true goodCurl true | "get-" :: args => getFiles (← hashMemo.filterByFilePaths (toPaths args)) false false goodCurl false - | ["pack"] => discard $ packCache hashMap false (← getGitCommitHash) - | ["pack!"] => discard $ packCache hashMap true (← getGitCommitHash) + | ["pack"] => discard $ packCache hashMap false false (← getGitCommitHash) + | ["pack!"] => discard $ packCache hashMap true false (← getGitCommitHash) | ["unpack"] => unpackCache hashMap false | ["unpack!"] => unpackCache hashMap true | ["clean"] => cleanCache $ hashMap.fold (fun acc _ hash => acc.insert $ CACHEDIR / hash.asLTar) .empty | ["clean!"] => cleanCache -- We allow arguments for `put` and `put!` so they can be added to the `roots`. - | "put" :: _ => putFiles (← packCache hashMap false (← getGitCommitHash)) false (← getToken) - | "put!" :: _ => putFiles (← packCache hashMap false (← getGitCommitHash)) true (← getToken) + | "put" :: _ => putFiles (← packCache hashMap false true (← getGitCommitHash)) false (← getToken) + | "put!" :: _ => putFiles (← packCache hashMap false true (← getGitCommitHash)) true (← getToken) | ["commit"] => if !(← isGitStatusClean) then IO.println "Please commit your changes first" return else commit hashMap false (← getToken) diff --git a/Cache/Requests.lean b/Cache/Requests.lean index 7ac04b50d8dde..ffdbec3b9a5e2 100644 --- a/Cache/Requests.lean +++ b/Cache/Requests.lean @@ -10,9 +10,22 @@ set_option autoImplicit true namespace Cache.Requests -/-- FRO cache public URL -/ +-- FRO cache is flaky so disable until we work out the kinks: https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/The.20cache.20doesn't.20work/near/411058849 +def useFROCache : Bool := false + +/-- Public URL for mathlib cache -/ def URL : String := - "https://mathlib4.lean-cache.cloud" + if useFROCache then + "https://mathlib4.lean-cache.cloud" + else + "https://lakecache.blob.core.windows.net/mathlib4" + +/-- Retrieves the azure token from the environment -/ +def getToken : IO String := do + let envVar := if useFROCache then "MATHLIB_CACHE_S3_TOKEN" else "MATHLIB_CACHE_SAS" + let some token ← IO.getEnv envVar + | throw $ IO.userError s!"environment variable {envVar} must be set to upload caches" + return token open System (FilePath) @@ -21,7 +34,7 @@ Given a file name like `"1234.tar.gz"`, makes the URL to that file on the server The `f/` prefix means that it's a common file for caching. -/ -def mkFileURL (fileName : String) : String := +def mkFileURL (URL fileName : String) : String := s!"{URL}/f/{fileName}" section Get @@ -45,13 +58,13 @@ def mkGetConfigContent (hashMap : IO.HashMap) : IO String := do -- Note we append a '.part' to the filenames here, -- which `downloadFiles` then removes when the download is successful. - pure $ acc ++ s!"url = {mkFileURL fileName}\n\ + pure $ acc ++ s!"url = {mkFileURL URL fileName}\n\ -o {(IO.CACHEDIR / (fileName ++ ".part")).toString.quote}\n" /-- Calls `curl` to download a single file from the server to `CACHEDIR` (`.cache`) -/ def downloadFile (hash : UInt64) : IO Bool := do let fileName := hash.asLTar - let url := mkFileURL fileName + let url := mkFileURL URL fileName let path := IO.CACHEDIR / fileName let partFileName := fileName ++ ".part" let partPath := IO.CACHEDIR / partFileName @@ -161,12 +174,16 @@ section Put /-- FRO cache S3 URL -/ def UPLOAD_URL : String := - "https://a09a7664adc082e00f294ac190827820.r2.cloudflarestorage.com/mathlib4" + if useFROCache then + "https://a09a7664adc082e00f294ac190827820.r2.cloudflarestorage.com/mathlib4" + else + URL /-- Formats the config file for `curl`, containing the list of files to be uploaded -/ -def mkPutConfigContent (fileNames : Array String) : IO String := do +def mkPutConfigContent (fileNames : Array String) (token : String) : IO String := do + let token := if useFROCache then "" else s!"?{token}" -- the FRO cache doesn't pass the token here let l ← fileNames.data.mapM fun fileName : String => do - pure s!"-T {(IO.CACHEDIR / fileName).toString}\nurl = {UPLOAD_URL}/f/{fileName}" + pure s!"-T {(IO.CACHEDIR / fileName).toString}\nurl = {mkFileURL UPLOAD_URL fileName}{token}" return "\n".intercalate l /-- Calls `curl` to send a set of cached files to the server -/ @@ -175,10 +192,20 @@ def putFiles (fileNames : Array String) (overwrite : Bool) (token : String) : IO let _ := overwrite let size := fileNames.size if size > 0 then - IO.FS.writeFile IO.CURLCFG (← mkPutConfigContent fileNames) + IO.FS.writeFile IO.CURLCFG (← mkPutConfigContent fileNames token) IO.println s!"Attempting to upload {size} file(s)" - discard $ IO.runCurl #["-X", "PUT", "--aws-sigv4", "aws:amz:auto:s3", "--user", token, - "--parallel", "-K", IO.CURLCFG.toString] + if useFROCache then + -- TODO: reimplement using HEAD requests? + let _ := overwrite + discard $ IO.runCurl #["-s", "-X", "PUT", "--aws-sigv4", "aws:amz:auto:s3", "--user", token, + "--parallel", "-K", IO.CURLCFG.toString] + else if overwrite then + discard $ IO.runCurl #["-s", "-X", "PUT", "-H", "x-ms-blob-type: BlockBlob", "--parallel", + "-K", IO.CURLCFG.toString] + else + discard $ IO.runCurl #["-s", "-X", "PUT", "-H", "x-ms-blob-type: BlockBlob", + "-H", "If-None-Match: *", "--parallel", "-K", IO.CURLCFG.toString] + IO.FS.removeFile IO.CURLCFG else IO.println "No files to upload" end Put @@ -196,20 +223,24 @@ Sends a commit file to the server, containing the hashes of the respective commi The file name is the current Git hash and the `c/` prefix means that it's a commit file. -/ def commit (hashMap : IO.HashMap) (overwrite : Bool) (token : String) : IO Unit := do - -- TODO: reimplement using HEAD requests? - let _ := overwrite let hash ← getGitCommitHash let path := IO.CACHEDIR / hash IO.mkDir IO.CACHEDIR IO.FS.writeFile path $ ("\n".intercalate $ hashMap.hashes.toList.map toString) ++ "\n" - discard $ IO.runCurl $ #["-T", path.toString, "--aws-sigv4", "aws:amz:auto:s3", - "--user", token, s!"{UPLOAD_URL}/c/{hash}"] + if useFROCache then + -- TODO: reimplement using HEAD requests? + let _ := overwrite + discard $ IO.runCurl $ #["-T", path.toString, "--aws-sigv4", "aws:amz:auto:s3", + "--user", token, s!"{UPLOAD_URL}/c/{hash}"] + else + let params := if overwrite + then #["-X", "PUT", "-H", "x-ms-blob-type: BlockBlob"] + else #["-X", "PUT", "-H", "x-ms-blob-type: BlockBlob", "-H", "If-None-Match: *"] + discard $ IO.runCurl $ params ++ #["-T", path.toString, s!"{URL}/c/{hash}?{token}"] IO.FS.removeFile path end Commit --- TODO: unused, not adapted to the FRO cache yet -/- section Collect inductive QueryType @@ -234,6 +265,8 @@ Retrieves metadata about hosted files: their names and the timestamps of last mo Example: `["f/39476538726384726.tar.gz", "Sat, 24 Dec 2022 17:33:01 GMT"]` -/ def getFilesInfo (q : QueryType) : IO $ List (String × String) := do + if useFROCache then + throw <| .userError "FIXME: getFilesInfo is not adapted to FRO cache yet" IO.println s!"Downloading info list of {q.desc}" let ret ← IO.runCurl #["-X", "GET", s!"{URL}?comp=list&restype=container{q.prefix}"] match ret.splitOn "" with @@ -249,6 +282,5 @@ def getFilesInfo (q : QueryType) : IO $ List (String × String) := do | _ => formatError end Collect --/ end Cache.Requests diff --git a/test/LibrarySearch/basic.lean b/test/LibrarySearch/basic.lean index 075b98f17fccd..5a101cdd77164 100644 --- a/test/LibrarySearch/basic.lean +++ b/test/LibrarySearch/basic.lean @@ -7,8 +7,6 @@ import Mathlib.Data.Real.Basic set_option autoImplicit true -/- FIXME: tests are flaky after #9409 - -- Enable this option for tracing: -- set_option trace.Tactic.librarySearch true -- And this option to trace all candidate lemmas before application. @@ -238,5 +236,3 @@ example (P Q : Prop) (h : P → Q) (h' : ¬Q) : ¬P := by -- first -- | exact? says exact le_antisymm hxy hyx -- | exact? says exact ge_antisymm hyx hxy - --/ diff --git a/test/RewriteSearch/Basic.lean b/test/RewriteSearch/Basic.lean index 3135fdfa83ca3..d06ecc1d270af 100644 --- a/test/RewriteSearch/Basic.lean +++ b/test/RewriteSearch/Basic.lean @@ -8,8 +8,6 @@ set_option autoImplicit true -- You can get timing information (very useful if tweaking the search algorithm!) using -- set_option profiler true -/- FIXME: tests are flaky after #9409 - /-- info: Try this: rw [@List.length_append, Nat.add_comm] -/ #guard_msgs in example (xs ys : List α) : (xs ++ ys).length = ys.length + xs.length := by @@ -55,5 +53,3 @@ example (n : Nat) : makeSingleton n = [0] := by · simp only [makeSingleton] · -- At one point, this failed with: unknown free variable '_uniq.62770' rw_search - --/ From f61a485edf966de0b09bd70c1edc7f254cd1b0ae Mon Sep 17 00:00:00 2001 From: Jeremy Tan Jie Rui Date: Thu, 4 Jan 2024 07:13:13 +0000 Subject: [PATCH 314/353] feat: move `replaceVertex` to its own file (#9400) --- Mathlib.lean | 1 + Mathlib/Combinatorics/SimpleGraph/Basic.lean | 37 ------------ Mathlib/Combinatorics/SimpleGraph/Clique.lean | 2 +- .../Combinatorics/SimpleGraph/Operations.lean | 58 +++++++++++++++++++ 4 files changed, 60 insertions(+), 38 deletions(-) create mode 100644 Mathlib/Combinatorics/SimpleGraph/Operations.lean diff --git a/Mathlib.lean b/Mathlib.lean index 2f1f1b2e3b072..0febcb1a2dc25 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1379,6 +1379,7 @@ import Mathlib.Combinatorics.SimpleGraph.IncMatrix import Mathlib.Combinatorics.SimpleGraph.Init import Mathlib.Combinatorics.SimpleGraph.Matching import Mathlib.Combinatorics.SimpleGraph.Metric +import Mathlib.Combinatorics.SimpleGraph.Operations import Mathlib.Combinatorics.SimpleGraph.Partition import Mathlib.Combinatorics.SimpleGraph.Prod import Mathlib.Combinatorics.SimpleGraph.Regularity.Bound diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 5ca69b7108848..2a5e9e6e87070 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -1308,43 +1308,6 @@ theorem DeleteFar.mono (h : G.DeleteFar p r₂) (hr : r₁ ≤ r₂) : G.DeleteF end DeleteFar -/-! ## Vertex replacement -/ - - -section ReplaceVertex - -variable [DecidableEq V] (s t : V) - -/-- The graph formed by forgetting `t`'s neighbours and instead giving it those of `s`. The `s-t` -edge is removed if present. -/ -abbrev replaceVertex : SimpleGraph V where - Adj v w := if v = t then if w = t then False else G.Adj s w - else if w = t then G.Adj v s else G.Adj v w - symm v w := by dsimp only; split_ifs <;> simp [adj_comm] - -/-- There is never an `s-t` edge in `G.replaceVertex s t`. -/ -theorem not_adj_replaceVertex_same : ¬(G.replaceVertex s t).Adj s t := by simp - -@[simp] -theorem replaceVertex_self : G.replaceVertex s s = G := by - ext; dsimp only; split_ifs <;> simp_all [adj_comm] - -/-- Except possibly for `t`, the neighbours of `s` in `G.replaceVertex s t` are its neighbours in -`G`. -/ -lemma adj_replaceVertex_iff_of_ne_left {w : V} (hw : w ≠ t) : - (G.replaceVertex s t).Adj s w ↔ G.Adj s w := by simp [hw] - -/-- Except possibly for itself, the neighbours of `t` in `G.replaceVertex s t` are the neighbours of -`s` in `G`. -/ -lemma adj_replaceVertex_iff_of_ne_right {w : V} (hw : w ≠ t) : - (G.replaceVertex s t).Adj t w ↔ G.Adj s w := by simp [hw] - -/-- Adjacency in `G.replaceVertex s t` which does not involve `t` is the same as that of `G`. -/ -lemma adj_replaceVertex_iff_of_ne {v w : V} (hv : v ≠ t) (hw : w ≠ t) : - (G.replaceVertex s t).Adj v w ↔ G.Adj v w := by simp [hv, hw] - -end ReplaceVertex - /-! ## Map and comap -/ diff --git a/Mathlib/Combinatorics/SimpleGraph/Clique.lean b/Mathlib/Combinatorics/SimpleGraph/Clique.lean index d8f5c9de53809..cf0d783247864 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Clique.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Clique.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 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 Mathlib.Combinatorics.SimpleGraph.Basic +import Mathlib.Combinatorics.SimpleGraph.Operations import Mathlib.Data.Finset.Pairwise import Mathlib.Data.Finset.Preimage diff --git a/Mathlib/Combinatorics/SimpleGraph/Operations.lean b/Mathlib/Combinatorics/SimpleGraph/Operations.lean new file mode 100644 index 0000000000000..03f3af6ab940b --- /dev/null +++ b/Mathlib/Combinatorics/SimpleGraph/Operations.lean @@ -0,0 +1,58 @@ +/- +Copyright (c) 2023 Jeremy Tan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jeremy Tan +-/ +import Mathlib.Combinatorics.SimpleGraph.Basic + +/-! +# Local graph operations + +This file defines some single-graph operations that modify a finite number of vertices +and proves basic theorems about them. When the graph itself has a finite number of vertices +we also prove theorems about the number of edges in the modified graphs. + +## Main definitions + +* `G.replaceVertex s t` is `G` with `t` replaced by a copy of `s`, + removing the `s-t` edge if present. +-/ + + +open Finset + +namespace SimpleGraph + +variable {V : Type*} [DecidableEq V] (G : SimpleGraph V) (s t : V) + +section ReplaceVertex + +/-- The graph formed by forgetting `t`'s neighbours and instead giving it those of `s`. The `s-t` +edge is removed if present. -/ +abbrev replaceVertex : SimpleGraph V where + Adj v w := if v = t then if w = t then False else G.Adj s w + else if w = t then G.Adj v s else G.Adj v w + symm v w := by dsimp only; split_ifs <;> simp [adj_comm] + +/-- There is never an `s-t` edge in `G.replaceVertex s t`. -/ +theorem not_adj_replaceVertex_same : ¬(G.replaceVertex s t).Adj s t := by simp + +@[simp] +theorem replaceVertex_self : G.replaceVertex s s = G := by + ext; dsimp only; split_ifs <;> simp_all [adj_comm] + +/-- Except possibly for `t`, the neighbours of `s` in `G.replaceVertex s t` are its neighbours in +`G`. -/ +lemma adj_replaceVertex_iff_of_ne_left {w : V} (hw : w ≠ t) : + (G.replaceVertex s t).Adj s w ↔ G.Adj s w := by simp [hw] + +/-- Except possibly for itself, the neighbours of `t` in `G.replaceVertex s t` are the neighbours of +`s` in `G`. -/ +lemma adj_replaceVertex_iff_of_ne_right {w : V} (hw : w ≠ t) : + (G.replaceVertex s t).Adj t w ↔ G.Adj s w := by simp [hw] + +/-- Adjacency in `G.replaceVertex s t` which does not involve `t` is the same as that of `G`. -/ +lemma adj_replaceVertex_iff_of_ne {v w : V} (hv : v ≠ t) (hw : w ≠ t) : + (G.replaceVertex s t).Adj v w ↔ G.Adj v w := by simp [hv, hw] + +end ReplaceVertex From b6aa685200bdd74ba470a4e517a4996203bc8218 Mon Sep 17 00:00:00 2001 From: Jeremy Tan Jie Rui Date: Thu, 4 Jan 2024 09:05:47 +0000 Subject: [PATCH 315/353] feat: deprecate `div_le_div_of_le_of_nonneg` (#9399) This was noticed in the discussion around #9393. --- Mathlib/Algebra/Order/Field/Basic.lean | 1 + Mathlib/Algebra/Order/Floor.lean | 2 +- Mathlib/Analysis/Calculus/Monotone.lean | 4 ++-- Mathlib/Analysis/NormedSpace/AddTorsor.lean | 2 +- Mathlib/Combinatorics/Additive/Behrend.lean | 2 +- Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean | 6 +++--- Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean | 2 +- .../Dynamics/Circle/RotationNumber/TranslationNumber.lean | 2 +- Mathlib/Topology/UrysohnsLemma.lean | 4 ++-- 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Mathlib/Algebra/Order/Field/Basic.lean b/Mathlib/Algebra/Order/Field/Basic.lean index 94767a43c7429..13d56dcdd2c8d 100644 --- a/Mathlib/Algebra/Order/Field/Basic.lean +++ b/Mathlib/Algebra/Order/Field/Basic.lean @@ -351,6 +351,7 @@ theorem div_le_div_of_le_left (ha : 0 ≤ a) (hc : 0 < c) (h : c ≤ b) : a / b exact mul_le_mul_of_nonneg_left ((inv_le_inv (hc.trans_le h) hc).mpr h) ha #align div_le_div_of_le_left div_le_div_of_le_left +@[deprecated div_le_div_of_le] theorem div_le_div_of_le_of_nonneg (hab : a ≤ b) (hc : 0 ≤ c) : a / c ≤ b / c := div_le_div_of_le hc hab #align div_le_div_of_le_of_nonneg div_le_div_of_le_of_nonneg diff --git a/Mathlib/Algebra/Order/Floor.lean b/Mathlib/Algebra/Order/Floor.lean index 6ac5c8149f523..97f604bb717cd 100644 --- a/Mathlib/Algebra/Order/Floor.lean +++ b/Mathlib/Algebra/Order/Floor.lean @@ -540,7 +540,7 @@ theorem floor_div_nat (a : α) (n : ℕ) : ⌊a / n⌋₊ = ⌊a⌋₊ / n := by refine' (floor_eq_iff _).2 _ · exact div_nonneg ha n.cast_nonneg constructor - · exact cast_div_le.trans (div_le_div_of_le_of_nonneg (floor_le ha) n.cast_nonneg) + · exact cast_div_le.trans (div_le_div_of_le n.cast_nonneg (floor_le ha)) rw [div_lt_iff, add_mul, one_mul, ← cast_mul, ← cast_add, ← floor_lt ha] · exact lt_div_mul_add hn · exact cast_pos.2 hn diff --git a/Mathlib/Analysis/Calculus/Monotone.lean b/Mathlib/Analysis/Calculus/Monotone.lean index f7db63b63df0d..f1e34d4e81b63 100644 --- a/Mathlib/Analysis/Calculus/Monotone.lean +++ b/Mathlib/Analysis/Calculus/Monotone.lean @@ -171,11 +171,11 @@ theorem Monotone.ae_hasDerivAt {f : ℝ → ℝ} (hf : Monotone f) : · filter_upwards [self_mem_nhdsWithin] rintro y (hy : x < y) have : ↑0 < (y - x) ^ 2 := sq_pos_of_pos (sub_pos.2 hy) - apply div_le_div_of_le_of_nonneg _ (sub_pos.2 hy).le + apply div_le_div_of_le (sub_pos.2 hy).le exact (sub_le_sub_iff_right _).2 (hf.rightLim_le (by norm_num; linarith)) · filter_upwards [self_mem_nhdsWithin] rintro y (hy : x < y) - apply div_le_div_of_le_of_nonneg _ (sub_pos.2 hy).le + apply div_le_div_of_le (sub_pos.2 hy).le exact (sub_le_sub_iff_right _).2 (hf.le_rightLim (le_refl y)) -- prove differentiability on the left, by sandwiching with values of `g` have L2 : Tendsto (fun y => (f y - f x) / (y - x)) (𝓝[<] x) diff --git a/Mathlib/Analysis/NormedSpace/AddTorsor.lean b/Mathlib/Analysis/NormedSpace/AddTorsor.lean index 5bf830a9136bd..d62a98fefaa43 100644 --- a/Mathlib/Analysis/NormedSpace/AddTorsor.lean +++ b/Mathlib/Analysis/NormedSpace/AddTorsor.lean @@ -214,7 +214,7 @@ theorem dist_midpoint_midpoint_le' (p₁ p₂ p₃ p₄ : P) : rw [dist_eq_norm_vsub V, dist_eq_norm_vsub V, dist_eq_norm_vsub V, midpoint_vsub_midpoint] try infer_instance rw [midpoint_eq_smul_add, norm_smul, invOf_eq_inv, norm_inv, ← div_eq_inv_mul] - exact div_le_div_of_le_of_nonneg (norm_add_le _ _) (norm_nonneg _) + exact div_le_div_of_le (norm_nonneg _) (norm_add_le _ _) #align dist_midpoint_midpoint_le' dist_midpoint_midpoint_le' theorem nndist_midpoint_midpoint_le' (p₁ p₂ p₃ p₄ : P) : diff --git a/Mathlib/Combinatorics/Additive/Behrend.lean b/Mathlib/Combinatorics/Additive/Behrend.lean index 247a9d984680f..80aef26aa015e 100644 --- a/Mathlib/Combinatorics/Additive/Behrend.lean +++ b/Mathlib/Combinatorics/Additive/Behrend.lean @@ -333,7 +333,7 @@ theorem exp_neg_two_mul_le {x : ℝ} (hx : 0 < x) : exp (-2 * x) < exp (2 - ⌈x rw [← add_assoc, sub_add_cancel] linarith refine' lt_of_le_of_lt _ (div_lt_div_of_lt_left (exp_pos _) (cast_pos.2 <| ceil_pos.2 hx) h₁) - refine' le_trans _ (div_le_div_of_le_of_nonneg (exp_le_exp.2 h₂) <| add_nonneg hx.le zero_le_one) + refine' le_trans _ (div_le_div_of_le (add_nonneg hx.le zero_le_one) (exp_le_exp.2 h₂)) rw [le_div_iff (add_pos hx zero_lt_one), ← le_div_iff' (exp_pos _), ← exp_sub, neg_mul, sub_neg_eq_add, two_mul, sub_add_add_cancel, add_comm _ x] exact le_trans (le_add_of_nonneg_right zero_le_one) (add_one_le_exp _) diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean index f2edb74f00576..909563bd62209 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean @@ -396,7 +396,7 @@ private theorem eps_le_card_star_div [Nonempty α] (hPα : P.parts.card * 16 ^ P calc 4 / 5 * ε = (1 - 1 / 10) * (1 - 9⁻¹) * ε := by norm_num _ ≤ (1 - ε / 10) * (1 - (↑m)⁻¹) * ((G.nonuniformWitness ε U V).card / U.card) := - (mul_le_mul (mul_le_mul (sub_le_sub_left (div_le_div_of_le_of_nonneg hε₁ <| by norm_num) _) + (mul_le_mul (mul_le_mul (sub_le_sub_left (div_le_div_of_le (by norm_num) hε₁) _) (sub_le_sub_left (inv_le_inv_of_le (by norm_num) <| mod_cast (show 9 ≤ 100 by norm_num).trans (hundred_le_m hPα hPε hε₁)) _) (by norm_num) hε) @@ -462,8 +462,8 @@ private theorem edgeDensity_star_not_uniform [Nonempty α] exact this have hε' : ε ^ 5 ≤ ε := by simpa using pow_le_pow_of_le_one (by sz_positivity) hε₁ (show 1 ≤ 5 by norm_num) - have hpr' : |p - r| ≤ ε / 49 := hpr.trans (div_le_div_of_le_of_nonneg hε' <| by norm_num) - have hqt' : |q - t| ≤ ε / 49 := hqt.trans (div_le_div_of_le_of_nonneg hε' <| by norm_num) + have hpr' : |p - r| ≤ ε / 49 := hpr.trans (div_le_div_of_le (by norm_num) hε') + have hqt' : |q - t| ≤ ε / 49 := hqt.trans (div_le_div_of_le (by norm_num) hε') rw [abs_sub_le_iff] at hrs hpr' hqt' rw [le_abs] at hst ⊢ cases hst diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean index 6d8628c353e76..fddea8a59efcf 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean @@ -147,7 +147,7 @@ theorem energy_increment (hP : P.IsEquipartition) (hP₇ : 7 ≤ P.parts.card) rw [coe_energy, add_div, mul_div_cancel_left]; positivity _ ≤ (∑ x in P.parts.offDiag.attach, (∑ i in distinctPairs G ε hP x, G.edgeDensity i.1 i.2 ^ 2 : ℝ) / 16 ^ P.parts.card) / P.parts.card ^ 2 := - div_le_div_of_le_of_nonneg ?_ $ by positivity + div_le_div_of_le (by positivity) ?_ _ = (∑ x in P.parts.offDiag.attach, ∑ i in distinctPairs G ε hP x, G.edgeDensity i.1 i.2 ^ 2 : ℝ) / (increment hP G ε).parts.card ^ 2 := by rw [card_increment hPα hPG, coe_stepBound, mul_pow, pow_right_comm, diff --git a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean index 58a3f2ce6eb31..e9169f0f59ed5 100644 --- a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean +++ b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean @@ -802,7 +802,7 @@ theorem tendsto_translation_number' (x : ℝ) : theorem translationNumber_mono : Monotone τ := fun f g h => le_of_tendsto_of_tendsto' f.tendsto_translation_number₀ g.tendsto_translation_number₀ fun n => - div_le_div_of_le_of_nonneg (pow_mono h n 0) n.cast_nonneg + div_le_div_of_le n.cast_nonneg (pow_mono h n 0) #align circle_deg1_lift.translation_number_mono CircleDeg1Lift.translationNumber_mono theorem translationNumber_translate (x : ℝ) : τ (translate <| Multiplicative.ofAdd x) = x := diff --git a/Mathlib/Topology/UrysohnsLemma.lean b/Mathlib/Topology/UrysohnsLemma.lean index 928f36b630709..05125f0cb1965 100644 --- a/Mathlib/Topology/UrysohnsLemma.lean +++ b/Mathlib/Topology/UrysohnsLemma.lean @@ -301,8 +301,8 @@ theorem continuous_lim (c : CU P) : Continuous c.lim := by simp only [pow_succ, c.lim_eq_midpoint, c.left.lim_eq_midpoint, c.left.left.lim_of_nmem_U _ hxl, c.left.left.lim_of_nmem_U _ hyl] refine' (dist_midpoint_midpoint_le _ _ _ _).trans _ - refine' (div_le_div_of_le_of_nonneg (add_le_add_right (dist_midpoint_midpoint_le _ _ _ _) _) - zero_le_two).trans _ + refine' (div_le_div_of_le zero_le_two + (add_le_add_right (dist_midpoint_midpoint_le _ _ _ _) _)).trans _ rw [dist_self, zero_add] set r := (3 / 4 : ℝ) ^ n calc _ ≤ (r / 2 + r) / 2 := by gcongr From 496a2e8aa64cb48b230da58c8975fa922068dafe Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Thu, 4 Jan 2024 10:02:49 +0000 Subject: [PATCH 316/353] chore: bump to nightly-2024-01-03 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index df380ce57054d..091c6b09e1a68 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2023-12-31 +leanprover/lean4:nightly-2024-01-03 From 95f91f8e66f14c0eecde8da6dbfeff39d44cbd81 Mon Sep 17 00:00:00 2001 From: Chris Wong Date: Thu, 4 Jan 2024 10:15:58 +0000 Subject: [PATCH 317/353] fix(Cache): don't check stderr for shell commands (#9434) #9419 caused `lean exe cache unpack` to fail with this error: ``` installing leantar 0.1.10 uncaught exception: % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 954k 100 954k 0 0 1608k 0 --:--:-- --:--:-- --:--:-- 1608k ``` This is because `Cache.IO.runCmd` was changed to check `!stderr.isEmpty`, but by default `curl` prints a progress bar which fails this check. --- Cache/IO.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cache/IO.lean b/Cache/IO.lean index 166aff8f5ea31..eda0ba2e362f1 100644 --- a/Cache/IO.lean +++ b/Cache/IO.lean @@ -157,8 +157,7 @@ where /-- Runs a terminal command and retrieves its output -/ def runCmd (cmd : String) (args : Array String) (throwFailure := true) : IO String := do let out ← IO.Process.output { cmd := cmd, args := args } - if (out.exitCode != 0 || !out.stderr.isEmpty) && throwFailure then - throw $ IO.userError out.stderr + if out.exitCode != 0 && throwFailure then throw $ IO.userError out.stderr else return out.stdout def runCurl (args : Array String) (throwFailure := true) : IO String := do From 09a67f99126e536f74876479fecb0e9034b72793 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Thu, 4 Jan 2024 15:11:52 +0100 Subject: [PATCH 318/353] chore: fix nightly testing to work with 2024-01-03 --- Mathlib/Tactic/NormNum/Core.lean | 2 +- Mathlib/Tactic/Positivity/Core.lean | 2 +- Mathlib/Tactic/Propose.lean | 2 +- Mathlib/Tactic/Relation/Trans.lean | 2 +- lake-manifest.json | 10 +++++----- lakefile.lean | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mathlib/Tactic/NormNum/Core.lean b/Mathlib/Tactic/NormNum/Core.lean index 6ebf7ed63e1d7..d3450da515eb2 100644 --- a/Mathlib/Tactic/NormNum/Core.lean +++ b/Mathlib/Tactic/NormNum/Core.lean @@ -69,7 +69,7 @@ initialize normNumExt : ScopedEnvExtension Entry (Entry × NormNumExt) NormNums -- we only need this to deduplicate entries in the DiscrTree have : BEq NormNumExt := ⟨fun _ _ ↦ false⟩ /- Insert `v : NormNumExt` into the tree `dt` on all key sequences given in `kss`. -/ - let insert kss v dt := kss.foldl (fun dt ks ↦ dt.insertCore ks v discrTreeConfig) dt + let insert kss v dt := kss.foldl (fun dt ks ↦ dt.insertCore ks v) dt registerScopedEnvExtension { mkInitial := pure {} ofOLeanEntry := fun _ e@(_, n) ↦ return (e, ← mkNormNumExt n) diff --git a/Mathlib/Tactic/Positivity/Core.lean b/Mathlib/Tactic/Positivity/Core.lean index 755eb8cbe93ee..6df2444342089 100644 --- a/Mathlib/Tactic/Positivity/Core.lean +++ b/Mathlib/Tactic/Positivity/Core.lean @@ -74,7 +74,7 @@ initialize positivityExt : PersistentEnvExtension Entry (Entry × PositivityExt) (List Entry × DiscrTree PositivityExt) ← -- we only need this to deduplicate entries in the DiscrTree have : BEq PositivityExt := ⟨fun _ _ => false⟩ - let insert kss v dt := kss.foldl (fun dt ks => dt.insertCore ks v discrTreeConfig) dt + let insert kss v dt := kss.foldl (fun dt ks => dt.insertCore ks v) dt registerPersistentEnvExtension { mkInitial := pure ([], {}) addImportedFn := fun s => do diff --git a/Mathlib/Tactic/Propose.lean b/Mathlib/Tactic/Propose.lean index b83a8a6427eaa..2cb771a2235c6 100644 --- a/Mathlib/Tactic/Propose.lean +++ b/Mathlib/Tactic/Propose.lean @@ -54,7 +54,7 @@ initialize proposeLemmas : DeclCache (DiscrTree Name) ← let mut lemmas := lemmas for m in mvars do let path ← DiscrTree.mkPath (← inferType m) discrTreeConfig - lemmas := lemmas.insertIfSpecific path name discrTreeConfig + lemmas := lemmas.insertIfSpecific path name pure lemmas /-- Shortcut for calling `solveByElim`. -/ diff --git a/Mathlib/Tactic/Relation/Trans.lean b/Mathlib/Tactic/Relation/Trans.lean index df0b91d4958f8..4d55b9cfab49b 100644 --- a/Mathlib/Tactic/Relation/Trans.lean +++ b/Mathlib/Tactic/Relation/Trans.lean @@ -28,7 +28,7 @@ def transExt.config : WhnfCoreConfig := {} initialize transExt : SimpleScopedEnvExtension (Name × Array DiscrTree.Key) (DiscrTree Name) ← registerSimpleScopedEnvExtension { - addEntry := fun dt (n, ks) ↦ dt.insertCore ks n transExt.config + addEntry := fun dt (n, ks) ↦ dt.insertCore ks n initial := {} } diff --git a/lake-manifest.json b/lake-manifest.json index cb26596280b37..7234fbfaa86a2 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -19,22 +19,22 @@ "inputRev": "master", "inherited": false, "configFile": "lakefile.lean"}, - {"url": "https://github.com/leanprover-community/aesop", + {"url": "https://github.com/nomeata/aesop", "type": "git", "subDir": null, - "rev": "69404390bdc1de946bf0a2e51b1a69f308e56d7a", + "rev": "99334faa22c0e9979e8c79b748f2eb56a4358d7e", "name": "aesop", "manifestFile": "lake-manifest.json", - "inputRev": "master", + "inputRev": "joachim/lean-3123", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, - "rev": "bf61e90de075abfa27f638922e7aafafdce77c44", + "rev": "8dd18350791c85c0fc9adbd6254c94a81d260d35", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.24-pre2", + "inputRev": "main", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover/lean4-cli", diff --git a/lakefile.lean b/lakefile.lean index 1fd431f6de28c..a38efacb0bddc 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -28,8 +28,8 @@ require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" require std from git "https://github.com/leanprover/std4" @ "nightly-testing" require Qq from git "https://github.com/leanprover-community/quote4" @ "master" -require aesop from git "https://github.com/leanprover-community/aesop" @ "master" -require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.24-pre2" +require aesop from git "https://github.com/nomeata/aesop" @ "joachim/lean-3123" +require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "main" require Cli from git "https://github.com/leanprover/lean4-cli" @ "main" /-! From 8aec1e37973d4bf4c221b3991578c75b1dfcd523 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Thu, 4 Jan 2024 15:59:51 +0100 Subject: [PATCH 319/353] Use proofwidgets release --- lake-manifest.json | 2 +- lakefile.lean | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index 7234fbfaa86a2..09a5bcd61761f 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -34,7 +34,7 @@ "rev": "8dd18350791c85c0fc9adbd6254c94a81d260d35", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "main", + "inputRev": "v0.0.25", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover/lean4-cli", diff --git a/lakefile.lean b/lakefile.lean index a38efacb0bddc..fee10b3e4d491 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -29,7 +29,7 @@ require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" require std from git "https://github.com/leanprover/std4" @ "nightly-testing" require Qq from git "https://github.com/leanprover-community/quote4" @ "master" require aesop from git "https://github.com/nomeata/aesop" @ "joachim/lean-3123" -require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "main" +require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.25" require Cli from git "https://github.com/leanprover/lean4-cli" @ "main" /-! From bc480b77b4c7da9df2d4ff9fa1a9fc1d4811ff50 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Thu, 4 Jan 2024 16:37:52 +0100 Subject: [PATCH 320/353] nth_rewrite change --- Mathlib/GroupTheory/Perm/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/GroupTheory/Perm/Basic.lean b/Mathlib/GroupTheory/Perm/Basic.lean index ef4b9df6aeab6..4ac3cb1bc9490 100644 --- a/Mathlib/GroupTheory/Perm/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Basic.lean @@ -587,7 +587,7 @@ theorem mul_swap_eq_iff {i j : α} {σ : Perm α} : σ * swap i j = σ ↔ i = j theorem swap_mul_swap_mul_swap {x y z : α} (hxy : x ≠ y) (hxz : x ≠ z) : swap y z * swap x y * swap y z = swap z x := by - nth_rewrite 2 [← swap_inv] + nth_rewrite 3 [← swap_inv] rw [← swap_apply_apply, swap_apply_left, swap_apply_of_ne_of_ne hxy hxz, swap_comm] #align equiv.swap_mul_swap_mul_swap Equiv.swap_mul_swap_mul_swap From f239a7c44cbf20b5f69bea020e1a57b40ac7a1e1 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Thu, 4 Jan 2024 17:28:05 +0100 Subject: [PATCH 321/353] more nth_rewrite change --- Mathlib/RingTheory/Polynomial/Hermite/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean index c383b83153fbc..d21b4b7548141 100644 --- a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean @@ -172,7 +172,7 @@ theorem coeff_hermite_explicit : simp only -- Factor out (-1)'s. rw [mul_comm (↑k + _ : ℤ), sub_eq_add_neg] - nth_rw 3 [neg_eq_neg_one_mul] + nth_rw 2 [neg_eq_neg_one_mul] simp only [mul_assoc, ← mul_add, pow_succ] congr 2 -- Factor out double factorials. From cf7d6648958b18821ebceaa3f0a2adb156a5fd06 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Thu, 4 Jan 2024 18:10:49 +0100 Subject: [PATCH 322/353] Work around ProofWidgets release contents --- .github/workflows/build.yml.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build.yml.in b/.github/workflows/build.yml.in index cffd2c5b5cd46..77d925b71e62f 100644 --- a/.github/workflows/build.yml.in +++ b/.github/workflows/build.yml.in @@ -155,6 +155,14 @@ jobs: # The 'sleep 1' is small pause to let the network recover. lake exe cache get || (sleep 1; lake exe cache get) + - name: prune ProofWidgets .lake + run: | + # The ProofWidgets release contains not just the `.js` (which we need to build) + # but also `.oleans`, which may be built with the wrong toolchain. + # This removes them. + rm -rf .lake/packages/proofwidgets/.lake/build/lib + rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: build mathlib id: build uses: liskin/gh-problem-matcher-wrap@v2 From 9252ab4d0fe106bc25f3fcf76d4c4460774e5827 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Thu, 4 Jan 2024 18:12:35 +0100 Subject: [PATCH 323/353] Prune before running lake cache get --- .github/workflows/build.yml.in | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml.in b/.github/workflows/build.yml.in index 77d925b71e62f..b42f4ee04ece5 100644 --- a/.github/workflows/build.yml.in +++ b/.github/workflows/build.yml.in @@ -147,13 +147,9 @@ jobs: lean --version lake --version - - name: get cache + - name: build cache cache run: | - lake exe cache clean - # We've been seeing many failures at this step recently because of network errors. - # As a band-aid, we try twice. - # The 'sleep 1' is small pause to let the network recover. - lake exe cache get || (sleep 1; lake exe cache get) + lake build cache - name: prune ProofWidgets .lake run: | @@ -163,6 +159,14 @@ jobs: rm -rf .lake/packages/proofwidgets/.lake/build/lib rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: get cache + run: | + lake exe cache clean + # We've been seeing many failures at this step recently because of network errors. + # As a band-aid, we try twice. + # The 'sleep 1' is small pause to let the network recover. + lake exe cache get || (sleep 1; lake exe cache get) + - name: build mathlib id: build uses: liskin/gh-problem-matcher-wrap@v2 From 9b56a17561b1f6a3cab2dc764d0e884191101ed0 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Thu, 4 Jan 2024 18:13:31 +0100 Subject: [PATCH 324/353] Update workflows --- .github/workflows/bors.yml | 12 ++++++++++++ .github/workflows/build.yml | 12 ++++++++++++ .github/workflows/build_fork.yml | 12 ++++++++++++ 3 files changed, 36 insertions(+) diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index de909506295b8..abb030a2126bd 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -161,6 +161,18 @@ jobs: lean --version lake --version + - name: build cache cache + run: | + lake build cache + + - name: prune ProofWidgets .lake + run: | + # The ProofWidgets release contains not just the `.js` (which we need to build) + # but also `.oleans`, which may be built with the wrong toolchain. + # This removes them. + rm -rf .lake/packages/proofwidgets/.lake/build/lib + rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: get cache run: | lake exe cache clean diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index facc3d356f508..1ff81328af0f5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -168,6 +168,18 @@ jobs: lean --version lake --version + - name: build cache cache + run: | + lake build cache + + - name: prune ProofWidgets .lake + run: | + # The ProofWidgets release contains not just the `.js` (which we need to build) + # but also `.oleans`, which may be built with the wrong toolchain. + # This removes them. + rm -rf .lake/packages/proofwidgets/.lake/build/lib + rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: get cache run: | lake exe cache clean diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index 95b38877f245c..7c66ea4af844b 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -165,6 +165,18 @@ jobs: lean --version lake --version + - name: build cache cache + run: | + lake build cache + + - name: prune ProofWidgets .lake + run: | + # The ProofWidgets release contains not just the `.js` (which we need to build) + # but also `.oleans`, which may be built with the wrong toolchain. + # This removes them. + rm -rf .lake/packages/proofwidgets/.lake/build/lib + rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: get cache run: | lake exe cache clean From 561e9afe588e73cfb54b17c88ada0180f15719f0 Mon Sep 17 00:00:00 2001 From: JADekker <114015169+JADekker@users.noreply.github.com> Date: Thu, 4 Jan 2024 18:16:26 +0000 Subject: [PATCH 325/353] feat(Order/Filter) : add 2 constructors (#9200) Add two constructors to create filters from a property on sets: - `Filter.comk` if the property is stable under finite unions and set shrinking. - `Filter.ofCountableUnion` if the property is stable under countable unions and set shrinking `Filter.comk` is the key ingredient in `IsCompact.induction_on` but may be convenient to have as individual building block. A `Filter` generated by `Filter.ofCountableUnion` is a `CountableInterFilter`, which is given by the instance `Filter.countableInter_ofCountableUnion`. ### Other changes - Use `Filter.comk` for `Filter.cofinite`, `Bornology.ofBounded` and `MeasureTheory.Measure.cofinite`. - Use `Filter.ofCountableUnion` for `MeasureTheory.Measure.ae`. - Use `{_ : Bornology _}` instead of `[Bornology _]` in some lemmas so that `rw/simp` work with non-instance bornologies. Co-authored-by: Yury G. Kudryashov --- .../MeasureTheory/Measure/MeasureSpace.lean | 12 ++----- .../Measure/MeasureSpaceDef.lean | 16 +++------- Mathlib/Order/Filter/Basic.lean | 23 ++++++++++++++ Mathlib/Order/Filter/Cofinite.lean | 7 ++--- Mathlib/Order/Filter/CountableInter.lean | 25 +++++++++++++++ Mathlib/Topology/Bornology/Basic.lean | 31 ++++++------------- Mathlib/Topology/Compactness/Compact.lean | 7 ++--- 7 files changed, 70 insertions(+), 51 deletions(-) diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index f6fd90533d436..e87733ebb9ebf 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -1878,15 +1878,9 @@ end Pointwise /-! ### The `cofinite` filter -/ /-- The filter of sets `s` such that `sᶜ` has finite measure. -/ -def cofinite {m0 : MeasurableSpace α} (μ : Measure α) : Filter α where - sets := { s | μ sᶜ < ∞ } - univ_sets := by simp - inter_sets {s t} hs ht := by - simp only [compl_inter, mem_setOf_eq] - calc - μ (sᶜ ∪ tᶜ) ≤ μ sᶜ + μ tᶜ := measure_union_le _ _ - _ < ∞ := ENNReal.add_lt_top.2 ⟨hs, ht⟩ - sets_of_superset {s t} hs hst := lt_of_le_of_lt (measure_mono <| compl_subset_compl.2 hst) hs +def cofinite {m0 : MeasurableSpace α} (μ : Measure α) : Filter α := + comk (μ · < ∞) (by simp) (fun t ht s hs ↦ (measure_mono hs).trans_lt ht) fun s hs t ht ↦ + (measure_union_le s t).trans_lt <| ENNReal.add_lt_top.2 ⟨hs, ht⟩ #align measure_theory.measure.cofinite MeasureTheory.Measure.cofinite theorem mem_cofinite : s ∈ μ.cofinite ↔ μ sᶜ < ∞ := diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean index a68d762f3c371..dc80e03812b97 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean @@ -363,13 +363,10 @@ theorem measure_inter_null_of_null_left {S : Set α} (T : Set α) (h : μ S = 0) /-! ### The almost everywhere filter -/ - /-- The “almost everywhere” filter of co-null sets. -/ -def Measure.ae {α} {m : MeasurableSpace α} (μ : Measure α) : Filter α where - sets := { s | μ sᶜ = 0 } - univ_sets := by simp - inter_sets hs ht := by simp only [compl_inter, mem_setOf_eq]; exact measure_union_null hs ht - sets_of_superset hs hst := measure_mono_null (Set.compl_subset_compl.2 hst) hs +def Measure.ae {α : Type*} {_m : MeasurableSpace α} (μ : Measure α) : Filter α := + ofCountableUnion (μ · = 0) (fun _S hSc ↦ (measure_sUnion_null_iff hSc).2) fun _t ht _s hs ↦ + measure_mono_null hs ht #align measure_theory.measure.ae MeasureTheory.Measure.ae -- mathport name: «expr∀ᵐ ∂ , » @@ -415,11 +412,8 @@ theorem ae_of_all {p : α → Prop} (μ : Measure α) : (∀ a, p a) → ∀ᵐ -- ⟨fun s hs => let ⟨t, hst, htm, htμ⟩ := exists_measurable_superset_of_null hs; -- ⟨tᶜ, compl_mem_ae_iff.2 htμ, htm.compl, compl_subset_comm.1 hst⟩⟩ -instance instCountableInterFilter : CountableInterFilter μ.ae := - ⟨by - intro S hSc hS - rw [mem_ae_iff, compl_sInter, sUnion_image] - exact (measure_biUnion_null_iff hSc).2 hS⟩ +instance instCountableInterFilter : CountableInterFilter μ.ae := by + unfold Measure.ae; infer_instance #align measure_theory.measure.ae.countable_Inter_filter MeasureTheory.instCountableInterFilter theorem ae_all_iff {ι : Sort*} [Countable ι] {p : α → ι → Prop} : diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index b9381a98c8117..41393120a5061 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -3325,3 +3325,26 @@ theorem Set.MapsTo.tendsto {α β} {s : Set α} {t : Set β} {f : α → β} (h Filter.Tendsto f (𝓟 s) (𝓟 t) := Filter.tendsto_principal_principal.2 h #align set.maps_to.tendsto Set.MapsTo.tendsto + +namespace Filter + +/-- Construct a filter from a property that is stable under finite unions. +A set `s` belongs to `Filter.comk p _ _ _` iff its complement satisfies the predicate `p`. +This constructor is useful to define filters like `Filter.cofinite`. -/ +def comk (p : Set α → Prop) (he : p ∅) (hmono : ∀ t, p t → ∀ s ⊆ t, p s) + (hunion : ∀ s, p s → ∀ t, p t → p (s ∪ t)) : Filter α where + sets := {t | p tᶜ} + univ_sets := by simpa + sets_of_superset := fun ht₁ ht => hmono _ ht₁ _ (compl_subset_compl.2 ht) + inter_sets := fun ht₁ ht₂ => by simp [compl_inter, hunion _ ht₁ _ ht₂] + +@[simp] +lemma mem_comk {p : Set α → Prop} {he hmono hunion s} : + s ∈ comk p he hmono hunion ↔ p sᶜ := + .rfl + +lemma compl_mem_comk {p : Set α → Prop} {he hmono hunion s} : + sᶜ ∈ comk p he hmono hunion ↔ p s := by + simp + +end Filter diff --git a/Mathlib/Order/Filter/Cofinite.lean b/Mathlib/Order/Filter/Cofinite.lean index 2275cbf66e058..c145c66ebb9d2 100644 --- a/Mathlib/Order/Filter/Cofinite.lean +++ b/Mathlib/Order/Filter/Cofinite.lean @@ -29,11 +29,8 @@ variable {ι α β : Type*} {l : Filter α} namespace Filter /-- The cofinite filter is the filter of subsets whose complements are finite. -/ -def cofinite : Filter α where - sets := { s | sᶜ.Finite } - univ_sets := by simp only [compl_univ, finite_empty, mem_setOf_eq] - sets_of_superset hs st := hs.subset <| compl_subset_compl.2 st - inter_sets hs ht := by simpa only [compl_inter, mem_setOf_eq] using hs.union ht +def cofinite : Filter α := + comk Set.Finite finite_empty (fun _t ht _s hsub ↦ ht.subset hsub) fun _ h _ ↦ h.union #align filter.cofinite Filter.cofinite @[simp] diff --git a/Mathlib/Order/Filter/CountableInter.lean b/Mathlib/Order/Filter/CountableInter.lean index e560005b7ed43..96d2f8bd148d2 100644 --- a/Mathlib/Order/Filter/CountableInter.lean +++ b/Mathlib/Order/Filter/CountableInter.lean @@ -150,6 +150,31 @@ theorem Filter.mem_ofCountableInter {l : Set (Set α)} Iff.rfl #align filter.mem_of_countable_Inter Filter.mem_ofCountableInter +/-- Construct a filter with countable intersection property. +Similarly to `Filter.comk`, a set belongs to this filter if its complement satisfies the property. +Similarly to `Filter.ofCountableInter`, +this constructor deduces some properties from the countable intersection property +which becomes the countable union property because we take complements of all sets. + +Another small difference from `Filter.ofCountableInter` +is that this definition takes `p : Set α → Prop` instead of `Set (Set α)`. -/ +def Filter.ofCountableUnion (p : Set α → Prop) + (hUnion : ∀ S : Set (Set α), S.Countable → (∀ s ∈ S, p s) → p (⋃₀ S)) + (hmono : ∀ t, p t → ∀ s ⊆ t, p s) : Filter α := by + refine .ofCountableInter {s | p sᶜ} (fun S hSc hSp ↦ ?_) fun s t ht hsub ↦ ?_ + · rw [mem_setOf_eq, compl_sInter] + exact hUnion _ (hSc.image _) (ball_image_iff.2 hSp) + · exact hmono _ ht _ (compl_subset_compl.2 hsub) + +instance Filter.countableInter_ofCountableUnion (p : Set α → Prop) (h₁ h₂) : + CountableInterFilter (Filter.ofCountableUnion p h₁ h₂) := + countableInter_ofCountableInter .. + +@[simp] +theorem Filter.mem_ofCountableUnion {p : Set α → Prop} {hunion hmono s} : + s ∈ ofCountableUnion p hunion hmono ↔ p sᶜ := + Iff.rfl + instance countableInterFilter_principal (s : Set α) : CountableInterFilter (𝓟 s) := ⟨fun _ _ hS => subset_sInter hS⟩ #align countable_Inter_filter_principal countableInterFilter_principal diff --git a/Mathlib/Topology/Bornology/Basic.lean b/Mathlib/Topology/Bornology/Basic.lean index c7d11d2ea4a4e..b45b72bc1b2fb 100644 --- a/Mathlib/Topology/Bornology/Basic.lean +++ b/Mathlib/Topology/Bornology/Basic.lean @@ -94,23 +94,14 @@ def Bornology.ofBounded {α : Type*} (B : Set (Set α)) (subset_mem : ∀ s₁ ∈ B, ∀ s₂ ⊆ s₁, s₂ ∈ B) (union_mem : ∀ s₁ ∈ B, ∀ s₂ ∈ B, s₁ ∪ s₂ ∈ B) (singleton_mem : ∀ x, {x} ∈ B) : Bornology α where - cobounded' := - { sets := { s : Set α | sᶜ ∈ B } - univ_sets := by rwa [← compl_univ] at empty_mem - sets_of_superset := fun hx hy => subset_mem _ hx _ (compl_subset_compl.mpr hy) - inter_sets := fun hx hy => by simpa [compl_inter] using union_mem _ hx _ hy } - le_cofinite' := by - rw [le_cofinite_iff_compl_singleton_mem] - intro x - change {x}ᶜᶜ ∈ B - rw [compl_compl] - exact singleton_mem x + cobounded' := comk (· ∈ B) empty_mem subset_mem union_mem + le_cofinite' := by simpa [le_cofinite_iff_compl_singleton_mem] #align bornology.of_bounded Bornology.ofBounded -#align bornology.of_bounded_cobounded_sets Bornology.ofBounded_cobounded_sets +#align bornology.of_bounded_cobounded_sets Bornology.ofBounded_cobounded /-- A constructor for bornologies by specifying the bounded sets, and showing that they satisfy the appropriate conditions. -/ -@[simps!] +@[simps! cobounded] def Bornology.ofBounded' {α : Type*} (B : Set (Set α)) (empty_mem : ∅ ∈ B) (subset_mem : ∀ s₁ ∈ B, ∀ s₂ ⊆ s₁, s₂ ∈ B) @@ -122,24 +113,24 @@ def Bornology.ofBounded' {α : Type*} (B : Set (Set α)) rcases sUnion_univ x with ⟨s, hs, hxs⟩ exact subset_mem s hs {x} (singleton_subset_iff.mpr hxs) #align bornology.of_bounded' Bornology.ofBounded' -#align bornology.of_bounded'_cobounded_sets Bornology.ofBounded'_cobounded_sets +#align bornology.of_bounded'_cobounded_sets Bornology.ofBounded'_cobounded namespace Bornology section -variable [Bornology α] {s t : Set α} {x : α} - /-- `IsCobounded` is the predicate that `s` is in the filter of cobounded sets in the ambient bornology on `α` -/ -def IsCobounded (s : Set α) : Prop := +def IsCobounded [Bornology α] (s : Set α) : Prop := s ∈ cobounded α #align bornology.is_cobounded Bornology.IsCobounded /-- `IsBounded` is the predicate that `s` is bounded relative to the ambient bornology on `α`. -/ -def IsBounded (s : Set α) : Prop := +def IsBounded [Bornology α] (s : Set α) : Prop := IsCobounded sᶜ #align bornology.is_bounded Bornology.IsBounded +variable {_ : Bornology α} {s t : Set α} {x : α} + theorem isCobounded_def {s : Set α} : IsCobounded s ↔ s ∈ cobounded α := Iff.rfl #align bornology.is_cobounded_def Bornology.isCobounded_def @@ -263,9 +254,7 @@ theorem isCobounded_ofBounded_iff (B : Set (Set α)) {empty_mem subset_mem union theorem isBounded_ofBounded_iff (B : Set (Set α)) {empty_mem subset_mem union_mem sUnion_univ} : @IsBounded _ (ofBounded B empty_mem subset_mem union_mem sUnion_univ) s ↔ s ∈ B := by - rw [@isBounded_def _ (ofBounded B empty_mem subset_mem union_mem sUnion_univ), ← Filter.mem_sets, - ofBounded_cobounded_sets, Set.mem_setOf_eq, compl_compl] --- porting note: again had to use `@isBounded_def _` and feed Lean the instance + rw [isBounded_def, ofBounded_cobounded, compl_mem_comk] #align bornology.is_bounded_of_bounded_iff Bornology.isBounded_ofBounded_iff variable [Bornology α] diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index e98a426fc3409..54dc5979f52e9 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.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, Yury Kudryashov -/ +import Mathlib.Order.Filter.Basic import Mathlib.Topology.Bases import Mathlib.Data.Set.Accumulate import Mathlib.Topology.Bornology.Basic @@ -69,11 +70,7 @@ theorem IsCompact.compl_mem_sets_of_nhdsWithin (hs : IsCompact s) {f : Filter X} theorem IsCompact.induction_on (hs : IsCompact s) {p : Set X → Prop} (he : p ∅) (hmono : ∀ ⦃s t⦄, s ⊆ t → p t → p s) (hunion : ∀ ⦃s t⦄, p s → p t → p (s ∪ t)) (hnhds : ∀ x ∈ s, ∃ t ∈ 𝓝[s] x, p t) : p s := by - let f : Filter X := - { sets := { t | p tᶜ } - univ_sets := by simpa - sets_of_superset := fun ht₁ ht => hmono (compl_subset_compl.2 ht) ht₁ - inter_sets := fun ht₁ ht₂ => by simp [compl_inter, hunion ht₁ ht₂] } + let f : Filter X := comk p he (fun _t ht _s hsub ↦ hmono hsub ht) (fun _s hs _t ht ↦ hunion hs ht) have : sᶜ ∈ f := hs.compl_mem_sets_of_nhdsWithin (by simpa using hnhds) rwa [← compl_compl s] #align is_compact.induction_on IsCompact.induction_on From 02d418dd90a607cd0960d41ce0f59e44dc9cd3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 4 Jan 2024 22:32:41 +0000 Subject: [PATCH 326/353] chore: Move `MulOpposite.op_pow` (#9442) These lemmas can actually be proved much earlier than they were. Part of #9411 --- Mathlib/Algebra/Group/Opposite.lean | 23 +++++++++++++++++++++++ Mathlib/Algebra/GroupPower/Lemmas.lean | 26 -------------------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/Mathlib/Algebra/Group/Opposite.lean b/Mathlib/Algebra/Group/Opposite.lean index 6948b4de58f1b..70eb2124c42a3 100644 --- a/Mathlib/Algebra/Group/Opposite.lean +++ b/Mathlib/Algebra/Group/Opposite.lean @@ -181,6 +181,29 @@ instance commGroup [CommGroup α] : CommGroup αᵐᵒᵖ := { MulOpposite.group α, MulOpposite.commMonoid α with } variable {α} + +section Monoid +variable [Monoid α] + +@[simp] lemma op_pow (x : α) (n : ℕ) : op (x ^ n) = op x ^ n := rfl +#align mul_opposite.op_pow MulOpposite.op_pow + +@[simp] lemma unop_pow (x : αᵐᵒᵖ) (n : ℕ) : unop (x ^ n) = unop x ^ n := rfl +#align mul_opposite.unop_pow MulOpposite.unop_pow + +end Monoid + +section DivInvMonoid +variable [DivInvMonoid α] + +@[simp] lemma op_zpow (x : α) (z : ℤ) : op (x ^ z) = op x ^ z := rfl +#align mul_opposite.op_zpow MulOpposite.op_zpow + +@[simp] lemma unop_zpow (x : αᵐᵒᵖ) (z : ℤ) : unop (x ^ z) = unop x ^ z := rfl +#align mul_opposite.unop_zpow MulOpposite.unop_zpow + +end DivInvMonoid + @[to_additive (attr := simp, norm_cast)] theorem op_natCast [NatCast α] (n : ℕ) : op (n : α) = n := rfl diff --git a/Mathlib/Algebra/GroupPower/Lemmas.lean b/Mathlib/Algebra/GroupPower/Lemmas.lean index 7e2e718de4be1..32a1e07074ae7 100644 --- a/Mathlib/Algebra/GroupPower/Lemmas.lean +++ b/Mathlib/Algebra/GroupPower/Lemmas.lean @@ -1218,32 +1218,6 @@ theorem conj_pow' (u : Mˣ) (x : M) (n : ℕ) : end Units -namespace MulOpposite - -/-- Moving to the opposite monoid commutes with taking powers. -/ -@[simp] -theorem op_pow [Monoid M] (x : M) (n : ℕ) : op (x ^ n) = op x ^ n := - rfl -#align mul_opposite.op_pow MulOpposite.op_pow - -@[simp] -theorem unop_pow [Monoid M] (x : Mᵐᵒᵖ) (n : ℕ) : unop (x ^ n) = unop x ^ n := - rfl -#align mul_opposite.unop_pow MulOpposite.unop_pow - -/-- Moving to the opposite group or `GroupWithZero` commutes with taking powers. -/ -@[simp] -theorem op_zpow [DivInvMonoid M] (x : M) (z : ℤ) : op (x ^ z) = op x ^ z := - rfl -#align mul_opposite.op_zpow MulOpposite.op_zpow - -@[simp] -theorem unop_zpow [DivInvMonoid M] (x : Mᵐᵒᵖ) (z : ℤ) : unop (x ^ z) = unop x ^ z := - rfl -#align mul_opposite.unop_zpow MulOpposite.unop_zpow - -end MulOpposite - -- Porting note: this was added in an ad hoc port for use in `Tactic/NormNum/Basic` @[simp] theorem pow_eq {m : ℤ} {n : ℕ} : m.pow n = m ^ n := rfl From 8e19af95a024bb65b32488e4d2f67c7ab142977f Mon Sep 17 00:00:00 2001 From: Winston Yin Date: Thu, 4 Jan 2024 23:32:25 +0000 Subject: [PATCH 327/353] chore: Rename over-general names (#9429) Items 1-3 in [reference Zulip](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Assorted.20renames/near/411096017) Rename `chartedSpace`, `smoothMfldWithCorners`, and `funLike`. --- Mathlib/Geometry/Manifold/Instances/Sphere.lean | 10 +++++----- Mathlib/NumberTheory/LegendreSymbol/MulCharacter.lean | 2 +- docs/overview.yaml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Instances/Sphere.lean b/Mathlib/Geometry/Manifold/Instances/Sphere.lean index bb922383d08d1..c84328c8ea028 100644 --- a/Mathlib/Geometry/Manifold/Instances/Sphere.lean +++ b/Mathlib/Geometry/Manifold/Instances/Sphere.lean @@ -382,7 +382,7 @@ theorem stereographic'_target {n : ℕ} [Fact (finrank ℝ E = n + 1)] (v : sphe /-- The unit sphere in an `n + 1`-dimensional inner product space `E` is a charted space modelled on the Euclidean space of dimension `n`. -/ -instance chartedSpace {n : ℕ} [Fact (finrank ℝ E = n + 1)] : +instance EuclideanSpace.instChartedSpaceSphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] : ChartedSpace (EuclideanSpace ℝ (Fin n)) (sphere (0 : E) 1) where atlas := {f | ∃ v : sphere (0 : E) 1, f = stereographic' n v} chartAt v := stereographic' n (-v) @@ -411,7 +411,7 @@ theorem stereographic'_symm_apply {n : ℕ} [Fact (finrank ℝ E = n + 1)] (v : /-- The unit sphere in an `n + 1`-dimensional inner product space `E` is a smooth manifold, modelled on the Euclidean space of dimension `n`. -/ -instance smoothMfldWithCorners {n : ℕ} [Fact (finrank ℝ E = n + 1)] : +instance EuclideanSpace.instSmoothManifoldWithCornersSphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] : SmoothManifoldWithCorners (𝓡 n) (sphere (0 : E) 1) := smoothManifoldWithCorners_of_contDiffOn (𝓡 n) (sphere (0 : E) 1) (by @@ -443,7 +443,7 @@ instance smoothMfldWithCorners {n : ℕ} [Fact (finrank ℝ E = n + 1)] : theorem contMDiff_coe_sphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] : ContMDiff (𝓡 n) 𝓘(ℝ, E) ∞ ((↑) : sphere (0 : E) 1 → E) := by -- Porting note: trouble with filling these implicit variables in the instance - have := smoothMfldWithCorners (E := E) (n := n) + have := EuclideanSpace.instSmoothManifoldWithCornersSphere (E := E) (n := n) rw [contMDiff_iff] constructor · exact continuous_subtype_val @@ -589,10 +589,10 @@ attribute [local instance] finrank_real_complex_fact' /-- The unit circle in `ℂ` is a charted space modelled on `EuclideanSpace ℝ (Fin 1)`. This follows by definition from the corresponding result for `Metric.Sphere`. -/ instance : ChartedSpace (EuclideanSpace ℝ (Fin 1)) circle := - chartedSpace + EuclideanSpace.instChartedSpaceSphere instance : SmoothManifoldWithCorners (𝓡 1) circle := - smoothMfldWithCorners (E := ℂ) + EuclideanSpace.instSmoothManifoldWithCornersSphere (E := ℂ) /-- The unit circle in `ℂ` is a Lie group. -/ instance : LieGroup (𝓡 1) circle where diff --git a/Mathlib/NumberTheory/LegendreSymbol/MulCharacter.lean b/Mathlib/NumberTheory/LegendreSymbol/MulCharacter.lean index d9bef5da10fd8..4bc6b10688607 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/MulCharacter.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/MulCharacter.lean @@ -71,7 +71,7 @@ structure MulChar extends MonoidHom R R' where map_nonunit' : ∀ a : R, ¬IsUnit a → toFun a = 0 #align mul_char MulChar -instance funLike : FunLike (MulChar R R') R (fun _ => R') := +instance MulChar.instFunLike : FunLike (MulChar R R') R (fun _ => R') := ⟨fun χ => χ.toFun, fun χ₀ χ₁ h => by cases χ₀; cases χ₁; congr; apply MonoidHom.ext (fun _ => congr_fun h _)⟩ diff --git a/docs/overview.yaml b/docs/overview.yaml index d262da1176d36..bf6a5b7332969 100644 --- a/docs/overview.yaml +++ b/docs/overview.yaml @@ -408,7 +408,7 @@ Geometry: tangent bundle: 'TangentBundle' tangent map: 'tangentMap' Lie group: 'LieGroup' - sphere: 'smoothMfldWithCorners' + sphere: 'EuclideanSpace.instSmoothManifoldWithCornersSphere' Algebraic geometry: prime spectrum: 'PrimeSpectrum' From 86decee4d83d85770dda012b1bc1c2329a02f773 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 5 Jan 2024 00:28:18 +0000 Subject: [PATCH 328/353] chore(Tactic/CancelDenoms/Core): slightly Qq-ify and golf (#9421) Using a stronger type for `synthesizeUsingNormNum` removes the need for a handful of `let`s. --- Mathlib/Tactic/CancelDenoms/Core.lean | 28 ++++++++++----------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/Mathlib/Tactic/CancelDenoms/Core.lean b/Mathlib/Tactic/CancelDenoms/Core.lean index 9a8ebbeb22ffc..5d56764a986e7 100644 --- a/Mathlib/Tactic/CancelDenoms/Core.lean +++ b/Mathlib/Tactic/CancelDenoms/Core.lean @@ -26,8 +26,6 @@ There are likely some rough edges to it. Improving this tactic would be a good project for someone interested in learning tactic programming. -/ -set_option autoImplicit true - open Lean Parser Tactic Mathlib Meta NormNum Qq initialize registerTraceClass `CancelDenoms @@ -149,7 +147,7 @@ partial def findCancelFactor (e : Expr) : ℕ × Tree ℕ := | none => (1, .node 1 .nil .nil) | _ => (1, .node 1 .nil .nil) -def synthesizeUsingNormNum (type : Expr) : MetaM Expr := do +def synthesizeUsingNormNum (type : Q(Prop)) : MetaM Q($type) := do try synthesizeUsingTactic' type (← `(tactic| norm_num)) catch e => @@ -160,9 +158,9 @@ def synthesizeUsingNormNum (type : Expr) : MetaM Expr := do canceled in `e'`, distributing `v` proportionally according to the tree `tr` computed by `findCancelFactor`. -/ -partial def mkProdPrf (α : Q(Type u)) (sα : Q(Field $α)) (v : ℕ) (t : Tree ℕ) +partial def mkProdPrf {u : Level} (α : Q(Type u)) (sα : Q(Field $α)) (v : ℕ) (t : Tree ℕ) (e : Q($α)) : MetaM Expr := do - let amwo ← synthInstanceQ q(AddMonoidWithOne $α) + let amwo : Q(AddMonoidWithOne $α) := q(inferInstance) trace[CancelDenoms] "mkProdPrf {e} {v}" match t, e with | .node _ lhs rhs, ~q($e1 + $e2) => do @@ -180,8 +178,7 @@ partial def mkProdPrf (α : Q(Type u)) (sα : Q(Field $α)) (v : ℕ) (t : Tree have ln' := (← mkOfNat α amwo <| mkRawNatLit ln).1 have vln' := (← mkOfNat α amwo <| mkRawNatLit (v/ln)).1 have v' := (← mkOfNat α amwo <| mkRawNatLit v).1 - let ntp : Q(Prop) := q($ln' * $vln' = $v') - let npf ← synthesizeUsingNormNum ntp + let npf ← synthesizeUsingNormNum q($ln' * $vln' = $v') mkAppM ``CancelDenoms.mul_subst #[v1, v2, npf] | .node _ lhs (.node rn _ _), ~q($e1 / $e2) => do -- Invariant: e2 is equal to the natural number rn @@ -189,10 +186,8 @@ partial def mkProdPrf (α : Q(Type u)) (sα : Q(Field $α)) (v : ℕ) (t : Tree have rn' := (← mkOfNat α amwo <| mkRawNatLit rn).1 have vrn' := (← mkOfNat α amwo <| mkRawNatLit <| v / rn).1 have v' := (← mkOfNat α amwo <| mkRawNatLit <| v).1 - let ntp : Q(Prop) := q($rn' / $e2 = 1) - let npf ← synthesizeUsingNormNum ntp - let ntp2 : Q(Prop) := q($vrn' * $rn' = $v') - let npf2 ← synthesizeUsingNormNum ntp2 + let npf ← synthesizeUsingNormNum q($rn' / $e2 = 1) + let npf2 ← synthesizeUsingNormNum q($vrn' * $rn' = $v') mkAppM ``CancelDenoms.div_subst #[v1, npf, npf2] | t, ~q(-$e) => do let v ← mkProdPrf α sα v t e @@ -203,17 +198,14 @@ partial def mkProdPrf (α : Q(Type u)) (sα : Q(Field $α)) (v : ℕ) (t : Tree have k1' := (← mkOfNat α amwo <| mkRawNatLit k1).1 have v' := (← mkOfNat α amwo <| mkRawNatLit v).1 have l' := (← mkOfNat α amwo <| mkRawNatLit l).1 - let ntp : Q(Prop) := q($l' * $k1' ^ $e2 = $v') - let npf ← synthesizeUsingNormNum ntp + let npf ← synthesizeUsingNormNum q($l' * $k1' ^ $e2 = $v') mkAppM ``CancelDenoms.pow_subst #[v1, npf] | .node _ .nil (.node rn _ _), ~q($e ⁻¹) => do have rn' := (← mkOfNat α amwo <| mkRawNatLit rn).1 have vrn' := (← mkOfNat α amwo <| mkRawNatLit <| v / rn).1 have v' := (← mkOfNat α amwo <| mkRawNatLit <| v).1 - let ntp : Q(Prop) := q($rn' ≠ 0) - let npf ← synthesizeUsingNormNum ntp - let ntp2 : Q(Prop) := q($vrn' * $rn' = $v') - let npf2 ← synthesizeUsingNormNum ntp2 + let npf ← synthesizeUsingNormNum q($rn' ≠ 0) + let npf2 ← synthesizeUsingNormNum q($vrn' * $rn' = $v') mkAppM ``CancelDenoms.inv_subst #[npf, npf2] | _, _ => do have v' := (← mkOfNat α amwo <| mkRawNatLit <| v).1 @@ -226,7 +218,7 @@ def deriveThms : List Name := [``div_div_eq_mul_div, ``div_neg] /-- Helper lemma to chain together a `simp` proof and the result of `mkProdPrf`. -/ -theorem derive_trans [Mul α] {a b c d : α} (h : a = b) (h' : c * b = d) : c * a = d := h ▸ h' +theorem derive_trans {α} [Mul α] {a b c d : α} (h : a = b) (h' : c * b = d) : c * a = d := h ▸ h' /-- Given `e`, a term with rational division, produces a natural number `n` and a proof of `n*e = e'`, From f40990a65761feba2d7f2d8563b064b268732cd1 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 5 Jan 2024 11:55:30 +1100 Subject: [PATCH 329/353] . --- lake-manifest.json | 6 +++--- lakefile.lean | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index 09a5bcd61761f..b32e185ca32d0 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -19,13 +19,13 @@ "inputRev": "master", "inherited": false, "configFile": "lakefile.lean"}, - {"url": "https://github.com/nomeata/aesop", + {"url": "https://github.com/leanprover-community/aesop", "type": "git", "subDir": null, - "rev": "99334faa22c0e9979e8c79b748f2eb56a4358d7e", + "rev": "48375eac3aa5e3be2869d718e1f5c38b83787243", "name": "aesop", "manifestFile": "lake-manifest.json", - "inputRev": "joachim/lean-3123", + "inputRev": "bump/v4.6.0", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover-community/ProofWidgets4", diff --git a/lakefile.lean b/lakefile.lean index fee10b3e4d491..3d8d080cdaea8 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -28,7 +28,7 @@ require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" require std from git "https://github.com/leanprover/std4" @ "nightly-testing" require Qq from git "https://github.com/leanprover-community/quote4" @ "master" -require aesop from git "https://github.com/nomeata/aesop" @ "joachim/lean-3123" +require aesop from git "https://github.com/leanprover-community/aesop" @ "bump/v4.6.0" require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.25" require Cli from git "https://github.com/leanprover/lean4-cli" @ "main" From 700b5743b7404638e605cfc1ff0175e378e158af Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 5 Jan 2024 11:58:14 +1100 Subject: [PATCH 330/353] improve comments --- .github/workflows/bors.yml | 6 +++--- .github/workflows/build.yml | 6 +++--- .github/workflows/build.yml.in | 6 +++--- .github/workflows/build_fork.yml | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index abb030a2126bd..b8a1461fbc118 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -161,14 +161,14 @@ jobs: lean --version lake --version - - name: build cache cache + - name: build cache run: | lake build cache - name: prune ProofWidgets .lake run: | - # The ProofWidgets release contains not just the `.js` (which we need to build) - # but also `.oleans`, which may be built with the wrong toolchain. + # The ProofWidgets release contains not just the `.js` (which we need in order to build) + # but also `.oleans`, which may have been built with the wrong toolchain. # This removes them. rm -rf .lake/packages/proofwidgets/.lake/build/lib rm -rf .lake/packages/proofwidgets/.lake/build/ir diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1ff81328af0f5..91e950f442f7d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -168,14 +168,14 @@ jobs: lean --version lake --version - - name: build cache cache + - name: build cache run: | lake build cache - name: prune ProofWidgets .lake run: | - # The ProofWidgets release contains not just the `.js` (which we need to build) - # but also `.oleans`, which may be built with the wrong toolchain. + # The ProofWidgets release contains not just the `.js` (which we need in order to build) + # but also `.oleans`, which may have been built with the wrong toolchain. # This removes them. rm -rf .lake/packages/proofwidgets/.lake/build/lib rm -rf .lake/packages/proofwidgets/.lake/build/ir diff --git a/.github/workflows/build.yml.in b/.github/workflows/build.yml.in index b42f4ee04ece5..2b59b60d39603 100644 --- a/.github/workflows/build.yml.in +++ b/.github/workflows/build.yml.in @@ -147,14 +147,14 @@ jobs: lean --version lake --version - - name: build cache cache + - name: build cache run: | lake build cache - name: prune ProofWidgets .lake run: | - # The ProofWidgets release contains not just the `.js` (which we need to build) - # but also `.oleans`, which may be built with the wrong toolchain. + # The ProofWidgets release contains not just the `.js` (which we need in order to build) + # but also `.oleans`, which may have been built with the wrong toolchain. # This removes them. rm -rf .lake/packages/proofwidgets/.lake/build/lib rm -rf .lake/packages/proofwidgets/.lake/build/ir diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index 7c66ea4af844b..edaa74ab6c7f2 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -165,14 +165,14 @@ jobs: lean --version lake --version - - name: build cache cache + - name: build cache run: | lake build cache - name: prune ProofWidgets .lake run: | - # The ProofWidgets release contains not just the `.js` (which we need to build) - # but also `.oleans`, which may be built with the wrong toolchain. + # The ProofWidgets release contains not just the `.js` (which we need in order to build) + # but also `.oleans`, which may have been built with the wrong toolchain. # This removes them. rm -rf .lake/packages/proofwidgets/.lake/build/lib rm -rf .lake/packages/proofwidgets/.lake/build/ir From 19557c783a5ea8214203e763f27787acbb048bf3 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 5 Jan 2024 01:23:50 +0000 Subject: [PATCH 331/353] chore: bump std4 dependency (#9426) This is quite a substantial bump as `Nondet` / `backtrack` / `solve_by_elim` have all moved to Std. Co-authored-by: Scott Morrison --- ImportGraph/Main.lean | 4 +- Mathlib.lean | 7 - .../Computation/Approximations.lean | 2 +- Mathlib/Computability/PartrecCode.lean | 8 +- Mathlib/Data/MLList/Basic.lean | 26 - Mathlib/Data/Nat/PSub.lean | 6 +- Mathlib/Data/Nondet/Basic.lean | 206 ------- Mathlib/Data/Option/Basic.lean | 9 +- Mathlib/Data/Set/Enumerate.lean | 6 +- Mathlib/Lean/Data/NameMap.lean | 44 -- Mathlib/Lean/IO/Process.lean | 43 -- Mathlib/Lean/Meta.lean | 10 - Mathlib/Lean/Name.lean | 2 +- Mathlib/Lean/SMap.lean | 17 - Mathlib/Mathport/Syntax.lean | 1 - Mathlib/Tactic.lean | 2 - Mathlib/Tactic/Backtrack.lean | 198 ------- Mathlib/Tactic/Common.lean | 1 - Mathlib/Tactic/GCongr/Core.lean | 2 +- Mathlib/Tactic/Hint.lean | 2 +- Mathlib/Tactic/LibrarySearch.lean | 3 +- Mathlib/Tactic/Monotonicity/Basic.lean | 4 +- Mathlib/Tactic/Nontriviality/Core.lean | 4 +- Mathlib/Tactic/Propose.lean | 2 +- Mathlib/Tactic/Relation/Symm.lean | 27 +- Mathlib/Tactic/Rewrites.lean | 2 +- Mathlib/Tactic/SolveByElim.lean | 501 ------------------ Mathlib/Tactic/Tauto.lean | 2 +- Mathlib/Util/Imports.lean | 2 +- lake-manifest.json | 2 +- test/Nondet.lean | 76 --- test/apply_rules.lean | 2 +- test/solve_by_elim/basic.lean | 2 +- test/solve_by_elim/instances.lean | 2 +- 34 files changed, 36 insertions(+), 1191 deletions(-) delete mode 100644 Mathlib/Data/MLList/Basic.lean delete mode 100644 Mathlib/Data/Nondet/Basic.lean delete mode 100644 Mathlib/Lean/Data/NameMap.lean delete mode 100644 Mathlib/Lean/IO/Process.lean delete mode 100644 Mathlib/Lean/SMap.lean delete mode 100644 Mathlib/Tactic/Backtrack.lean delete mode 100644 Mathlib/Tactic/SolveByElim.lean delete mode 100644 test/Nondet.lean diff --git a/ImportGraph/Main.lean b/ImportGraph/Main.lean index 0b86f35143303..4303bdd12b5b9 100644 --- a/ImportGraph/Main.lean +++ b/ImportGraph/Main.lean @@ -5,8 +5,8 @@ Authors: Scott Morrison -/ import Mathlib.Util.Imports import Mathlib.Lean.CoreM -import Mathlib.Lean.Data.NameMap -import Mathlib.Lean.IO.Process +import Std.Lean.NameMap +import Std.Lean.IO.Process import Mathlib.Lean.Name import Std.Lean.Util.Path import Cli diff --git a/Mathlib.lean b/Mathlib.lean index 0febcb1a2dc25..f2911594599ca 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1675,7 +1675,6 @@ import Mathlib.Data.List.Sym import Mathlib.Data.List.TFAE import Mathlib.Data.List.ToFinsupp import Mathlib.Data.List.Zip -import Mathlib.Data.MLList.Basic import Mathlib.Data.MLList.BestFirst import Mathlib.Data.MLList.Dedup import Mathlib.Data.MLList.DepthFirst @@ -1805,7 +1804,6 @@ import Mathlib.Data.Nat.Totient import Mathlib.Data.Nat.Units import Mathlib.Data.Nat.Upto import Mathlib.Data.Nat.WithBot -import Mathlib.Data.Nondet.Basic import Mathlib.Data.Num.Basic import Mathlib.Data.Num.Bitwise import Mathlib.Data.Num.Lemmas @@ -2312,7 +2310,6 @@ import Mathlib.Init.Quot import Mathlib.Init.Set import Mathlib.Init.ZeroOne import Mathlib.Lean.CoreM -import Mathlib.Lean.Data.NameMap import Mathlib.Lean.Elab.Tactic.Basic import Mathlib.Lean.Elab.Term import Mathlib.Lean.EnvExtension @@ -2322,7 +2319,6 @@ import Mathlib.Lean.Expr.Basic import Mathlib.Lean.Expr.ExtraRecognizers import Mathlib.Lean.Expr.ReplaceRec import Mathlib.Lean.Expr.Traverse -import Mathlib.Lean.IO.Process import Mathlib.Lean.Json import Mathlib.Lean.LocalContext import Mathlib.Lean.Message @@ -2333,7 +2329,6 @@ import Mathlib.Lean.Meta.DiscrTree import Mathlib.Lean.Meta.Simp import Mathlib.Lean.Name import Mathlib.Lean.PrettyPrinter.Delaborator -import Mathlib.Lean.SMap import Mathlib.Lean.Thunk import Mathlib.LinearAlgebra.AdicCompletion import Mathlib.LinearAlgebra.AffineSpace.AffineEquiv @@ -3267,7 +3262,6 @@ import Mathlib.Tactic.ApplyFun import Mathlib.Tactic.ApplyWith import Mathlib.Tactic.Attr.Core import Mathlib.Tactic.Attr.Register -import Mathlib.Tactic.Backtrack import Mathlib.Tactic.Basic import Mathlib.Tactic.ByContra import Mathlib.Tactic.CancelDenoms @@ -3416,7 +3410,6 @@ import Mathlib.Tactic.SimpRw import Mathlib.Tactic.Simps.Basic import Mathlib.Tactic.Simps.NotationClass import Mathlib.Tactic.SlimCheck -import Mathlib.Tactic.SolveByElim import Mathlib.Tactic.SplitIfs import Mathlib.Tactic.Spread import Mathlib.Tactic.Substs diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean b/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean index 60e16e7d3946b..8c9291700e31f 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/Approximations.lean @@ -6,7 +6,7 @@ Authors: Kevin Kappelmann import Mathlib.Algebra.ContinuedFractions.Computation.CorrectnessTerminating import Mathlib.Data.Nat.Fib.Basic import Mathlib.Tactic.Monotonicity -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim #align_import algebra.continued_fractions.computation.approximations from "leanprover-community/mathlib"@"a7e36e48519ab281320c4d192da6a7b348ce40ad" diff --git a/Mathlib/Computability/PartrecCode.lean b/Mathlib/Computability/PartrecCode.lean index 9207729655b42..a729b0bdfeb41 100644 --- a/Mathlib/Computability/PartrecCode.lean +++ b/Mathlib/Computability/PartrecCode.lean @@ -812,7 +812,8 @@ theorem evaln_mono : ∀ {k₁ k₂ c n x}, k₁ ≤ k₂ → x ∈ evaln k₁ c · exact fun y h₁ h₂ => ⟨y, evaln_mono hl' h₁, hg _ _ h₂⟩ · -- rfind' cf simp? [Bind.bind] at h ⊢ says - simp only [unpaired, bind, pair_unpair, Option.mem_def, Option.bind_eq_some] at h ⊢ + simp only [unpaired, bind, pair_unpair, Option.pure_def, Option.mem_def, + Option.bind_eq_some] at h ⊢ refine' h.imp fun x => And.imp (hf _ _) _ by_cases x0 : x = 0 <;> simp [x0] exact evaln_mono hl' @@ -844,8 +845,7 @@ theorem evaln_sound : ∀ {k c n x}, x ∈ evaln k c n → x ∈ eval c n rcases h with ⟨m, h₁, h₂⟩ by_cases m0 : m = 0 <;> simp [m0] at h₂ · exact - ⟨0, ⟨by simpa [m0] using hf _ _ h₁, fun {m} => (Nat.not_lt_zero _).elim⟩, by - injection h₂ with h₂; simp [h₂]⟩ + ⟨0, ⟨by simpa [m0] using hf _ _ h₁, fun {m} => (Nat.not_lt_zero _).elim⟩, by simp [h₂]⟩ · have := evaln_sound h₂ simp [eval] at this rcases this with ⟨y, ⟨hy₁, hy₂⟩, rfl⟩ @@ -908,7 +908,7 @@ theorem evaln_complete {c n x} : x ∈ eval c n ↔ ∃ k, x ∈ evaln k c n := induction' y with y IH generalizing m <;> simp [evaln, Bind.bind] · simp at hy₁ rcases hf hy₁ with ⟨k, hk⟩ - exact ⟨_, Nat.le_of_lt_succ <| evaln_bound hk, _, hk, by simp; rfl⟩ + exact ⟨_, Nat.le_of_lt_succ <| evaln_bound hk, _, hk, by simp⟩ · rcases hy₂ (Nat.succ_pos _) with ⟨a, ha, a0⟩ rcases hf ha with ⟨k₁, hk₁⟩ rcases IH m.succ (by simpa [Nat.succ_eq_add_one, add_comm, add_left_comm] using hy₁) diff --git a/Mathlib/Data/MLList/Basic.lean b/Mathlib/Data/MLList/Basic.lean deleted file mode 100644 index ba99a7d84eb18..0000000000000 --- a/Mathlib/Data/MLList/Basic.lean +++ /dev/null @@ -1,26 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Std.Data.MLList.Basic - -/-! -# Basic operations on `MLList` - -These functions can be upstreamed to Std when convenient. --/ - -set_option autoImplicit true - -namespace MLList - -/-- Construct a singleton monadic lazy list from a single monadic value. -/ -def singletonM [Monad m] (x : m α) : MLList m α := - .squash fun _ => do return .cons (← x) .nil - -/-- Construct a singleton monadic lazy list from a single value. -/ -def singleton [Monad m] (x : α) : MLList m α := - .singletonM (pure x) - -end MLList diff --git a/Mathlib/Data/Nat/PSub.lean b/Mathlib/Data/Nat/PSub.lean index 2b2703d1c722b..d57e17bc20e07 100644 --- a/Mathlib/Data/Nat/PSub.lean +++ b/Mathlib/Data/Nat/PSub.lean @@ -107,9 +107,9 @@ theorem psub_eq_sub {m n} (h : n ≤ m) : psub m n = some (m - n) := -- Porting note: we only have the simp lemma `Option.bind_some` which uses `Option.bind` not `>>=` theorem psub_add (m n k) : psub m (n + k) = (do psub (← psub m n) k) := by - induction k - simp only [zero_eq, add_zero, psub_zero, Option.bind_eq_bind, Option.bind_some] - simp [*, Nat.add_succ] + induction k with + | zero => simp only [zero_eq, add_zero, psub_zero, Option.bind_eq_bind, Option.bind_some] + | succ n ih => simp only [ih, add_succ, psub_succ, bind_assoc] #align nat.psub_add Nat.psub_add /-- Same as `psub`, but with a more efficient implementation. -/ diff --git a/Mathlib/Data/Nondet/Basic.lean b/Mathlib/Data/Nondet/Basic.lean deleted file mode 100644 index 9c70c25b182c5..0000000000000 --- a/Mathlib/Data/Nondet/Basic.lean +++ /dev/null @@ -1,206 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Std.Tactic.Lint -import Std.Data.MLList.Basic -import Mathlib.Data.MLList.Basic - -/-! -# A nondeterminism monad. - -We represent nondeterministic values in a type `α` as a single field structure containing an -`MLList m (σ × α)`, i.e. as a monadic lazy list of possible values, -each equipped with the backtrackable state -required to run further computations in the ambient monad. - -We provide an `Alternative` `Monad` instance, as well as functions `bind`, `mapM`, and `filterMapM`, -and functions `singletonM`, `ofListM`, `ofOptionM`, and `firstM` -for entering and leaving the nondeterministic world. - -Operations on the nondeterministic value via `bind`, `mapM`, and `filterMapM` -run with the appropriate backtrackable state, and are responsible for updating the state themselves -(typically this doesn't need to be done explicitly, -but just happens as a side effect in the monad `m`). --/ - -set_option autoImplicit true - -open Lean - -/-- -`Nondet m α` is variation on `MLList m α` suitable for use with backtrackable monads `m`. - -We think of `Nondet m α` as a nondeterministic value in `α`, -with the possible alternatives stored in a monadic lazy list. - -Along with each `a : α` we store the backtrackable state, and ensure that monadic operations -on alternatives run with the appropriate state. - -Operations on the nondeterministic value via `bind`, `mapM`, and `filterMapM` -run with the appropriate backtrackable state, and are responsible for updating the state themselves -(typically this doesn't need to be done explicitly, -but just happens as a side effect in the monad `m`). --/ -@[nolint unusedArguments] -structure Nondet (m : Type → Type) [MonadBacktrack σ m] (α : Type) : Type where - /-- - Convert a non-deterministic value into a lazy list, keeping the backtrackable state. - Be careful that monadic operations on the `MLList` will not respect this state! - -/ - toMLList : MLList m (α × σ) - -namespace Nondet - -variable {m : Type → Type} [Monad m] [MonadBacktrack σ m] - -/-- The empty nondeterministic value. -/ -def nil : Nondet m α := .mk .nil - -instance : Inhabited (Nondet m α) := ⟨.nil⟩ - -/-- -Squash a monadic nondeterministic value to a nondeterministic value. --/ -def squash (L : Unit → m (Nondet m α)) : Nondet m α := - .mk <| MLList.squash fun _ => return (← L ()).toMLList - -/-- -Bind a nondeterministic function over a nondeterministic value, -ensuring the function is run with the relevant backtrackable state at each value. --/ -partial def bind (L : Nondet m α) (f : α → Nondet m β) : Nondet m β := .squash fun _ => do - match ← L.toMLList.uncons with - | none => pure .nil - | some (⟨x, s⟩, xs) => do - let r := (Nondet.mk xs).bind f - restoreState s - match ← (f x).toMLList.uncons with - | none => return r - | some (y, ys) => return .mk <| .cons y (ys.append (fun _ => r.toMLList)) - -/-- Convert any value in the monad to the singleton nondeterministic value. -/ -def singletonM (x : m α) : Nondet m α := - .mk <| .singletonM do - let a ← x - return (a, ← saveState) - -/-- Convert a value to the singleton nondeterministic value. -/ -def singleton (x : α) : Nondet m α := singletonM (pure x) - -/-- `Nondet m` is a monad. -/ -instance : Monad (Nondet m) where - pure a := singletonM (pure a) - bind := bind - -/-- `Nondet m` is an alternative monad. -/ -instance : Alternative (Nondet m) where - failure := .nil - orElse x y := .mk <| x.toMLList.append fun _ => (y ()).toMLList - -instance : MonadLift m (Nondet m) where - monadLift := singletonM - -/-- -Lift a list of monadic values to a nondeterministic value. -We ensure that each monadic value is evaluated with the same backtrackable state. --/ -def ofListM (L : List (m α)) : Nondet m α := - .squash fun _ => do - let s ← saveState - return .mk <| MLList.ofListM <| L.map fun x => do - restoreState s - let a ← x - pure (a, ← saveState) - -/-- -Lift a list of values to a nondeterministic value. -(The backtrackable state in each will be identical: -whatever the state was when we first read from the result.) --/ -def ofList (L : List α) : Nondet m α := ofListM (L.map pure) - -/-- Apply a function which returns values in the monad to every alternative of a `Nondet m α`. -/ -partial def mapM (f : α → m β) (L : Nondet m α) : Nondet m β := - L.bind fun a => singletonM (f a) - -/-- Apply a function to each alternative in a `Nondet m α` . -/ -def map (f : α → β) (L : Nondet m α) : Nondet m β := - L.mapM fun a => pure (f a) - -/-- Convert a monadic optional value to a nondeterministic value. -/ -def ofOptionM (x : m (Option α)) : Nondet m α := .squash fun _ => do - match ← x with - | none => return .nil - | some a => return singleton a - -/-- Convert an optional value to a nondeterministic value. -/ -def ofOption (x : Option α) : Nondet m α := ofOptionM (pure x) - -/-- Filter and map a nondeterministic value using a monadic function which may return `none`. -/ -partial def filterMapM (f : α → m (Option β)) (L : Nondet m α) : Nondet m β := - L.bind fun a => ofOptionM (f a) - -/-- Filter and map a nondeterministic value. -/ -def filterMap (f : α → Option β) (L : Nondet m α) : Nondet m β := - L.filterMapM fun a => pure (f a) - -/-- Filter a nondeterministic value using a monadic predicate. -/ -partial def filterM (p : α → m (ULift Bool)) (L : Nondet m α) : Nondet m α := - L.filterMapM fun a => do - if (← p a).down then - pure (some a) - else - pure none - -/-- Filter a nondeterministic value. -/ -def filter (p : α → Bool) (L : Nondet m α) : Nondet m α := - L.filterM fun a => pure <| .up (p a) - -/-- -All iterations of a non-deterministic function on an initial value. - -(That is, depth first search.) --/ -partial def iterate (f : α → Nondet m α) (a : α) : Nondet m α := - singleton a <|> (f a).bind (iterate f) - -/-- -Find the first alternative in a nondeterministic value, as a monadic value. --/ -def head [Alternative m] (L : Nondet m α) : m α := do - let (x, s) ← L.toMLList.head - restoreState s - return x - -/-- -Find the value of a monadic function on the first alternative in a nondeterministic value -where the function succeeds. --/ -def firstM [Alternative m] (L : Nondet m α) (f : α → m (Option β)) : m β := - L.filterMapM f |>.head - -/-- -Convert a non-deterministic value into a lazy list, by discarding the backtrackable state. --/ -def toMLList' (L : Nondet m α) : MLList m α := L.toMLList.map (·.1) - -/-- -Convert a non-deterministic value into a list in the monad, retaining the backtrackable state. --/ -def toList (L : Nondet m α) : m (List (α × σ)) := L.toMLList.force - -/-- -Convert a non-deterministic value into a list in the monad, by discarding the backtrackable state. --/ -def toList' (L : Nondet m α) : m (List α) := L.toMLList.map (·.1) |>.force - -end Nondet - -/-- The `Id` monad is trivially backtrackable, with state `Unit`. -/ --- This is useful so we can use `Nondet Id α` instead of `List α` --- as the basic non-determinism monad. -instance : MonadBacktrack Unit Id where - saveState := pure () - restoreState _ := pure () diff --git a/Mathlib/Data/Option/Basic.lean b/Mathlib/Data/Option/Basic.lean index c9609459f7871..aaef9ead0161c 100644 --- a/Mathlib/Data/Option/Basic.lean +++ b/Mathlib/Data/Option/Basic.lean @@ -103,18 +103,15 @@ theorem bind_eq_some' {x : Option α} {f : α → Option β} {b : β} : by cases x <;> simp #align option.bind_eq_some' Option.bind_eq_some' -theorem bind_eq_none' {o : Option α} {f : α → Option β} : - o.bind f = none ↔ ∀ b a, a ∈ o → b ∉ f a := by - simp only [eq_none_iff_forall_not_mem, mem_def, bind_eq_some, not_exists, not_and] #align option.bind_eq_none' Option.bind_eq_none' theorem joinM_eq_join : joinM = @join α := funext fun _ ↦ rfl #align option.join_eq_join Option.joinM_eq_join -theorem bind_eq_bind {α β : Type u} {f : α → Option β} {x : Option α} : x >>= f = x.bind f := +theorem bind_eq_bind' {α β : Type u} {f : α → Option β} {x : Option α} : x >>= f = x.bind f := rfl -#align option.bind_eq_bind Option.bind_eq_bind +#align option.bind_eq_bind Option.bind_eq_bind' theorem map_coe {α β} {a : α} {f : α → β} : f <$> (a : Option α) = ↑(f a) := rfl @@ -328,7 +325,7 @@ theorem getD_default_eq_iget [Inhabited α] (o : Option α) : @[simp] theorem guard_eq_some' {p : Prop} [Decidable p] (u) : _root_.guard p = some u ↔ p := by cases u - by_cases h : p <;> simp [_root_.guard, h]; rfl + by_cases h : p <;> simp [_root_.guard, h] #align option.guard_eq_some' Option.guard_eq_some' theorem liftOrGet_choice {f : α → α → α} (h : ∀ a b, f a b = a ∨ f a b = b) : diff --git a/Mathlib/Data/Set/Enumerate.lean b/Mathlib/Data/Set/Enumerate.lean index c41c89c9a0da6..a986eca94ee95 100644 --- a/Mathlib/Data/Set/Enumerate.lean +++ b/Mathlib/Data/Set/Enumerate.lean @@ -40,7 +40,7 @@ def enumerate : Set α → ℕ → Option α theorem enumerate_eq_none_of_sel {s : Set α} (h : sel s = none) : ∀ {n}, enumerate sel s n = none | 0 => by simp [h, enumerate] - | n + 1 => by simp [h, enumerate]; rfl + | n + 1 => by simp [h, enumerate] #align set.enumerate_eq_none_of_sel Set.enumerate_eq_none_of_sel theorem enumerate_eq_none : @@ -52,7 +52,9 @@ theorem enumerate_eq_none : · cases m with | zero => contradiction | succ m' => - simp? [hs, enumerate] at h ⊢ says simp only [enumerate, hs, Nat.add_eq, add_zero] at h ⊢ + simp? [hs, enumerate] at h ⊢ says + simp only [enumerate, hs, Nat.add_eq, add_zero, Option.bind_eq_bind, + Option.some_bind] at h ⊢ have hm : n ≤ m' := Nat.le_of_succ_le_succ hm exact enumerate_eq_none h hm #align set.enumerate_eq_none Set.enumerate_eq_none diff --git a/Mathlib/Lean/Data/NameMap.lean b/Mathlib/Lean/Data/NameMap.lean deleted file mode 100644 index 1d16e6c8ba4e9..0000000000000 --- a/Mathlib/Lean/Data/NameMap.lean +++ /dev/null @@ -1,44 +0,0 @@ -/- -Copyright (c) 2023 Jon Eugster. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jon Eugster --/ -import Lean.Data.NameMap -import Std.Data.RBMap.Basic - -/-! -# Additional functions on `Lean.NameMap`. - -We provide `NameMap.filter` and `NameMap.filterMap`. --/ - -set_option autoImplicit true - -namespace Lean.NameMap - -instance : ForIn m (NameMap β) (Name × β) := - inferInstanceAs <| ForIn m (RBMap Name β _) _ - -/-- -`filter f m` returns the `NameMap` consisting of all -"`key`/`val`"-pairs in `m` where `f key val` returns `true`. --/ -def filter (f : Name → α → Bool) (m : NameMap α) : NameMap α := - m.fold process {} -where - process (r : NameMap α) (n : Name) (i : α) := - if f n i then r.insert n i else r - -/-- -`filterMap f m` allows to filter a `NameMap` and simultaneously modify the filtered values. - -It takes a function `f : Name → α → Option β` and applies `f name` to the value with key `name`. -The resulting entries with non-`none` value are collected to form the output `NameMap`. --/ -def filterMap (f : Name → α → Option β) (m : NameMap α) : NameMap β := - m.fold process {} -where - process (r : NameMap β) (n : Name) (i : α) := - match f n i with - | none => r - | some b => r.insert n b diff --git a/Mathlib/Lean/IO/Process.lean b/Mathlib/Lean/IO/Process.lean deleted file mode 100644 index 6e9def8620754..0000000000000 --- a/Mathlib/Lean/IO/Process.lean +++ /dev/null @@ -1,43 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ - -/-! -# Running external commands. --/ - -namespace IO.Process - -open System (FilePath) - -/-- -Pipe `input` into stdin of the spawned process, -then return `(exitCode, stdout, stdErr)` upon completion. --/ --- TODO We could reduce some code duplication by centralising some functions like this, --- which are used here, in `cache`, and in https://github.com/leanprover-community/llm. -def runCmdWithInput' (cmd : String) (args : Array String) - (input : String := "") (throwFailure := true) : IO (UInt32 × String × String) := do - let child ← spawn - { cmd := cmd, args := args, stdin := .piped, stdout := .piped, stderr := .piped } - let (stdin, child) ← child.takeStdin - stdin.putStr input - stdin.flush - let stdout ← IO.asTask child.stdout.readToEnd Task.Priority.dedicated - let err ← child.stderr.readToEnd - let exitCode ← child.wait - if exitCode != 0 && throwFailure then - throw $ IO.userError err - else - let out ← IO.ofExcept stdout.get - return (exitCode, out, err) - -/-- -Pipe `input` into stdin of the spawned process, -then return the entire content of stdout as a `String` upon completion. --/ -def runCmdWithInput (cmd : String) (args : Array String) - (input : String := "") (throwFailure := true) : IO String := do - return (← runCmdWithInput' cmd args input throwFailure).2.1 diff --git a/Mathlib/Lean/Meta.lean b/Mathlib/Lean/Meta.lean index 606f13de63ee4..1e2f89dca7792 100644 --- a/Mathlib/Lean/Meta.lean +++ b/Mathlib/Lean/Meta.lean @@ -17,16 +17,6 @@ open Lean Meta namespace Lean.MVarId -/-- Solve a goal by synthesizing an instance. -/ --- FIXME: probably can just be `g.inferInstance` once lean4#2054 is fixed -def synthInstance (g : MVarId) : MetaM Unit := do - g.assign (← Lean.Meta.synthInstance (← g.getType)) - -/-- Add the hypothesis `h : t`, given `v : t`, and return the new `FVarId`. -/ -def note (g : MVarId) (h : Name) (v : Expr) (t : Option Expr := .none) : - MetaM (FVarId × MVarId) := do - (← g.assert h (← t.getDM (inferType v)) v).intro1P - /-- Add the hypothesis `h : t`, given `v : t`, and return the new `FVarId`. -/ def «let» (g : MVarId) (h : Name) (v : Expr) (t : Option Expr := .none) : MetaM (FVarId × MVarId) := do diff --git a/Mathlib/Lean/Name.lean b/Mathlib/Lean/Name.lean index ee2cf29cee6b7..f91356d298801 100644 --- a/Mathlib/Lean/Name.lean +++ b/Mathlib/Lean/Name.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ import Std.Data.HashMap.Basic -import Mathlib.Lean.SMap +import Std.Lean.SMap import Mathlib.Lean.Expr.Basic /-! diff --git a/Mathlib/Lean/SMap.lean b/Mathlib/Lean/SMap.lean deleted file mode 100644 index 44a660e2e0102..0000000000000 --- a/Mathlib/Lean/SMap.lean +++ /dev/null @@ -1,17 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Lean.Data.SMap - -/-! -# Extra functions on Lean.SMap --/ - -set_option autoImplicit true - -/-- Monadic fold over a staged map. -/ -def Lean.SMap.foldM {m : Type w → Type w} [Monad m] [BEq α] [Hashable α] - (f : σ → α → β → m σ) (init : σ) (map : SMap α β) : m σ := do - map.map₂.foldlM f (← map.map₁.foldM f init) diff --git a/Mathlib/Mathport/Syntax.lean b/Mathlib/Mathport/Syntax.lean index 5350b7be4816f..84b71343007e6 100644 --- a/Mathlib/Mathport/Syntax.lean +++ b/Mathlib/Mathport/Syntax.lean @@ -82,7 +82,6 @@ import Mathlib.Tactic.Set import Mathlib.Tactic.SimpIntro import Mathlib.Tactic.SimpRw import Mathlib.Tactic.Simps.Basic -import Mathlib.Tactic.SolveByElim import Mathlib.Tactic.SplitIfs import Mathlib.Tactic.Substs import Mathlib.Tactic.SwapVar diff --git a/Mathlib/Tactic.lean b/Mathlib/Tactic.lean index 3449074553a7a..19af921d915fd 100644 --- a/Mathlib/Tactic.lean +++ b/Mathlib/Tactic.lean @@ -5,7 +5,6 @@ import Mathlib.Tactic.ApplyFun import Mathlib.Tactic.ApplyWith import Mathlib.Tactic.Attr.Core import Mathlib.Tactic.Attr.Register -import Mathlib.Tactic.Backtrack import Mathlib.Tactic.Basic import Mathlib.Tactic.ByContra import Mathlib.Tactic.CancelDenoms @@ -154,7 +153,6 @@ import Mathlib.Tactic.SimpRw import Mathlib.Tactic.Simps.Basic import Mathlib.Tactic.Simps.NotationClass import Mathlib.Tactic.SlimCheck -import Mathlib.Tactic.SolveByElim import Mathlib.Tactic.SplitIfs import Mathlib.Tactic.Spread import Mathlib.Tactic.Substs diff --git a/Mathlib/Tactic/Backtrack.lean b/Mathlib/Tactic/Backtrack.lean deleted file mode 100644 index 6df4ee47a4380..0000000000000 --- a/Mathlib/Tactic/Backtrack.lean +++ /dev/null @@ -1,198 +0,0 @@ -/- -Copyright (c) 2023 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Lean.Meta.Basic -import Mathlib.Data.Nondet.Basic -import Lean.Meta.Tactic.Util -import Std.Data.List.Basic -import Mathlib.Lean.Meta - -/-! -# `backtrack` - -A meta-tactic for running backtracking search, given a non-deterministic tactic -`alternatives : MVarId → Nondet MetaM (List MVarId)`. - -`backtrack alternatives goals` will recursively try to solve all goals in `goals`, -and the subgoals generated, backtracking as necessary. - -In its default behaviour, it will either solve all goals, or fail. -A customisable `suspend` hook in `BacktrackConfig` allows suspend a goal (or subgoal), -so that it will be returned instead of processed further. -Other hooks `proc` and `discharge` (described in `BacktrackConfig`) allow running other -tactics before `alternatives`, or if all search branches from a given goal fail. - -Currently only `solveByElim` is implemented in terms of `backtrack`. --/ - -set_option autoImplicit true - -open Lean Meta - -/-- Visualize an `Except` using a checkmark or a cross. -/ -def Except.emoji : Except ε α → String - | .error _ => crossEmoji - | .ok _ => checkEmoji - -/-- Run a monadic function on every element of a list, -returning the list of elements on which the function fails, and the list of successful results. -/ -def List.tryAllM [Monad m] [Alternative m] (L : List α) (f : α → m β) : m (List α × List β) := do - let R ← L.mapM (fun a => (Sum.inr <$> f a) <|> (pure (Sum.inl a))) - return (R.filterMap (fun s => match s with | .inl a => a | _ => none), - R.filterMap (fun s => match s with | .inr b => b | _ => none)) - -namespace Mathlib.Tactic - -/-- -Configuration structure to control the behaviour of `backtrack`: -* control the maximum depth and behaviour (fail or return subgoals) at the maximum depth, -* and hooks allowing - * modifying intermediate goals before running the external tactic, - * 'suspending' goals, returning them in the result, and - * discharging subgoals if the external tactic fails. --/ -structure BacktrackConfig where - /-- Maximum recursion depth. -/ - maxDepth : Nat := 6 - /-- An arbitrary procedure which can be used to modify the list of goals - before each attempt to generate alternatives. - Called as `proc goals curr`, where `goals` are the original goals for `backtracking`, - and `curr` are the current goals. - Returning `some l` will replace the current goals with `l` and recurse - (consuming one step of maximum depth). - Returning `none` will proceed to generating alternative without changing goals. - Failure will cause backtracking. - (defaults to `none`) -/ - proc : List MVarId → List MVarId → MetaM (Option (List MVarId)) := fun _ _ => pure none - /-- If `suspend g`, then we do not consider alternatives for `g`, - but return `g` as a new subgoal. (defaults to `false`) -/ - suspend : MVarId → MetaM Bool := fun _ => pure false - /-- `discharge g` is called on goals for which there were no alternatives. - If `none` we return `g` as a new subgoal. - If `some l`, we replace `g` by `l` in the list of active goals, and recurse. - If failure, we backtrack. (defaults to failure) -/ - discharge : MVarId → MetaM (Option (List MVarId)) := fun _ => failure - /-- - If we solve any "independent" goals, don't fail. - See `Lean.MVarId.independent?` for the definition of independence. - -/ - commitIndependentGoals : Bool := false - -/-- -Attempts to solve the `goals`, by recursively calling `alternatives g` on each subgoal that appears. -`alternatives` returns a nondeterministic list of new subgoals generated from a goal. - -`backtrack` performs a backtracking search, attempting to close all subgoals. - -Further flow control options are available via the `Config` argument. - -Returns a list of subgoals which were "suspended" via the `suspend` or `discharge` hooks -in `Config`. In the default configuration, `backtrack` will either return an empty list or fail. --/ -partial def backtrack (cfg : BacktrackConfig := {}) (trace : Name := .anonymous) - (alternatives : MVarId → Nondet MetaM (List MVarId)) - (goals : List MVarId) : MetaM (List MVarId) := do - processIndependentGoals goals goals -where - /-- - * `n : Nat` steps remaining. - * `curr : List MVarId` the current list of unsolved goals. - * `acc : List MVarId` a list of "suspended" goals, which will be returned as subgoals. - -/ - -- `acc` is intentionally a `List` rather than an `Array` so we can share across branches. - run (n : Nat) (curr acc : List MVarId) : MetaM (List MVarId) := do - match n with - | 0 => do - -- We're out of fuel. - throwError "backtrack exceeded the recursion limit" - | n + 1 => do - -- First, run `cfg.proc`, to see if it wants to modify the goals. - let procResult? ← try - cfg.proc goals curr - catch e => - withTraceNode trace - (return m!"{·.emoji} BacktrackConfig.proc failed: {e.toMessageData}") do - throw e - match procResult? with - | some curr' => run n curr' acc - | none => - match curr with - -- If there are no active goals, return the accumulated goals. - | [] => withTraceNode trace (return m!"{·.emoji} success!") do - return acc.reverse - | g :: gs => - -- Discard any goals which have already been assigned. - if ← g.isAssigned then - withTraceNode trace (return m!"{·.emoji} discarding already assigned goal {g}") do - run (n+1) gs acc - else - withTraceNode trace - -- Note: the `addMessageContextFull` ensures we show the goal using the mvar context before - -- the `do` block below runs, potentially unifying mvars in the goal. - (return m!"{·.emoji} working on: {← addMessageContextFull g}") - do - -- Check if we should suspend the search here: - if (← cfg.suspend g) then - withTraceNode trace - (fun _ => return m!"⏸️ suspending search and returning as subgoal") do - run (n+1) gs (g :: acc) - else - try - -- We attempt to find an alternative, - -- for which all resulting sub-goals can be discharged using `run n`. - (alternatives g).firstM fun r => observing? do run n (r ++ gs) acc - catch _ => - -- No lemmas could be applied: - match (← cfg.discharge g) with - | none => (withTraceNode trace - (fun _ => return m!"⏭️ deemed acceptable, returning as subgoal") do - run (n+1) gs (g :: acc)) - | some l => (withTraceNode trace - (fun _ => return m!"⏬ discharger generated new subgoals") do - run n (l ++ gs) acc) - /-- - A wrapper around `run`, which works on "independent" goals separately first, - to reduce backtracking. - -/ - processIndependentGoals (goals remaining : List MVarId) : MetaM (List MVarId) := do - -- Partition the remaining goals into "independent" goals - -- (which should be solvable without affecting the solvability of other goals) - -- and all the others. - let (igs, ogs) ← remaining.partitionM (MVarId.isIndependentOf goals) - if igs.isEmpty then - -- If there are no independent goals, we solve all the goals together via backtracking search. - return (← run cfg.maxDepth remaining []) - else - withTraceNode trace - (fun _ => return m!"independent goals {← ppMVarIds igs}," - ++ m!" working on them before {← ppMVarIds ogs}") do - -- Invoke `run` on each of the independent goals separately, - -- gathering the subgoals on which `run` fails, - -- and the new subgoals generated from goals on which it is successful. - let (failed, newSubgoals') ← igs.tryAllM (fun g => run cfg.maxDepth [g] []) - let newSubgoals := newSubgoals'.join - withTraceNode trace - (fun _ => return m!"failed: {← ppMVarIds failed}, new: {← ppMVarIds newSubgoals}") do - -- Update the list of goals with respect to which we need to check independence. - let goals' := (← goals.filterM (fun g => do pure !(← g.isAssigned))) ++ newSubgoals - -- If `commitIndependentGoals` is `true`, we will return the new goals - -- regardless of whether we can make further progress on the other goals. - if cfg.commitIndependentGoals && !newSubgoals.isEmpty then - return newSubgoals ++ failed ++ (← (processIndependentGoals goals' ogs <|> pure ogs)) - else if !failed.isEmpty then - -- If `commitIndependentGoals` is `false`, and we failed on any of the independent goals, - -- then overall failure is inevitable so we can stop here. - failure - else - -- Finally, having solved this batch of independent goals, - -- recurse (potentially now finding new independent goals). - return newSubgoals ++ (← processIndependentGoals goals' ogs) - /-- - Pretty print a list of goals. - -/ - ppMVarIds (gs : List MVarId) : MetaM (List Format) := do - gs.mapM fun g => do ppExpr (← g.getType) - -end Mathlib.Tactic diff --git a/Mathlib/Tactic/Common.lean b/Mathlib/Tactic/Common.lean index 4ddcec5e60015..ab30a2a40e83e 100644 --- a/Mathlib/Tactic/Common.lean +++ b/Mathlib/Tactic/Common.lean @@ -84,7 +84,6 @@ import Mathlib.Tactic.Simps.Basic -- `Gen` / `Testable` / `Sampleable` instances for types should be out in the library, -- rather than the theory for those types being imported into `SlimCheck`. -- import Mathlib.Tactic.SlimCheck -import Mathlib.Tactic.SolveByElim import Mathlib.Tactic.SplitIfs import Mathlib.Tactic.Spread import Mathlib.Tactic.Substs diff --git a/Mathlib/Tactic/GCongr/Core.lean b/Mathlib/Tactic/GCongr/Core.lean index c15ad39a29fef..a6c652a454f4d 100644 --- a/Mathlib/Tactic/GCongr/Core.lean +++ b/Mathlib/Tactic/GCongr/Core.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Heather Macbeth -/ import Mathlib.Init.Order.Defs -import Mathlib.Tactic.Backtrack +import Std.Tactic.SolveByElim.Backtrack import Mathlib.Tactic.Core import Mathlib.Tactic.GCongr.ForwardAttr diff --git a/Mathlib/Tactic/Hint.lean b/Mathlib/Tactic/Hint.lean index 6461fd52698f4..b431488a371ee 100644 --- a/Mathlib/Tactic/Hint.lean +++ b/Mathlib/Tactic/Hint.lean @@ -5,7 +5,7 @@ Authors: Scott Morrison -/ import Std.Tactic.TryThis import Std.Linter.UnreachableTactic -import Mathlib.Data.Nondet.Basic +import Std.Control.Nondet.Basic import Mathlib.Tactic.FailIfNoProgress import Mathlib.Mathport.Rename diff --git a/Mathlib/Tactic/LibrarySearch.lean b/Mathlib/Tactic/LibrarySearch.lean index 3a99072021bb0..e149c32a3a862 100644 --- a/Mathlib/Tactic/LibrarySearch.lean +++ b/Mathlib/Tactic/LibrarySearch.lean @@ -5,9 +5,10 @@ Authors: Gabriel Ebner, Scott Morrison -/ import Std.Util.Pickle import Std.Util.Cache -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim import Std.Data.MLList.Heartbeats import Mathlib.Lean.Name +import Mathlib.Lean.Meta import Mathlib.Lean.Meta.DiscrTree /-! diff --git a/Mathlib/Tactic/Monotonicity/Basic.lean b/Mathlib/Tactic/Monotonicity/Basic.lean index 3127d1e9fcaf0..ac70011dbacfb 100644 --- a/Mathlib/Tactic/Monotonicity/Basic.lean +++ b/Mathlib/Tactic/Monotonicity/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon -/ import Mathlib.Tactic.Monotonicity.Attr -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim /-! # Monotonicity tactic @@ -24,7 +24,7 @@ for this in Lean 3 was `mono*`. Both `mono` and `mono*` implement this behavior -/ open Lean Elab Tactic Parser Tactic -open Mathlib Tactic SolveByElim +open Std Tactic SolveByElim namespace Mathlib.Tactic.Monotonicity diff --git a/Mathlib/Tactic/Nontriviality/Core.lean b/Mathlib/Tactic/Nontriviality/Core.lean index b1fed972e004c..be9673c4dc35f 100644 --- a/Mathlib/Tactic/Nontriviality/Core.lean +++ b/Mathlib/Tactic/Nontriviality/Core.lean @@ -6,14 +6,14 @@ Authors: Sébastien Gouëzel, Mario Carneiro import Qq.MetaM import Mathlib.Logic.Nontrivial.Basic import Mathlib.Tactic.Attr.Core -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim /-! # The `nontriviality` tactic. -/ set_option autoImplicit true namespace Mathlib.Tactic.Nontriviality -open Lean Elab Meta Tactic Qq +open Lean Elab Meta Tactic Qq Std.Tactic theorem subsingleton_or_nontrivial_elim {p : Prop} {α : Type u} (h₁ : Subsingleton α → p) (h₂ : Nontrivial α → p) : p := diff --git a/Mathlib/Tactic/Propose.lean b/Mathlib/Tactic/Propose.lean index b83a8a6427eaa..58c0782d84692 100644 --- a/Mathlib/Tactic/Propose.lean +++ b/Mathlib/Tactic/Propose.lean @@ -9,7 +9,7 @@ import Mathlib.Lean.Meta.Basic import Mathlib.Lean.Meta.DiscrTree import Std.Util.Cache import Mathlib.Tactic.Core -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim import Mathlib.Tactic.TryThis /-! diff --git a/Mathlib/Tactic/Relation/Symm.lean b/Mathlib/Tactic/Relation/Symm.lean index 328e31da47ed8..239d92ca4f703 100644 --- a/Mathlib/Tactic/Relation/Symm.lean +++ b/Mathlib/Tactic/Relation/Symm.lean @@ -8,42 +8,19 @@ import Std.Tactic.Relation.Symm import Lean.Elab.Tactic.Location /-! -# `symm_saturate` tactic +# `relSidesIfSymm?` -For every hypothesis `h : a ~ b` where a `@[symm]` lemma is available, -add a hypothesis `h_symm : b ~ a`. +This may now be orphaned code which can be removed. -/ set_option autoImplicit true open Lean Meta -namespace Lean.MVarId - -/-- For every hypothesis `h : a ~ b` where a `@[symm]` lemma is available, -add a hypothesis `h_symm : b ~ a`. -/ -def symmSaturate (g : MVarId) : MetaM MVarId := g.withContext do - let mut g' := g - let hyps ← getLocalHyps - let types ← hyps.mapM inferType - for h in hyps do try - let symm ← h.applySymm - let symmType ← inferType symm - if ¬ (← types.anyM (isDefEq symmType)) then - (_, g') ← g'.note ((← h.fvarId!.getUserName).appendAfter "_symm") symm - catch _ => g' ← pure g' - return g' - -end Lean.MVarId - namespace Mathlib.Tactic open Lean.Elab.Tactic Std.Tactic -/-- For every hypothesis `h : a ~ b` where a `@[symm]` lemma is available, -add a hypothesis `h_symm : b ~ a`. -/ -elab "symm_saturate" : tactic => liftMetaTactic1 fun g => g.symmSaturate - /-- If `e` is the form `@R .. x y`, where `R` is a symmetric relation, return `some (R, x, y)`. As a special case, if `e` is `@HEq α a β b`, return ``some (`HEq, a, b)``. -/ diff --git a/Mathlib/Tactic/Rewrites.lean b/Mathlib/Tactic/Rewrites.lean index 2f7371145e076..53e2b90786cfc 100644 --- a/Mathlib/Tactic/Rewrites.lean +++ b/Mathlib/Tactic/Rewrites.lean @@ -12,7 +12,7 @@ import Std.Util.Cache import Mathlib.Lean.Meta import Mathlib.Tactic.TryThis import Mathlib.Control.Basic -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim /-! # The `rewrites` tactic. diff --git a/Mathlib/Tactic/SolveByElim.lean b/Mathlib/Tactic/SolveByElim.lean deleted file mode 100644 index 6773bdfe6237c..0000000000000 --- a/Mathlib/Tactic/SolveByElim.lean +++ /dev/null @@ -1,501 +0,0 @@ -/- -Copyright (c) 2021 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison, David Renshaw --/ -import Mathlib.Tactic.Backtrack -import Mathlib.Tactic.Relation.Symm -import Lean.Meta.Tactic.Apply -import Std.Tactic.LabelAttr -import Std.Data.Sum.Basic - -/-! -# `solve_by_elim`, `apply_rules`, and `apply_assumption`. --/ - -open Lean Meta Elab Tactic -open Mathlib.Tactic - -initialize registerTraceClass `Meta.Tactic.solveByElim - -namespace Mathlib.Tactic.SolveByElim - -/-- -`applyTactics lemmas goal` will return a list of tactics, -corresponding to applying each one of the lemmas to the goal `goal`. - -Providing this to the `backtracking` tactic, -we can perform backtracking search based on applying a list of lemmas. - -``applyTactics (trace := `name)`` will construct trace nodes for ``name` indicating which -calls to `apply` succeeded or failed. --/ -def applyTactics (cfg : ApplyConfig := {}) (transparency : TransparencyMode := .default) - (lemmas : List Expr) (g : MVarId) : Nondet MetaM (List MVarId) := - (Nondet.ofList lemmas).filterMapM fun e => observing? do - withTraceNode `Meta.Tactic.solveByElim (return m!"{·.emoji} trying to apply: {e}") do - let goals ← withTransparency transparency (g.apply e cfg) - -- When we call `apply` interactively, `Lean.Elab.Tactic.evalApplyLikeTactic` - -- deals with closing new typeclass goals by calling - -- `Lean.Elab.Term.synthesizeSyntheticMVarsNoPostponing`. - -- It seems we can't reuse that machinery down here in `MetaM`, - -- so we just settle for trying to close each subgoal using `inferInstance`. - goals.filterM fun g => try g.inferInstance; pure false catch _ => pure true - -/-- -`applyFirst lemmas goal` applies the first of the `lemmas` -which can be successfully applied to `goal`, and fails if none apply. - -We use this in `apply_rules` and `apply_assumption` where backtracking is not needed. --/ -def applyFirst (cfg : ApplyConfig := {}) (transparency : TransparencyMode := .default) - (lemmas : List Expr) (g : MVarId) : MetaM (List MVarId) := - (applyTactics cfg transparency lemmas g).head - -/-- -Configuration structure to control the behaviour of `solve_by_elim`: -* transparency mode for calls to `apply` -* whether to use `symm` on hypotheses and `exfalso` on the goal as needed, -* see also `BacktrackConfig` for hooks allowing flow control. --/ -structure Config extends BacktrackConfig, ApplyConfig where - /-- Transparency mode for calls to `apply`. -/ - transparency : TransparencyMode := .default - /-- Also use symmetric versions (via `@[symm]`) of local hypotheses. -/ - symm : Bool := true - /-- Try proving the goal via `exfalso` if `solve_by_elim` otherwise fails. - This is only used when operating on a single goal. -/ - exfalso : Bool := true - backtracking : Bool := true - -instance : Coe Config BacktrackConfig := ⟨Config.toBacktrackConfig⟩ - -/-- The default `maxDepth` for `apply_rules` is higher. -/ -structure ApplyRulesConfig extends Config where - maxDepth := 50 - -/-- -Allow elaboration of `Config` arguments to tactics. --/ -declare_config_elab elabConfig Config - -/-- -Allow elaboration of `ApplyRulesConfig` arguments to tactics. --/ -declare_config_elab elabApplyRulesConfig ApplyRulesConfig - -/-! -These functions could be lifted up to `BacktrackConfig`, -but we'd still need to keep copies here. --/ -namespace Config - -/-- Create or modify a `Config` which allows a class of goals to be returned as subgoals. -/ -def accept (cfg : Config := {}) (test : MVarId → MetaM Bool) : Config := - { cfg with - discharge := fun g => do - if (← test g) then - pure none - else - cfg.discharge g } - -/-- -Create or modify a `Config` which runs a tactic on the main goal. -If that tactic fails, fall back to the `proc` behaviour of `cfg`. --/ -def mainGoalProc (cfg : Config := {}) (proc : MVarId → MetaM (List MVarId)) : Config := - { cfg with - proc := fun orig goals => match goals with - | [] => cfg.proc orig [] - | g :: gs => try - return (← proc g) ++ gs - catch _ => cfg.proc orig goals } - -/-- Create or modify a `Config` which calls `intro` on each goal before applying lemmas. -/ --- Because `SolveByElim` works on each goal in sequence, even though --- `mainGoalProc` only applies this operation on the main goal, --- it is applied to every goal before lemmas are applied. -def intros (cfg : Config := {}) : Config := - cfg.mainGoalProc fun g => do pure [(← g.intro1P).2] - -/-- Attempt typeclass inference on each goal, before applying lemmas. -/ --- Because `SolveByElim` works on each goal in sequence, even though --- `mainGoalProc` only applies this operation on the main goal, --- it is applied to every goal before lemmas are applied. -def synthInstance (cfg : Config := {}) : Config := - cfg.mainGoalProc fun g => do g.synthInstance; pure [] - -/-- Add a discharging tactic, falling back to the original discharging tactic if it fails. -Return `none` to return the goal as a new subgoal, or `some goals` to replace it. -/ -def withDischarge (cfg : Config := {}) (discharge : MVarId → MetaM (Option (List MVarId))) : - Config := - { cfg with - discharge := fun g => try discharge g - catch _ => cfg.discharge g } - -/-- Create or modify a `Config` which calls `intro` on any goal for which no lemma applies. -/ -def introsAfter (cfg : Config := {}) : Config := - cfg.withDischarge fun g => do pure [(← g.intro1P).2] - -/-- Create or modify a `Config` which -calls `synthInstance` on any goal for which no lemma applies. -/ -def synthInstanceAfter (cfg : Config := {}) : Config := - cfg.withDischarge fun g => do g.synthInstance; pure (some []) - -/-- -Create or modify a `Config` which rejects branches for which `test`, -applied to the instantiations of the original goals, fails or returns `false`. --/ -def testPartialSolutions (cfg : Config := {}) (test : List Expr → MetaM Bool) : Config := - { cfg with - proc := fun orig goals => do - let .true ← test (← orig.mapM fun m => m.withContext do instantiateMVars (.mvar m)) | failure - cfg.proc orig goals } - -/-- -Create or modify a `Config` which rejects complete solutions for which `test`, -applied to the instantiations of the original goals, fails or returns `false`. --/ -def testSolutions (cfg : Config := {}) (test : List Expr → MetaM Bool) : Config := - cfg.testPartialSolutions fun sols => do - if sols.any Expr.hasMVar then - pure true - else - test sols - -/-- -Create or modify a `Config` which only accept solutions -for which every expression in `use` appears as a subexpression. --/ -def requireUsingAll (cfg : Config := {}) (use : List Expr) : Config := - cfg.testSolutions fun sols => do - pure <| use.all fun e => sols.any fun s => e.occurs s - -end Config - -/-- -Elaborate a list of lemmas and local context. -See `mkAssumptionSet` for an explanation of why this is needed. --/ -def elabContextLemmas (g : MVarId) (lemmas : List (TermElabM Expr)) (ctx : TermElabM (List Expr)) : - MetaM (List Expr) := do - g.withContext (Elab.Term.TermElabM.run' do pure ((← ctx) ++ (← lemmas.mapM id))) - -/-- Returns the list of tactics corresponding to applying the available lemmas to the goal. -/ -def applyLemmas (cfg : Config) (lemmas : List (TermElabM Expr)) (ctx : TermElabM (List Expr)) - (g : MVarId) : Nondet MetaM (List MVarId) := Nondet.squash fun _ => do - -- We handle `cfg.symm` by saturating hypotheses of all goals using `symm`. - -- This has better performance that the mathlib3 approach. - let g ← if cfg.symm then g.symmSaturate else pure g - let es ← elabContextLemmas g lemmas ctx - return applyTactics cfg.toApplyConfig cfg.transparency es g - -/-- Applies the first possible lemma to the goal. -/ -def applyFirstLemma (cfg : Config) (lemmas : List (TermElabM Expr)) (ctx : TermElabM (List Expr)) - (g : MVarId) : MetaM (List MVarId) := do --- We handle `cfg.symm` by saturating hypotheses of all goals using `symm`. --- This has better performance that the mathlib3 approach. -let g ← if cfg.symm then g.symmSaturate else pure g -let es ← elabContextLemmas g lemmas ctx -applyFirst cfg.toApplyConfig cfg.transparency es g - -/-- -Solve a collection of goals by repeatedly applying lemmas, backtracking as necessary. - -Arguments: -* `cfg : Config` additional configuration options - (options for `apply`, maximum depth, and custom flow control) -* `lemmas : List (TermElabM Expr)` lemmas to apply. - These are thunks in `TermElabM` to avoid stuck metavariables. -* `ctx : TermElabM (List Expr)` monadic function returning the local hypotheses to use. -* `goals : List MVarId` the initial list of goals for `solveByElim` - -Returns a list of suspended goals, if it succeeded on all other subgoals. -By default `cfg.suspend` is `false,` `cfg.discharge` fails, and `cfg.failAtMaxDepth` is `true`, -and so the returned list is always empty. -Custom wrappers (e.g. `apply_assumption` and `apply_rules`) may modify this behaviour. --/ -def solveByElim (cfg : Config) (lemmas : List (TermElabM Expr)) (ctx : TermElabM (List Expr)) - (goals : List MVarId) : MetaM (List MVarId) := do - try - run goals - catch e => do - -- Implementation note: as with `cfg.symm`, this is different from the mathlib3 approach, - -- for (not as severe) performance reasons. - match goals, cfg.exfalso with - | [g], true => - withTraceNode `Meta.Tactic.solveByElim - (fun _ => return m!"⏮️ starting over using `exfalso`") do - run [← g.exfalso] - | _, _ => throw e -where - -- Run either backtracking search, or repeated application, on the list of goals. - run : List MVarId → MetaM (List MVarId) := if cfg.backtracking then - backtrack cfg `Meta.Tactic.solveByElim (applyLemmas cfg lemmas ctx) - else - repeat1' (maxIters := cfg.maxDepth) (applyFirstLemma cfg lemmas ctx) - -/-- -A `MetaM` analogue of the `apply_rules` user tactic. - -We pass the lemmas as `TermElabM Expr` rather than just `Expr`, -so they can be generated fresh for each application, to avoid stuck metavariables. - -By default it uses all local hypotheses, but you can disable this with `only := true`. -If you need to remove particular local hypotheses, call `solveByElim` directly. --/ -def _root_.Lean.MVarId.applyRules (cfg : Config) (lemmas : List (TermElabM Expr)) - (only : Bool := false) (g : MVarId) : MetaM (List MVarId) := do - let ctx : TermElabM (List Expr) := if only then pure [] else do pure (← getLocalHyps).toList - solveByElim { cfg with backtracking := false } lemmas ctx [g] - -open Lean.Parser.Tactic -open Std.Tactic.LabelAttr - -/-- -`mkAssumptionSet` builds a collection of lemmas for use in -the backtracking search in `solve_by_elim`. - -* By default, it includes all local hypotheses, along with `rfl`, `trivial`, `congrFun` - and `congrArg`. -* The flag `noDefaults` removes these. -* The flag `star` includes all local hypotheses, but not `rfl`, `trivial`, `congrFun`, - or `congrArg`. (It doesn't make sense to use `star` without `noDefaults`.) -* The argument `add` is the list of terms inside the square brackets that did not have `-` - and can be used to add expressions or local hypotheses -* The argument `remove` is the list of terms inside the square brackets that had a `-`, - and can be used to remove local hypotheses. - (It doesn't make sense to remove expressions which are not local hypotheses, - to remove local hypotheses unless `!noDefaults || star`, - and it does not make sense to use `star` unless you remove at least one local hypothesis.) - -`mkAssumptionSet` returns not a `List expr`, but a `List (TermElabM Expr) × TermElabM (List Expr)`. -There are two separate problems that need to be solved. - -### Stuck metavariables - -Lemmas with implicit arguments would be filled in with metavariables if we created the -`Expr` objects immediately, so instead we return thunks that generate the expressions -on demand. This is the first component, with type `List (TermElabM expr)`. - -As an example, we have `def rfl : ∀ {α : Sort u} {a : α}, a = a`, which on elaboration will become -`@rfl ?m_1 ?m_2`. - -Because `solve_by_elim` works by repeated application of lemmas against subgoals, -the first time such a lemma is successfully applied, -those metavariables will be unified, and thereafter have fixed values. -This would make it impossible to apply the lemma -a second time with different values of the metavariables. - -See https://github.com/leanprover-community/mathlib/issues/2269 - -### Relevant local hypotheses - -`solve_by_elim*` works with multiple goals, -and we need to use separate sets of local hypotheses for each goal. -The second component of the returned value provides these local hypotheses. -(Essentially using `local_context`, along with some filtering to remove hypotheses -that have been explicitly removed via `only` or `[-h]`.) - --/ --- These `TermElabM`s must be run inside a suitable `g.withContext`, --- usually using `elabContextLemmas`. -def mkAssumptionSet (noDefaults star : Bool) (add remove : List Term) (use : Array Ident) : - MetaM (List (TermElabM Expr) × TermElabM (List Expr)) := do - if star && !noDefaults then - throwError "It doesn't make sense to use `*` without `only`." - - let defaults : List (TermElabM Expr) := - [← `(rfl), ← `(trivial), ← `(congrFun), ← `(congrArg)].map elab' - let labelledLemmas := (← use.mapM (labelled ·.raw.getId)).flatten.toList - |>.map (liftM <| mkConstWithFreshMVarLevels ·) - let lemmas := if noDefaults then - add.map elab' ++ labelledLemmas - else - add.map elab' ++ labelledLemmas ++ defaults - - if !remove.isEmpty && noDefaults && !star then - throwError "It doesn't make sense to remove local hypotheses when using `only` without `*`." - let locals : TermElabM (List Expr) := if noDefaults && !star then do - pure [] - else do - pure <| (← getLocalHyps).toList.removeAll (← remove.mapM elab') - - return (lemmas, locals) - where - /-- Run `elabTerm`. -/ - elab' (t : Term) : TermElabM Expr := Elab.Term.elabTerm t.raw none - -/-- Syntax for omitting a local hypothesis in `solve_by_elim`. -/ -syntax erase := "-" term:max -/-- Syntax for including all local hypotheses in `solve_by_elim`. -/ -syntax star := "*" -/-- Syntax for adding or removing a term, or `*`, in `solve_by_elim`. -/ -syntax arg := star <|> erase <|> term -/-- Syntax for adding and removing terms in `solve_by_elim`. -/ -syntax args := " [" SolveByElim.arg,* "]" -/-- Syntax for using all lemmas labelled with an attribute in `solve_by_elim`. -/ -syntax using_ := " using " ident,* - -open Syntax - -/-- -Parse the lemma argument of a call to `solve_by_elim`. -The first component should be true if `*` appears at least once. -The second component should contain each term `t`in the arguments. -The third component should contain `t` for each `-t` in the arguments. --/ -def parseArgs (s : Option (TSyntax ``args)) : - Bool × List Term × List Term := - let args : Array (TSyntax ``arg) := match s with - | some s => match s with - | `(args| [$args,*]) => args.getElems - | _ => #[] - | none => #[] - let args : Array (Option (Term ⊕ Term)) := args.map fun t => match t with - | `(arg| $_:star) => none - | `(arg| - $t:term) => some (Sum.inr t) - | `(arg| $t:term) => some (Sum.inl t) - | _ => panic! "Unreachable parse of solve_by_elim arguments." - let args := args.toList - (args.contains none, - args.filterMap fun o => o.bind Sum.getLeft?, - args.filterMap fun o => o.bind Sum.getRight?) - -/-- Parse the `using ...` argument for `solve_by_elim`. -/ -def parseUsing (s : Option (TSyntax ``using_)) : Array Ident := - match s with - | some s => match s with - | `(using_ | using $ids,*) => ids.getElems - | _ => #[] - | none => #[] - -/-- -`solve_by_elim` calls `apply` on the main goal to find an assumption whose head matches -and then repeatedly calls `apply` on the generated subgoals until no subgoals remain, -performing at most `maxDepth` (defaults to 6) recursive steps. - -`solve_by_elim` discharges the current goal or fails. - -`solve_by_elim` performs backtracking if subgoals can not be solved. - -By default, the assumptions passed to `apply` are the local context, `rfl`, `trivial`, -`congrFun` and `congrArg`. - -The assumptions can be modified with similar syntax as for `simp`: -* `solve_by_elim [h₁, h₂, ..., hᵣ]` also applies the given expressions. -* `solve_by_elim only [h₁, h₂, ..., hᵣ]` does not include the local context, - `rfl`, `trivial`, `congrFun`, or `congrArg` unless they are explicitly included. -* `solve_by_elim [-h₁, ... -hₙ]` removes the given local hypotheses. -* `solve_by_elim using [a₁, ...]` uses all lemmas which have been labelled - with the attributes `aᵢ` (these attributes must be created using `register_label_attr`). - -`solve_by_elim*` tries to solve all goals together, using backtracking if a solution for one goal -makes other goals impossible. -(Adding or removing local hypotheses may not be well-behaved when starting with multiple goals.) - -Optional arguments passed via a configuration argument as `solve_by_elim (config := { ... })` -- `maxDepth`: number of attempts at discharging generated subgoals -- `symm`: adds all hypotheses derived by `symm` (defaults to `true`). -- `exfalso`: allow calling `exfalso` and trying again if `solve_by_elim` fails - (defaults to `true`). -- `transparency`: change the transparency mode when calling `apply`. Defaults to `.default`, - but it is often useful to change to `.reducible`, - so semireducible definitions will not be unfolded when trying to apply a lemma. - -See also the doc-comment for `Mathlib.Tactic.BacktrackConfig` for the options -`proc`, `suspend`, and `discharge` which allow further customization of `solve_by_elim`. -Both `apply_assumption` and `apply_rules` are implemented via these hooks. --/ -syntax (name := solveByElimSyntax) - "solve_by_elim" "*"? (config)? (&" only")? (args)? (using_)? : tactic - -/-- Wrapper for `solveByElim` that processes a list of `Term`s -that specify the lemmas to use. -/ -def solveByElim.processSyntax (cfg : Config := {}) (only star : Bool) (add remove : List Term) - (use : Array Ident) (goals : List MVarId) : MetaM (List MVarId) := do - if !remove.isEmpty && goals.length > 1 then - throwError "Removing local hypotheses is not supported when operating on multiple goals." - let ⟨lemmas, ctx⟩ ← mkAssumptionSet only star add remove use - solveByElim cfg lemmas ctx goals - -elab_rules : tactic | - `(tactic| solve_by_elim $[*%$s]? $[$cfg]? $[only%$o]? $[$t:args]? $[$use:using_]?) => do - let (star, add, remove) := parseArgs t - let use := parseUsing use - let goals ← if s.isSome then - getGoals - else - pure [← getMainGoal] - let cfg ← elabConfig (mkOptionalNode cfg) - let [] ← solveByElim.processSyntax cfg o.isSome star add remove use goals | - throwError "solve_by_elim unexpectedly returned subgoals" - pure () - -/-- -`apply_assumption` looks for an assumption of the form `... → ∀ _, ... → head` -where `head` matches the current goal. - -You can specify additional rules to apply using `apply_assumption [...]`. -By default `apply_assumption` will also try `rfl`, `trivial`, `congrFun`, and `congrArg`. -If you don't want these, or don't want to use all hypotheses, use `apply_assumption only [...]`. -You can use `apply_assumption [-h]` to omit a local hypothesis. -You can use `apply_assumption using [a₁, ...]` to use all lemmas which have been labelled -with the attributes `aᵢ` (these attributes must be created using `register_label_attr`). - -`apply_assumption` will use consequences of local hypotheses obtained via `symm`. - -If `apply_assumption` fails, it will call `exfalso` and try again. -Thus if there is an assumption of the form `P → ¬ Q`, the new tactic state -will have two goals, `P` and `Q`. - -You can pass a further configuration via the syntax `apply_rules (config := {...}) lemmas`. -The options supported are the same as for `solve_by_elim` (and include all the options for `apply`). --/ -syntax (name := applyAssumptionSyntax) - "apply_assumption" (config)? (&" only")? (args)? (using_)? : tactic - -elab_rules : tactic | - `(tactic| apply_assumption $[$cfg]? $[only%$o]? $[$t:args]? $[$use:using_]?) => do - let (star, add, remove) := parseArgs t - let use := parseUsing use - let cfg ← elabConfig (mkOptionalNode cfg) - let cfg := { cfg with - backtracking := false - maxDepth := 1 } - replaceMainGoal (← solveByElim.processSyntax cfg o.isSome star add remove use [← getMainGoal]) - -/-- -`apply_rules [l₁, l₂, ...]` tries to solve the main goal by iteratively -applying the list of lemmas `[l₁, l₂, ...]` or by applying a local hypothesis. -If `apply` generates new goals, `apply_rules` iteratively tries to solve those goals. -You can use `apply_rules [-h]` to omit a local hypothesis. - -`apply_rules` will also use `rfl`, `trivial`, `congrFun` and `congrArg`. -These can be disabled, as can local hypotheses, by using `apply_rules only [...]`. - -You can use `apply_rules using [a₁, ...]` to use all lemmas which have been labelled -with the attributes `aᵢ` (these attributes must be created using `register_label_attr`). - -You can pass a further configuration via the syntax `apply_rules (config := {...})`. -The options supported are the same as for `solve_by_elim` (and include all the options for `apply`). - -`apply_rules` will try calling `symm` on hypotheses and `exfalso` on the goal as needed. -This can be disabled with `apply_rules (config := {symm := false, exfalso := false})`. - -You can bound the iteration depth using the syntax `apply_rules (config := {maxDepth := n})`. - -Unlike `solve_by_elim`, `apply_rules` does not perform backtracking, and greedily applies -a lemma from the list until it gets stuck. --/ -syntax (name := applyRulesSyntax) "apply_rules" (config)? (&" only")? (args)? (using_)? : tactic - --- See also `Lean.MVarId.applyRules` for a `MetaM` level analogue of this tactic. -elab_rules : tactic | - `(tactic| apply_rules $[$cfg]? $[only%$o]? $[$t:args]? $[$use:using_]?) => do - let (star, add, remove) := parseArgs t - let use := parseUsing use - let cfg ← elabApplyRulesConfig (mkOptionalNode cfg) - let cfg := { cfg with - backtracking := false } - liftMetaTactic fun g => solveByElim.processSyntax cfg o.isSome star add remove use [g] diff --git a/Mathlib/Tactic/Tauto.lean b/Mathlib/Tactic/Tauto.lean index 88bde8ecc1ef6..e1bfd66bcd776 100644 --- a/Mathlib/Tactic/Tauto.lean +++ b/Mathlib/Tactic/Tauto.lean @@ -8,7 +8,7 @@ import Lean import Mathlib.Tactic.CasesM import Mathlib.Tactic.Classical import Mathlib.Tactic.Core -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim import Mathlib.Lean.Elab.Tactic.Basic import Mathlib.Logic.Basic import Qq diff --git a/Mathlib/Util/Imports.lean b/Mathlib/Util/Imports.lean index 146934733ce73..bd46a73ce3214 100644 --- a/Mathlib/Util/Imports.lean +++ b/Mathlib/Util/Imports.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ import Mathlib.Lean.Expr.Basic -import Mathlib.Lean.Data.NameMap +import Std.Lean.NameMap /-! diff --git a/lake-manifest.json b/lake-manifest.json index 5f36b7078600b..a3715f895d767 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "d8610e1bcb91c013c3d868821c0ef28bf693be07", + "rev": "0f6bc5b32bf5b0498902d3b5f0806c75530539d5", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", diff --git a/test/Nondet.lean b/test/Nondet.lean deleted file mode 100644 index c722ceaebd87a..0000000000000 --- a/test/Nondet.lean +++ /dev/null @@ -1,76 +0,0 @@ -import Mathlib.Data.Nondet.Basic -import Std.Tactic.GuardMsgs - -set_option autoImplicit true - -open Lean Meta - -def M := StateT (List Nat) MetaM - -deriving instance Monad for M -deriving instance Alternative for M - -instance : MonadBacktrack (List Nat) M where - saveState := StateT.get - restoreState := StateT.set - -def record (n : Nat) : M Unit := do - discard <| restoreState (n :: (← saveState)) - -def iotaM [Monad m] [Alternative m] [MonadBacktrack σ m] (n : Nat) : Nondet m Nat := - Nondet.ofList (List.iota n) - -/-- info: (52, []) -/ -#guard_msgs in -#eval show MetaM (Nat × List Nat) from StateT.run (iotaM 52 : Nondet M Nat).head [] - -/-- info: ((), [52]) -/ -#guard_msgs in -#eval show MetaM (Unit × List Nat) from StateT.run (((iotaM 52).mapM record).head) [] - -def x : Nondet M Nat := - (iotaM 52).filterMapM fun x => do - record x - if x % 7 = 0 then - return some (x^2) - else - return none - -/-- info: (2401, [49]) -/ -#guard_msgs in -#eval show MetaM (Nat × List Nat) from StateT.run x.head [] - -def divisors (n : Nat) : List Nat := List.iota (n - 1) |>.filter fun m => n % m = 0 -example : divisors 52 = [26, 13, 4, 2, 1] := rfl - -def divisorsM [Monad m] [MonadBacktrack σ m] (n : Nat) : Nondet m Nat := - Nondet.ofList (divisors n) - -/-- Take the numbers `32, ..., 1`, replace each with their divisors, then replace again. -/ -def y : Nondet M Nat := - (iotaM 32) - |>.bind fun x => do - record x - divisorsM x - |>.bind fun x => do - record x - divisorsM x - -/-- info: [8, 4, 2, 1, 4, 2, 1, 2, 1, 1, 5, 3, 1, 5, 2, 1, 3, 2, 1, 1, 1, 1, 7] -/ -#guard_msgs in -#eval show MetaM (List Nat) from StateT.run' (y.toMLList'.takeAsList 23) [] - --- All ways to find `4 ∣ a ∣ b`, with `b = 32, ..., 1`. -/-- info: ([(4, [16, 32]), (4, [8, 32]), (4, [12, 24]), (4, [8, 24]), (4, [8, 16])], [1]) -/ -#guard_msgs in -#eval show MetaM (List (Nat × List Nat) × List Nat) from - StateT.run (y.filter (· = 4)).toMLList.force [] - -/-- info: [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] -/ -#guard_msgs in -#eval (iotaM 15 : Nondet MetaM Nat).toList' - --- Depth first search of the divisors of 255. -/-- info: [255, 85, 17, 1, 5, 1, 1, 51, 17, 1, 3, 1, 1, 17, 1, 15, 5, 1, 3, 1, 1, 5, 1, 3, 1, 1] -/ -#guard_msgs in -#eval (Nondet.iterate divisorsM 255 : Nondet Id Nat).toList' diff --git a/test/apply_rules.lean b/test/apply_rules.lean index 0a1123d583c38..aa04f6d0f8d46 100644 --- a/test/apply_rules.lean +++ b/test/apply_rules.lean @@ -1,5 +1,5 @@ import Mathlib.Algebra.Order.Field.Basic -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim set_option autoImplicit true open Nat diff --git a/test/solve_by_elim/basic.lean b/test/solve_by_elim/basic.lean index 137b1d595ff52..04bcb4f6de36c 100644 --- a/test/solve_by_elim/basic.lean +++ b/test/solve_by_elim/basic.lean @@ -8,7 +8,7 @@ import Mathlib.Init.Logic import Std.Tactic.RCases import Mathlib.Tactic.Constructor import Std.Tactic.PermuteGoals -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim import Std.Test.Internal.DummyLabelAttr set_option autoImplicit true diff --git a/test/solve_by_elim/instances.lean b/test/solve_by_elim/instances.lean index 17f2822a870d9..c9633ea4d0c9b 100644 --- a/test/solve_by_elim/instances.lean +++ b/test/solve_by_elim/instances.lean @@ -5,7 +5,7 @@ Authors: Scott Morrison -/ import Mathlib.Algebra.GroupWithZero.Basic import Mathlib.Data.Nat.Order.Basic -import Mathlib.Tactic.SolveByElim +import Std.Tactic.SolveByElim lemma foo (a b : ℕ) (ha : a ≠ 0) (hb : b ≠ 0) : a * b ≠ 0 := by apply_rules [mul_ne_zero] From 2297cb1e9dac65b4f83b5ba470bc069e2d53d2bc Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Fri, 5 Jan 2024 01:23:51 +0000 Subject: [PATCH 332/353] fix: add beta reduction in BigOperator norm_num extensions (#9446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inserts a call to `Expr.betaRev` in the `cons` case of `evalFinsetBigop`. This prevents `norm_num` from getting stuck on a beta redex applied to a nat literal, as currently happens in the third example below: ```lean import Mathlib.Tactic.NormNum import Mathlib.Tactic.NormNum.BigOperators open BigOperators -- works example : (∑ i in Finset.range 10, (i^2 : ℕ)) = 285 := by norm_num1 -- also works (via the evalOfNat extension) example : (∑ i in Finset.range 10, (OfNat.ofNat i)) = 45 := by norm_num1 -- does not work example : (∑ i in Finset.range 10, i) = 45 := by norm_num1 ``` Also, adds a test and removes some unnecessary parens from neighboring tests. --- Mathlib/Tactic/NormNum/BigOperators.lean | 2 +- test/norm_num_ext.lean | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Mathlib/Tactic/NormNum/BigOperators.lean b/Mathlib/Tactic/NormNum/BigOperators.lean index 66c39458fe52b..a86608ae47dc3 100644 --- a/Mathlib/Tactic/NormNum/BigOperators.lean +++ b/Mathlib/Tactic/NormNum/BigOperators.lean @@ -341,7 +341,7 @@ partial def evalFinsetBigop {α : Q(Type u)} {β : Q(Type v)} match ← Finset.proveEmptyOrCons s with | .empty pf => pure <| res_empty.eq_trans q(congr_fun (congr_arg _ $pf) _) | .cons a s' h pf => do - let fa : Q($β) := Expr.app f a + let fa : Q($β) := Expr.betaRev f #[a] let res_fa ← derive fa let res_op_s' : Result q($op $s' $f) ← evalFinsetBigop op f res_empty @res_cons s' let res ← res_cons res_fa res_op_s' diff --git a/test/norm_num_ext.lean b/test/norm_num_ext.lean index 5221f544dad65..d1984619eb0de 100644 --- a/test/norm_num_ext.lean +++ b/test/norm_num_ext.lean @@ -376,8 +376,9 @@ example (f : ℕ → α) : ∑ i in {0, 1, 2}, f i = f 0 + f 1 + f 2 := by norm_ example (f : ℕ → α) : ∑ i in {0, 2, 2, 3, 1, 0}, f i = f 0 + f 1 + f 2 + f 3 := by norm_num; ring example (f : ℕ → α) : ∑ i in {0, 2, 2 - 3, 3 - 1, 1, 0}, f i = f 0 + f 1 + f 2 := by norm_num; ring -/ -example : (∑ i in Finset.range 10, (i^2 : ℕ)) = 285 := by norm_num1 -example : (∏ i in Finset.range 4, ((i+1)^2 : ℕ)) = 576 := by norm_num1 +example : ∑ i in Finset.range 10, i = 45 := by norm_num1 +example : ∑ i in Finset.range 10, (i^2 : ℕ) = 285 := by norm_num1 +example : ∏ i in Finset.range 4, ((i+1)^2 : ℕ) = 576 := by norm_num1 /- example : (∑ i in Finset.Icc 5 10, (i^2 : ℕ)) = 355 := by norm_num example : (∑ i in Finset.Ico 5 10, (i^2 : ℕ)) = 255 := by norm_num From cf7dace5515a411aa3f1b427d523040ce06b15d2 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 5 Jan 2024 02:29:28 +0000 Subject: [PATCH 333/353] chore: bump ProofWidgets to v0.0.25 (#9448) Co-authored-by: Scott Morrison --- lake-manifest.json | 4 ++-- lakefile.lean | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index a3715f895d767..13c561aed7980 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -31,10 +31,10 @@ {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, - "rev": "31d41415d5782a196999d4fd8eeaef3cae386a5f", + "rev": "8dd18350791c85c0fc9adbd6254c94a81d260d35", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.24", + "inputRev": "v0.0.25", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover/lean4-cli", diff --git a/lakefile.lean b/lakefile.lean index 40c372bfec165..db2b89928d405 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -29,7 +29,7 @@ require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" @ "main" require std from git "https://github.com/leanprover/std4" @ "main" require Qq from git "https://github.com/leanprover-community/quote4" @ "master" require aesop from git "https://github.com/leanprover-community/aesop" @ "master" -require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.24" +require proofwidgets from git "https://github.com/leanprover-community/ProofWidgets4" @ "v0.0.25" require Cli from git "https://github.com/leanprover/lean4-cli" @ "main" /-! From 26348e8e469e162d62a79517f657900ea9f2c1a6 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 5 Jan 2024 02:29:29 +0000 Subject: [PATCH 334/353] chore: remove unused `cases'` names (#9451) These unused names will soon acquire a linter warning. Easiest to clean them up pre-emptively. (Thanks to @nomeata for fixing these on `nightly-testing`.) Co-authored-by: Scott Morrison --- Mathlib/Data/FP/Basic.lean | 4 ++-- Mathlib/Data/List/MinMax.lean | 2 +- Mathlib/Data/PFunctor/Univariate/M.lean | 4 ++-- Mathlib/Data/QPF/Univariate/Basic.lean | 2 +- Mathlib/Logic/Encodable/Basic.lean | 2 +- Mathlib/Order/Estimator.lean | 2 +- Mathlib/Order/InitialSeg.lean | 2 +- Mathlib/RingTheory/Ideal/Norm.lean | 2 +- Mathlib/SetTheory/Ordinal/Notation.lean | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mathlib/Data/FP/Basic.lean b/Mathlib/Data/FP/Basic.lean index d1d2bb060cc8a..8bec271be9db9 100644 --- a/Mathlib/Data/FP/Basic.lean +++ b/Mathlib/Data/FP/Basic.lean @@ -147,10 +147,10 @@ def divNatLtTwoPow (n d : ℕ) : ℤ → Bool @[nolint docBlame] unsafe def ofPosRatDn (n : ℕ+) (d : ℕ+) : Float × Bool := by let e₁ : ℤ := n.1.size - d.1.size - prec - cases' h₁ : Int.shift2 d.1 n.1 (e₁ + prec) with d₁ n₁ + cases' Int.shift2 d.1 n.1 (e₁ + prec) with d₁ n₁ let e₂ := if n₁ < d₁ then e₁ - 1 else e₁ let e₃ := max e₂ emin - cases' h₂ : Int.shift2 d.1 n.1 (e₃ + prec) with d₂ n₂ + cases' Int.shift2 d.1 n.1 (e₃ + prec) with d₂ n₂ let r := mkRat n₂ d₂ let m := r.floor refine' (Float.finite Bool.false e₃ (Int.toNat m) _, r.den = 1) diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index b83e55c766e29..8989dbe286f68 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -346,7 +346,7 @@ variable [LinearOrder α] {l : List α} {a m : α} theorem maximum_concat (a : α) (l : List α) : maximum (l ++ [a]) = max (maximum l) a := by simp only [maximum, argmax_concat, id] - cases h : argmax id l + cases argmax id l · exact (max_eq_right bot_le).symm · simp [WithBot.some_eq_coe, max_def_lt, WithBot.coe_lt_coe] #align list.maximum_concat List.maximum_concat diff --git a/Mathlib/Data/PFunctor/Univariate/M.lean b/Mathlib/Data/PFunctor/Univariate/M.lean index 31072132ad0bc..b61c4dfa2c78f 100644 --- a/Mathlib/Data/PFunctor/Univariate/M.lean +++ b/Mathlib/Data/PFunctor/Univariate/M.lean @@ -129,7 +129,7 @@ def sCorec : X → ∀ n, CofixA F n theorem P_corec (i : X) (n : ℕ) : Agree (sCorec f i n) (sCorec f i (succ n)) := by induction' n with n n_ih generalizing i constructor - cases' h : f i with y g + cases' f i with y g constructor introv apply n_ih @@ -578,7 +578,7 @@ theorem corec_def {X} (f : X → F X) (x₀ : X) : M.corec f x₀ = M.mk (F.map cases' n with n · dsimp only [sCorec, Approx.sMk] · dsimp only [sCorec, Approx.sMk] - cases h : f x₀ + cases f x₀ dsimp only [PFunctor.map] congr set_option linter.uppercaseLean3 false in diff --git a/Mathlib/Data/QPF/Univariate/Basic.lean b/Mathlib/Data/QPF/Univariate/Basic.lean index 9f3873f283372..7daa034066022 100644 --- a/Mathlib/Data/QPF/Univariate/Basic.lean +++ b/Mathlib/Data/QPF/Univariate/Basic.lean @@ -541,7 +541,7 @@ def comp : QPF (Functor.Comp F₂ F₁) where conv => rhs rw [← abs_repr x] - cases' h : repr x with a f + cases' repr x with a f dsimp congr with x cases' h' : repr (f x) with b g diff --git a/Mathlib/Logic/Encodable/Basic.lean b/Mathlib/Logic/Encodable/Basic.lean index 5fe3ed0d0456e..62579a65debf8 100644 --- a/Mathlib/Logic/Encodable/Basic.lean +++ b/Mathlib/Logic/Encodable/Basic.lean @@ -644,7 +644,7 @@ theorem sequence_mono_nat {r : β → β → Prop} {f : α → β} (hf : Directe r (f (hf.sequence f n)) (f (hf.sequence f (n + 1))) := by dsimp [Directed.sequence] generalize hf.sequence f n = p - cases' h : (decode n: Option α) with a + cases' (decode n : Option α) with a · exact (Classical.choose_spec (hf p p)).1 · exact (Classical.choose_spec (hf p a)).1 #align directed.sequence_mono_nat Directed.sequence_mono_nat diff --git a/Mathlib/Order/Estimator.lean b/Mathlib/Order/Estimator.lean index 763f956bfc634..364c8baeb69cb 100644 --- a/Mathlib/Order/Estimator.lean +++ b/Mathlib/Order/Estimator.lean @@ -179,7 +179,7 @@ instance (a b : Thunk ℕ) {εa εb : Type*} [Estimator a εa] [Estimator b εb] have s₁ := Estimator.improve_spec (a := a) e.1 have s₂ := Estimator.improve_spec (a := b) e.2 revert s₁ s₂ - cases h₁ : improve a e.fst <;> cases h₂ : improve b e.snd <;> intro s₁ s₂ <;> simp_all only + cases improve a e.fst <;> cases improve b e.snd <;> intro s₁ s₂ <;> simp_all only · apply Nat.add_lt_add_left s₂ · apply Nat.add_lt_add_right s₁ · apply Nat.add_lt_add_right s₁ diff --git a/Mathlib/Order/InitialSeg.lean b/Mathlib/Order/InitialSeg.lean index 67a77c84ab0bf..1062281ebc660 100644 --- a/Mathlib/Order/InitialSeg.lean +++ b/Mathlib/Order/InitialSeg.lean @@ -513,7 +513,7 @@ noncomputable def InitialSeg.leLT [IsWellOrder β s] [IsTrans γ t] (f : r ≼i @[simp] theorem InitialSeg.leLT_apply [IsWellOrder β s] [IsTrans γ t] (f : r ≼i s) (g : s ≺i t) (a : α) : (f.leLT g) a = g (f a) := by - delta InitialSeg.leLT; cases' h : f.ltOrEq with f' f' + delta InitialSeg.leLT; cases' f.ltOrEq with f' f' · simp only [PrincipalSeg.trans_apply, f.ltOrEq_apply_left] · simp only [PrincipalSeg.equivLT_apply, f.ltOrEq_apply_right] #align initial_seg.le_lt_apply InitialSeg.leLT_apply diff --git a/Mathlib/RingTheory/Ideal/Norm.lean b/Mathlib/RingTheory/Ideal/Norm.lean index 500ebe4ccb616..0b72971ea4213 100644 --- a/Mathlib/RingTheory/Ideal/Norm.lean +++ b/Mathlib/RingTheory/Ideal/Norm.lean @@ -553,7 +553,7 @@ theorem spanNorm_localization (I : Ideal S) [Module.Finite R S] [Module.Free R S [Algebra Rₘ Sₘ] [Algebra R Sₘ] [IsScalarTower R Rₘ Sₘ] [IsScalarTower R S Sₘ] [IsLocalization M Rₘ] [IsLocalization (Algebra.algebraMapSubmonoid S M) Sₘ] : spanNorm Rₘ (I.map (algebraMap S Sₘ)) = (spanNorm R I).map (algebraMap R Rₘ) := by - cases h : subsingleton_or_nontrivial R + cases subsingleton_or_nontrivial R · haveI := IsLocalization.unique R Rₘ M simp [eq_iff_true_of_subsingleton] let b := Module.Free.chooseBasis R S diff --git a/Mathlib/SetTheory/Ordinal/Notation.lean b/Mathlib/SetTheory/Ordinal/Notation.lean index 3e30da76b787b..4247cccfcd67b 100644 --- a/Mathlib/SetTheory/Ordinal/Notation.lean +++ b/Mathlib/SetTheory/Ordinal/Notation.lean @@ -515,7 +515,7 @@ theorem sub_nfBelow : ∀ {o₁ o₂ b}, NFBelow o₁ b → NF o₂ → NFBelow · apply NFBelow.zero · simp only [h, Ordering.compares_eq] at this subst e₂ - cases mn : (n₁ : ℕ) - n₂ <;> simp [sub] + cases (n₁ : ℕ) - n₂ <;> simp [sub] · by_cases en : n₁ = n₂ <;> simp [en] · exact h'.mono (le_of_lt h₁.lt) · exact NFBelow.zero From 03433adfeb0da75f13881091b7855256a83624e9 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 5 Jan 2024 04:56:48 +0000 Subject: [PATCH 335/353] chore: prune proofwidgets oleans (#9450) The `.olean` files delivered via Lake from ProofWidgets have often been built using a different toolchain than Mathlib wants. These have been a perennial source of problems, and it seems easiest to just discard them and rely on the local build to generate them correctly. (This change was made by Joachim on `nightly-testing`, this PR is porting it back to `master`.) @tydeu @nomeata @digama0 Co-authored-by: Scott Morrison --- .github/workflows/bors.yml | 13 +++++++++++++ .github/workflows/build.yml | 13 +++++++++++++ .github/workflows/build.yml.in | 13 +++++++++++++ .github/workflows/build_fork.yml | 13 +++++++++++++ 4 files changed, 52 insertions(+) diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index de909506295b8..ff150595d3171 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -161,6 +161,19 @@ jobs: lean --version lake --version + - name: build cache + run: | + lake build cache + + - name: prune ProofWidgets .lake + run: | + # The ProofWidgets release contains not just the `.js` (which we need in order to build) + # but also `.oleans`, which may have been built with the wrong toolchain. + # This removes them. + # See discussion at https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/nightly-testing/near/411225235 + rm -rf .lake/packages/proofwidgets/.lake/build/lib + rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: get cache run: | lake exe cache clean diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index facc3d356f508..c773d9a306674 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -168,6 +168,19 @@ jobs: lean --version lake --version + - name: build cache + run: | + lake build cache + + - name: prune ProofWidgets .lake + run: | + # The ProofWidgets release contains not just the `.js` (which we need in order to build) + # but also `.oleans`, which may have been built with the wrong toolchain. + # This removes them. + # See discussion at https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/nightly-testing/near/411225235 + rm -rf .lake/packages/proofwidgets/.lake/build/lib + rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: get cache run: | lake exe cache clean diff --git a/.github/workflows/build.yml.in b/.github/workflows/build.yml.in index cffd2c5b5cd46..bb35ff3bad2a3 100644 --- a/.github/workflows/build.yml.in +++ b/.github/workflows/build.yml.in @@ -147,6 +147,19 @@ jobs: lean --version lake --version + - name: build cache + run: | + lake build cache + + - name: prune ProofWidgets .lake + run: | + # The ProofWidgets release contains not just the `.js` (which we need in order to build) + # but also `.oleans`, which may have been built with the wrong toolchain. + # This removes them. + # See discussion at https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/nightly-testing/near/411225235 + rm -rf .lake/packages/proofwidgets/.lake/build/lib + rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: get cache run: | lake exe cache clean diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index 95b38877f245c..6a0ebf2536021 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -165,6 +165,19 @@ jobs: lean --version lake --version + - name: build cache + run: | + lake build cache + + - name: prune ProofWidgets .lake + run: | + # The ProofWidgets release contains not just the `.js` (which we need in order to build) + # but also `.oleans`, which may have been built with the wrong toolchain. + # This removes them. + # See discussion at https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/nightly-testing/near/411225235 + rm -rf .lake/packages/proofwidgets/.lake/build/lib + rm -rf .lake/packages/proofwidgets/.lake/build/ir + - name: get cache run: | lake exe cache clean From b50557ce70bf397971b2ba89d7c532c36a163e5f Mon Sep 17 00:00:00 2001 From: JADekker <114015169+JADekker@users.noreply.github.com> Date: Fri, 5 Jan 2024 05:55:40 +0000 Subject: [PATCH 336/353] feat: Add Uncountable (#9254) Adds the Uncountable class to `Countable/Defs` and some basic API. Co-authored-by: Yury G. Kudryashov --- Mathlib/Data/Countable/Basic.lean | 43 +++++++++++++++---- Mathlib/Data/Countable/Defs.lean | 68 ++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 13 deletions(-) diff --git a/Mathlib/Data/Countable/Basic.lean b/Mathlib/Data/Countable/Basic.lean index 314c39a308ab5..3c8c3f02ba7b5 100644 --- a/Mathlib/Data/Countable/Basic.lean +++ b/Mathlib/Data/Countable/Basic.lean @@ -35,6 +35,9 @@ theorem countable_iff_nonempty_embedding : Countable α ↔ Nonempty (α ↪ ℕ ⟨fun ⟨⟨f, hf⟩⟩ => ⟨⟨f, hf⟩⟩, fun ⟨f⟩ => ⟨⟨f, f.2⟩⟩⟩ #align countable_iff_nonempty_embedding countable_iff_nonempty_embedding +theorem uncountable_iff_isEmpty_embedding : Uncountable α ↔ IsEmpty (α ↪ ℕ) := by + rw [← not_countable_iff, countable_iff_nonempty_embedding, not_nonempty_iff] + theorem nonempty_embedding_nat (α) [Countable α] : Nonempty (α ↪ ℕ) := countable_iff_nonempty_embedding.1 ‹_› #align nonempty_embedding_nat nonempty_embedding_nat @@ -43,6 +46,9 @@ protected theorem Function.Embedding.countable [Countable β] (f : α ↪ β) : f.injective.countable #align function.embedding.countable Function.Embedding.countable +protected lemma Function.Embedding.uncountable [Uncountable α] (f : α ↪ β) : Uncountable β := + f.injective.uncountable + end Embedding /-! @@ -53,24 +59,51 @@ section type variable {α : Type u} {β : Type v} {π : α → Type w} -instance [Countable α] [Countable β] : Countable (Sum α β) := by +instance [Countable α] [Countable β] : Countable (α ⊕ β) := by rcases exists_injective_nat α with ⟨f, hf⟩ rcases exists_injective_nat β with ⟨g, hg⟩ exact (Equiv.natSumNatEquivNat.injective.comp <| hf.sum_map hg).countable +instance Sum.uncountable_inl [Uncountable α] : Uncountable (α ⊕ β) := + inl_injective.uncountable + +instance Sum.uncountable_inr [Uncountable β] : Uncountable (α ⊕ β) := + inr_injective.uncountable + instance [Countable α] : Countable (Option α) := Countable.of_equiv _ (Equiv.optionEquivSumPUnit.{_, 0} α).symm +instance Option.instUncountable [Uncountable α] : Uncountable (Option α) := + Injective.uncountable fun _ _ ↦ Option.some_inj.1 + instance [Countable α] [Countable β] : Countable (α × β) := by rcases exists_injective_nat α with ⟨f, hf⟩ rcases exists_injective_nat β with ⟨g, hg⟩ exact (Nat.pairEquiv.injective.comp <| hf.Prod_map hg).countable +instance [Uncountable α] [Nonempty β] : Uncountable (α × β) := by + inhabit β + exact (Prod.mk.inj_right default).uncountable + +instance [Nonempty α] [Uncountable β] : Uncountable (α × β) := by + inhabit α + exact (Prod.mk.inj_left default).uncountable + instance [Countable α] [∀ a, Countable (π a)] : Countable (Sigma π) := by rcases exists_injective_nat α with ⟨f, hf⟩ choose g hg using fun a => exists_injective_nat (π a) exact ((Equiv.sigmaEquivProd ℕ ℕ).injective.comp <| hf.sigma_map hg).countable +lemma Sigma.uncountable (a : α) [Uncountable (π a)] : Uncountable (Sigma π) := + (sigma_mk_injective (i := a)).uncountable + +instance [Nonempty α] [∀ a, Uncountable (π a)] : Uncountable (Sigma π) := by + inhabit α; exact Sigma.uncountable default + +instance (priority := 500) SetCoe.countable [Countable α] (s : Set α) : Countable s := + Subtype.countable +#align set_coe.countable SetCoe.countable + end type section sort @@ -81,12 +114,8 @@ variable {α : Sort u} {β : Sort v} {π : α → Sort w} ### Operations on `Sort*`s -/ -instance (priority := 500) SetCoe.countable {α} [Countable α] (s : Set α) : Countable s := - Subtype.countable -#align set_coe.countable SetCoe.countable - -instance [Countable α] [Countable β] : Countable (PSum α β) := - Countable.of_equiv (Sum (PLift α) (PLift β)) (Equiv.plift.sumPSum Equiv.plift) +instance [Countable α] [Countable β] : Countable (α ⊕' β) := + Countable.of_equiv (PLift α ⊕ PLift β) (Equiv.plift.sumPSum Equiv.plift) instance [Countable α] [Countable β] : Countable (PProd α β) := Countable.of_equiv (PLift α × PLift β) (Equiv.plift.prodPProd Equiv.plift) diff --git a/Mathlib/Data/Countable/Defs.lean b/Mathlib/Data/Countable/Defs.lean index 78b60d323f3fc..7bec5e9fd701d 100644 --- a/Mathlib/Data/Countable/Defs.lean +++ b/Mathlib/Data/Countable/Defs.lean @@ -10,15 +10,17 @@ import Mathlib.Tactic.Common #align_import data.countable.defs from "leanprover-community/mathlib"@"70d50ecfd4900dd6d328da39ab7ebd516abe4025" /-! -# Countable types +# Countable and uncountable types -In this file we define a typeclass saying that a given `Sort*` is countable. See also `Encodable` -for a version that singles out a specific encoding of elements of `α` by natural numbers. +In this file we define a typeclass `Countable` saying that a given `Sort*` is countable +and a typeclass `Uncountable` saying that a given `Type*` is uncountable. -This file also provides a few instances of this typeclass. More instances can be found in other -files. --/ +See also `Encodable` for a version that singles out +a specific encoding of elements of `α` by natural numbers. +This file also provides a few instances of these typeclasses. +More instances can be found in other files. +-/ open Function @@ -117,3 +119,57 @@ instance (priority := 500) Quotient.countable [Countable α] {r : α → α → instance (priority := 500) [Countable α] {s : Setoid α} : Countable (Quotient s) := (inferInstance : Countable (@Quot α _)) + +/-! +### Uncountable types +-/ + +/-- A type `α` is uncountable if it is not countable. -/ +@[mk_iff uncountable_iff_not_countable] +class Uncountable (α : Sort*) : Prop where + /-- A type `α` is uncountable if it is not countable. -/ + not_countable : ¬Countable α + +lemma not_uncountable_iff : ¬Uncountable α ↔ Countable α := by + rw [uncountable_iff_not_countable, not_not] + +lemma not_countable_iff : ¬Countable α ↔ Uncountable α := (uncountable_iff_not_countable α).symm + +@[simp] +lemma not_uncountable [Countable α] : ¬Uncountable α := not_uncountable_iff.2 ‹_› + +@[simp] +lemma not_countable [Uncountable α] : ¬Countable α := Uncountable.not_countable + +protected theorem Function.Injective.uncountable [Uncountable α] {f : α → β} (hf : Injective f) : + Uncountable β := + ⟨fun _ ↦ not_countable hf.countable⟩ + +protected theorem Function.Surjective.uncountable [Uncountable β] {f : α → β} (hf : Surjective f) : + Uncountable α := (injective_surjInv hf).uncountable + +lemma not_injective_uncountable_countable [Uncountable α] [Countable β] (f : α → β) : + ¬Injective f := fun hf ↦ not_countable hf.countable + +lemma not_surjective_countable_uncountable [Countable α] [Uncountable β] (f : α → β) : + ¬Surjective f := fun hf ↦ + not_countable hf.countable + +theorem uncountable_iff_forall_not_surjective [Nonempty α] : + Uncountable α ↔ ∀ f : ℕ → α, ¬Surjective f := by + rw [← not_countable_iff, countable_iff_exists_surjective, not_exists] + +theorem Uncountable.of_equiv (α : Sort*) [Uncountable α] (e : α ≃ β) : Uncountable β := + e.injective.uncountable + +theorem Equiv.uncountable_iff (e : α ≃ β) : Uncountable α ↔ Uncountable β := + ⟨fun h => @Uncountable.of_equiv _ _ h e, fun h => @Uncountable.of_equiv _ _ h e.symm⟩ + +instance {β : Type v} [Uncountable β] : Uncountable (ULift.{u} β) := + .of_equiv _ Equiv.ulift.symm + +instance [Uncountable α] : Uncountable (PLift α) := + .of_equiv _ Equiv.plift.symm + +instance (priority := 100) [Uncountable α] : Infinite α := + ⟨fun _ ↦ not_countable (α := α) inferInstance⟩ From 901b783268f6721b515cbf39eddfb07db4fba5ed Mon Sep 17 00:00:00 2001 From: Jeremy Tan Jie Rui Date: Fri, 5 Jan 2024 06:57:28 +0000 Subject: [PATCH 337/353] feat: Zhu Shijie's identity (#9427) Cf. https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Proof.20of.20Combinatorial.20Identities/near/411120131 --- Mathlib/Data/Nat/Choose/Sum.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Mathlib/Data/Nat/Choose/Sum.lean b/Mathlib/Data/Nat/Choose/Sum.lean index 4fc5443a4c328..061ac12398ff5 100644 --- a/Mathlib/Data/Nat/Choose/Sum.lean +++ b/Mathlib/Data/Nat/Choose/Sum.lean @@ -132,6 +132,14 @@ theorem four_pow_le_two_mul_add_one_mul_central_binom (n : ℕ) : _ = (2 * n + 1) * choose (2 * n) n := by simp #align nat.four_pow_le_two_mul_add_one_mul_central_binom Nat.four_pow_le_two_mul_add_one_mul_central_binom +/-- **Zhu Shijie's identity** aka hockey-stick identity. -/ +theorem sum_Icc_choose (n k : ℕ) : ∑ m in Icc k n, m.choose k = (n + 1).choose (k + 1) := by + cases' le_or_gt k n with h h + · induction' n, h using le_induction with n _ ih; · simp + rw [← Ico_insert_right (by linarith), sum_insert (by simp), + show Ico k (n + 1) = Icc k n by rfl, ih, choose_succ_succ' (n + 1)] + · rw [choose_eq_zero_of_lt (by linarith), Icc_eq_empty_of_lt h, sum_empty] + end Nat theorem Int.alternating_sum_range_choose {n : ℕ} : From a310a89b3b6adc75dcde4df238382a90c1888d6c Mon Sep 17 00:00:00 2001 From: Winston Yin Date: Fri, 5 Jan 2024 09:42:52 +0000 Subject: [PATCH 338/353] feat: Boundaryless manifold (#9323) This is a more general notion of boundaryless manifold than `ModelWithCorners.Boundaryless`, which requires the `ModelWithCorners` to map to the whole model vector space. To justify this new type class, consider the interior of a manifold with non-empty boundary. It inherits a manifold structure via its embedding, and it would be convenient to use the same `ModelWithCorners` for the interior as for the whole space. Even though the interior is boundaryless, its inherited `ModelWithCorners` doesn't satisfy `ModelWithCorners.Boundaryless`. --- .../Geometry/Manifold/InteriorBoundary.lean | 41 +++++++++++++------ .../Manifold/SmoothManifoldWithCorners.lean | 4 +- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Mathlib/Geometry/Manifold/InteriorBoundary.lean b/Mathlib/Geometry/Manifold/InteriorBoundary.lean index e8f1d22de97be..970413b2edd42 100644 --- a/Mathlib/Geometry/Manifold/InteriorBoundary.lean +++ b/Mathlib/Geometry/Manifold/InteriorBoundary.lean @@ -103,25 +103,42 @@ lemma _root_.range_mem_nhds_isInteriorPoint {x : M} (h : I.IsInteriorPoint x) : rw [mem_nhds_iff] exact ⟨interior (range I), interior_subset, isOpen_interior, h⟩ -section boundaryless +/-- Type class for manifold without boundary. This differs from `ModelWithCorners.Boundaryless`, + which states that the `ModelWithCorners` maps to the whole model vector space. -/ +class _root_.BoundarylessManifold {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + (M : Type*) [TopologicalSpace M] [ChartedSpace H M] : Prop where + isInteriorPoint' : ∀ x : M, IsInteriorPoint I x + +section Boundaryless variable [I.Boundaryless] -/-- If `I` is boundaryless, every point of `M` is an interior point. -/ -lemma isInteriorPoint {x : M} : I.IsInteriorPoint x := by - let r := ((chartAt H x).isOpen_extend_target I).interior_eq - have : extChartAt I x = (chartAt H x).extend I := rfl - rw [← this] at r - rw [ModelWithCorners.isInteriorPoint_iff, r] - exact PartialEquiv.map_source _ (mem_extChartAt_source _ _) +/-- Boundaryless `ModelWithCorners` implies boundaryless manifold. -/ +instance : BoundarylessManifold I M where + isInteriorPoint' x := by + let r := ((chartAt H x).isOpen_extend_target I).interior_eq + have : extChartAt I x = (chartAt H x).extend I := rfl + rw [← this] at r + rw [ModelWithCorners.isInteriorPoint_iff, r] + exact PartialEquiv.map_source _ (mem_extChartAt_source _ _) -/-- If `I` is boundaryless, `M` has full interior. -/ +end Boundaryless + +section BoundarylessManifold +variable [BoundarylessManifold I M] + +lemma _root_.BoundarylessManifold.isInteriorPoint {x : M} : + IsInteriorPoint I x := BoundarylessManifold.isInteriorPoint' x + +/-- Boundaryless manifolds have full interior. -/ lemma interior_eq_univ : I.interior M = univ := by ext - refine ⟨fun _ ↦ trivial, fun _ ↦ I.isInteriorPoint⟩ + refine ⟨fun _ ↦ trivial, fun _ ↦ BoundarylessManifold.isInteriorPoint I⟩ -/-- If `I` is boundaryless, `M` has empty boundary. -/ +/-- Boundaryless manifolds have empty boundary. -/ lemma Boundaryless.boundary_eq_empty : I.boundary M = ∅ := by rw [I.boundary_eq_complement_interior, I.interior_eq_univ, compl_empty_iff] -end boundaryless +end BoundarylessManifold end ModelWithCorners diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index 7612e907c11ae..e958357df8faf 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -478,7 +478,9 @@ end ModelWithCornersProd section Boundaryless -/-- Property ensuring that the model with corners `I` defines manifolds without boundary. -/ +/-- Property ensuring that the model with corners `I` defines manifolds without boundary. This + differs from the more general `BoundarylessManifold`, which requires every point on the manifold + to be an interior point. -/ class ModelWithCorners.Boundaryless {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) : Prop where From f038bf8f141f7790d7c4e5903a7bfad571985094 Mon Sep 17 00:00:00 2001 From: leanprover-community-mathlib4-bot Date: Fri, 5 Jan 2024 10:02:48 +0000 Subject: [PATCH 339/353] chore: bump to nightly-2024-01-05 --- lean-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean-toolchain b/lean-toolchain index 091c6b09e1a68..a8de8cf356d97 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:nightly-2024-01-03 +leanprover/lean4:nightly-2024-01-05 From 4d385393cd569f08ac30425ef886a57bb10daaa5 Mon Sep 17 00:00:00 2001 From: L Date: Fri, 5 Jan 2024 10:17:16 +0000 Subject: [PATCH 340/353] feat: `IndepFun.symm` of different domains (#9425) Co-authored-by: L Lllvvuu --- Mathlib/Probability/Independence/Basic.lean | 7 ++++--- Mathlib/Probability/Independence/Kernel.lean | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Mathlib/Probability/Independence/Basic.lean b/Mathlib/Probability/Independence/Basic.lean index 18a7e4b341b6c..1e461cc0a4f38 100644 --- a/Mathlib/Probability/Independence/Basic.lean +++ b/Mathlib/Probability/Independence/Basic.lean @@ -650,11 +650,12 @@ theorem indepFun_iff_map_prod_eq_prod_map_map {mβ : MeasurableSpace β} {mβ' : rw [(h₀ hs ht).1, (h₀ hs ht).2, h, Measure.prod_prod] @[symm] -nonrec theorem IndepFun.symm {_ : MeasurableSpace β} {f g : Ω → β} (hfg : IndepFun f g μ) : - IndepFun g f μ := hfg.symm +nonrec theorem IndepFun.symm {_ : MeasurableSpace β} {_ : MeasurableSpace β'} + (hfg : IndepFun f g μ) : IndepFun g f μ := hfg.symm #align probability_theory.indep_fun.symm ProbabilityTheory.IndepFun.symm -theorem IndepFun.ae_eq {mβ : MeasurableSpace β} {f g f' g' : Ω → β} (hfg : IndepFun f g μ) +theorem IndepFun.ae_eq {mβ : MeasurableSpace β} {mβ' : MeasurableSpace β'} + {f' : Ω → β} {g' : Ω → β'} (hfg : IndepFun f g μ) (hf : f =ᵐ[μ] f') (hg : g =ᵐ[μ] g') : IndepFun f' g' μ := by refine kernel.IndepFun.ae_eq hfg ?_ ?_ <;> simp only [ae_dirac_eq, Filter.eventually_pure, kernel.const_apply] diff --git a/Mathlib/Probability/Independence/Kernel.lean b/Mathlib/Probability/Independence/Kernel.lean index 89457332a0f2f..222525433f5ab 100644 --- a/Mathlib/Probability/Independence/Kernel.lean +++ b/Mathlib/Probability/Independence/Kernel.lean @@ -788,10 +788,11 @@ theorem indepFun_iff_indepSet_preimage {mβ : MeasurableSpace β} {mβ' : Measur · rwa [← indepSet_iff_measure_inter_eq_mul (hf hs) (hg ht) κ μ] @[symm] -nonrec theorem IndepFun.symm {_ : MeasurableSpace β} {f g : Ω → β} (hfg : IndepFun f g κ μ) : - IndepFun g f κ μ := hfg.symm +nonrec theorem IndepFun.symm {_ : MeasurableSpace β} {_ : MeasurableSpace β'} + (hfg : IndepFun f g κ μ) : IndepFun g f κ μ := hfg.symm -theorem IndepFun.ae_eq {mβ : MeasurableSpace β} {f g f' g' : Ω → β} (hfg : IndepFun f g κ μ) +theorem IndepFun.ae_eq {mβ : MeasurableSpace β} {mβ' : MeasurableSpace β'} + {f' : Ω → β} {g' : Ω → β'} (hfg : IndepFun f g κ μ) (hf : ∀ᵐ a ∂μ, f =ᵐ[κ a] f') (hg : ∀ᵐ a ∂μ, g =ᵐ[κ a] g') : IndepFun f' g' κ μ := by rintro _ _ ⟨A, hA, rfl⟩ ⟨B, hB, rfl⟩ From a5346b6b0de2a269b02d7046418916a1ba5e3a86 Mon Sep 17 00:00:00 2001 From: Winston Yin Date: Fri, 5 Jan 2024 10:45:53 +0000 Subject: [PATCH 341/353] chore: rename in `PartialEquiv`, `Homeomorph`, `PartialHomeomorph` (#9430) Items 4-5 in [reference Zulip](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Assorted.20renames/near/411096017) Also added `symm` and `trans` definitions for `PartialEquiv`, `Homeomorph`, and `PartialHomeomorph`. --- Mathlib/Geometry/Manifold/ChartedSpace.lean | 6 +++--- Mathlib/Geometry/Manifold/Diffeomorph.lean | 3 ++- .../Manifold/SmoothManifoldWithCorners.lean | 4 ++-- Mathlib/Logic/Equiv/PartialEquiv.lean | 12 +++++++----- Mathlib/Topology/Homeomorph.lean | 2 ++ Mathlib/Topology/PartialHomeomorph.lean | 16 +++++++++------- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index e519a641f3a3e..2ad848a4620ec 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -1030,7 +1030,7 @@ theorem StructureGroupoid.compatible_of_mem_maximalAtlas {e e' : PartialHomeomor have D : (e.symm ≫ₕ f) ≫ₕ f.symm ≫ₕ e' ≈ (e.symm ≫ₕ e').restr s := calc (e.symm ≫ₕ f) ≫ₕ f.symm ≫ₕ e' = e.symm ≫ₕ (f ≫ₕ f.symm) ≫ₕ e' := by simp only [trans_assoc] _ ≈ e.symm ≫ₕ ofSet f.source f.open_source ≫ₕ e' := - EqOnSource.trans' (refl _) (EqOnSource.trans' (trans_self_symm _) (refl _)) + EqOnSource.trans' (refl _) (EqOnSource.trans' (self_trans_symm _) (refl _)) _ ≈ (e.symm ≫ₕ ofSet f.source f.open_source) ≫ₕ e' := by rw [trans_assoc] _ ≈ e.symm.restr s ≫ₕ e' := by rw [trans_of_set']; apply refl _ ≈ (e.symm ≫ₕ e').restr s := by rw [restr_trans] @@ -1098,7 +1098,7 @@ theorem singleton_hasGroupoid (h : e.source = Set.univ) (G : StructureGroupoid H intro e' e'' he' he'' rw [e.singletonChartedSpace_mem_atlas_eq h e' he', e.singletonChartedSpace_mem_atlas_eq h e'' he''] - refine' G.eq_on_source _ e.trans_symm_self + refine' G.eq_on_source _ e.symm_trans_self have hle : idRestrGroupoid ≤ G := (closedUnderRestriction_iff_id_le G).mp (by assumption) exact StructureGroupoid.le_iff.mp hle _ (idRestrGroupoid_mem _) } #align local_homeomorph.singleton_has_groupoid PartialHomeomorph.singleton_hasGroupoid @@ -1262,7 +1262,7 @@ def Structomorph.trans (e : Structomorph G M M') (e' : Structomorph G M' M'') : F₁ ≈ c.symm ≫ₕ f₁ ≫ₕ (g ≫ₕ g.symm) ≫ₕ f₂ ≫ₕ c' := by simp only [trans_assoc, _root_.refl] _ ≈ c.symm ≫ₕ f₁ ≫ₕ ofSet g.source g.open_source ≫ₕ f₂ ≫ₕ c' := EqOnSource.trans' (_root_.refl _) (EqOnSource.trans' (_root_.refl _) - (EqOnSource.trans' (trans_self_symm g) (_root_.refl _))) + (EqOnSource.trans' (self_trans_symm g) (_root_.refl _))) _ ≈ ((c.symm ≫ₕ f₁) ≫ₕ ofSet g.source g.open_source) ≫ₕ f₂ ≫ₕ c' := by simp only [trans_assoc, _root_.refl] _ ≈ (c.symm ≫ₕ f₁).restr s ≫ₕ f₂ ≫ₕ c' := by rw [trans_of_set'] diff --git a/Mathlib/Geometry/Manifold/Diffeomorph.lean b/Mathlib/Geometry/Manifold/Diffeomorph.lean index 38875a608ffa6..995a04d616bf6 100644 --- a/Mathlib/Geometry/Manifold/Diffeomorph.lean +++ b/Mathlib/Geometry/Manifold/Diffeomorph.lean @@ -195,6 +195,7 @@ theorem coe_refl : ⇑(Diffeomorph.refl I M n) = id := end /-- Composition of two diffeomorphisms. -/ +@[trans] protected def trans (h₁ : M ≃ₘ^n⟮I, I'⟯ M') (h₂ : M' ≃ₘ^n⟮I', J⟯ N) : M ≃ₘ^n⟮I, J⟯ N where contMDiff_toFun := h₂.contMDiff.comp h₁.contMDiff contMDiff_invFun := h₁.contMDiff_invFun.comp h₂.contMDiff_invFun @@ -217,7 +218,7 @@ theorem coe_trans (h₁ : M ≃ₘ^n⟮I, I'⟯ M') (h₂ : M' ≃ₘ^n⟮I', J #align diffeomorph.coe_trans Diffeomorph.coe_trans /-- Inverse of a diffeomorphism. -/ -@[pp_dot] +@[symm] protected def symm (h : M ≃ₘ^n⟮I, J⟯ N) : N ≃ₘ^n⟮J, I⟯ M where contMDiff_toFun := h.contMDiff_invFun contMDiff_invFun := h.contMDiff_toFun diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index e958357df8faf..be615f8a99e15 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -619,7 +619,7 @@ the `C^n` groupoid. -/ theorem symm_trans_mem_contDiffGroupoid (e : PartialHomeomorph M H) : e.symm.trans e ∈ contDiffGroupoid n I := haveI : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := - PartialHomeomorph.trans_symm_self _ + PartialHomeomorph.symm_trans_self _ StructureGroupoid.eq_on_source _ (ofSet_mem_contDiffGroupoid n I e.open_target) this #align symm_trans_mem_cont_diff_groupoid symm_trans_mem_contDiffGroupoid @@ -778,7 +778,7 @@ the analytic groupoid. -/ theorem symm_trans_mem_analyticGroupoid (e : PartialHomeomorph M H) : e.symm.trans e ∈ analyticGroupoid I := haveI : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := - PartialHomeomorph.trans_symm_self _ + PartialHomeomorph.symm_trans_self _ StructureGroupoid.eq_on_source _ (ofSet_mem_analyticGroupoid I e.open_target) this /-- The analytic groupoid is closed under restriction. -/ diff --git a/Mathlib/Logic/Equiv/PartialEquiv.lean b/Mathlib/Logic/Equiv/PartialEquiv.lean index 39ed99c0b3f3a..c3a0d71e6b55d 100644 --- a/Mathlib/Logic/Equiv/PartialEquiv.lean +++ b/Mathlib/Logic/Equiv/PartialEquiv.lean @@ -148,6 +148,7 @@ instance [Inhabited α] [Inhabited β] : Inhabited (PartialEquiv α β) := eqOn_empty _ _⟩⟩ /-- The inverse of a partial equivalence -/ +@[symm] protected def symm : PartialEquiv β α where toFun := e.invFun invFun := e.toFun @@ -689,6 +690,7 @@ protected def trans' (e' : PartialEquiv β γ) (h : e.target = e'.source) : Part /-- Composing two partial equivs, by restricting to the maximal domain where their composition is well defined. -/ +@[trans] protected def trans : PartialEquiv α γ := PartialEquiv.trans' (e.symm.restr e'.source).symm (e'.restr e.target) (inter_comm _ _) #align local_equiv.trans PartialEquiv.trans @@ -896,18 +898,18 @@ theorem EqOnSource.source_inter_preimage_eq {e e' : PartialEquiv α β} (he : e /-- Composition of a partial equivlance and its inverse is equivalent to the restriction of the identity to the source. -/ -theorem trans_self_symm : e.trans e.symm ≈ ofSet e.source := by +theorem self_trans_symm : e.trans e.symm ≈ ofSet e.source := by have A : (e.trans e.symm).source = e.source := by mfld_set_tac refine' ⟨by rw [A, ofSet_source], fun x hx => _⟩ rw [A] at hx simp only [hx, mfld_simps] -#align local_equiv.trans_self_symm PartialEquiv.trans_self_symm +#align local_equiv.self_trans_symm PartialEquiv.self_trans_symm /-- Composition of the inverse of a partial equivalence and this partial equivalence is equivalent to the restriction of the identity to the target. -/ -theorem trans_symm_self : e.symm.trans e ≈ PartialEquiv.ofSet e.target := - trans_self_symm e.symm -#align local_equiv.trans_symm_self PartialEquiv.trans_symm_self +theorem symm_trans_self : e.symm.trans e ≈ PartialEquiv.ofSet e.target := + self_trans_symm e.symm +#align local_equiv.symm_trans_self PartialEquiv.symm_trans_self /-- Two equivalent partial equivs are equal when the source and target are `univ`. -/ theorem eq_of_eqOnSource_univ (e e' : PartialEquiv α β) (h : e ≈ e') (s : e.source = univ) diff --git a/Mathlib/Topology/Homeomorph.lean b/Mathlib/Topology/Homeomorph.lean index eab27e4b2cba2..62369062ba06a 100644 --- a/Mathlib/Topology/Homeomorph.lean +++ b/Mathlib/Topology/Homeomorph.lean @@ -74,6 +74,7 @@ protected def empty [IsEmpty X] [IsEmpty Y] : X ≃ₜ Y where __ := Equiv.equivOfIsEmpty X Y /-- Inverse of a homeomorphism. -/ +@[symm] protected def symm (h : X ≃ₜ Y) : Y ≃ₜ X where continuous_toFun := h.continuous_invFun continuous_invFun := h.continuous_toFun @@ -117,6 +118,7 @@ protected def refl (X : Type*) [TopologicalSpace X] : X ≃ₜ X where #align homeomorph.refl Homeomorph.refl /-- Composition of two homeomorphisms. -/ +@[trans] protected def trans (h₁ : X ≃ₜ Y) (h₂ : Y ≃ₜ Z) : X ≃ₜ Z where continuous_toFun := h₂.continuous_toFun.comp h₁.continuous_toFun continuous_invFun := h₁.continuous_invFun.comp h₂.continuous_invFun diff --git a/Mathlib/Topology/PartialHomeomorph.lean b/Mathlib/Topology/PartialHomeomorph.lean index d0c6a7b94550f..c290c93085038 100644 --- a/Mathlib/Topology/PartialHomeomorph.lean +++ b/Mathlib/Topology/PartialHomeomorph.lean @@ -76,6 +76,7 @@ instance : CoeFun (PartialHomeomorph α β) fun _ => α → β := ⟨fun e => e.toFun'⟩ /-- The inverse of a partial homeomorphism -/ +@[symm] protected def symm : PartialHomeomorph β α where toPartialEquiv := e.toPartialEquiv.symm open_source := e.open_target @@ -816,6 +817,7 @@ protected def trans' (h : e.target = e'.source) : PartialHomeomorph α γ where /-- Composing two partial homeomorphisms, by restricting to the maximal domain where their composition is well defined. -/ +@[trans] protected def trans : PartialHomeomorph α γ := PartialHomeomorph.trans' (e.symm.restrOpen e'.source e'.open_source).symm (e'.restrOpen e.target e.open_target) (by simp [inter_comm]) @@ -1024,13 +1026,13 @@ theorem Set.EqOn.restr_eqOn_source {e e' : PartialHomeomorph α β} /-- Composition of a partial homeomorphism and its inverse is equivalent to the restriction of the identity to the source -/ -theorem trans_self_symm : e.trans e.symm ≈ PartialHomeomorph.ofSet e.source e.open_source := - PartialEquiv.trans_self_symm _ -#align local_homeomorph.trans_self_symm PartialHomeomorph.trans_self_symm +theorem self_trans_symm : e.trans e.symm ≈ PartialHomeomorph.ofSet e.source e.open_source := + PartialEquiv.self_trans_symm _ +#align local_homeomorph.self_trans_symm PartialHomeomorph.self_trans_symm -theorem trans_symm_self : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := - e.symm.trans_self_symm -#align local_homeomorph.trans_symm_self PartialHomeomorph.trans_symm_self +theorem symm_trans_self : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := + e.symm.self_trans_symm +#align local_homeomorph.symm_trans_self PartialHomeomorph.symm_trans_self theorem eq_of_eqOnSource_univ {e e' : PartialHomeomorph α β} (h : e ≈ e') (s : e.source = univ) (t : e.target = univ) : e = e' := @@ -1445,7 +1447,7 @@ theorem subtypeRestr_symm_trans_subtypeRestr (f f' : PartialHomeomorph α β) : rw [ofSet_trans', sets_identity, ← trans_of_set' _ openness₂, trans_assoc] refine' EqOnSource.trans' (eqOnSource_refl _) _ -- f has been eliminated !!! - refine' Setoid.trans (trans_symm_self s.localHomeomorphSubtypeCoe) _ + refine' Setoid.trans (symm_trans_self s.localHomeomorphSubtypeCoe) _ simp only [mfld_simps, Setoid.refl] #align local_homeomorph.subtype_restr_symm_trans_subtype_restr PartialHomeomorph.subtypeRestr_symm_trans_subtypeRestr From e1da93fc327a8f558ac37dfdba87c42c5fa0215f Mon Sep 17 00:00:00 2001 From: Winston Yin Date: Fri, 5 Jan 2024 11:32:28 +0000 Subject: [PATCH 342/353] feat(Geometry/Manifold/VectorBundle/Tangent): tangentCoordChange (#8672) We define `tangentCoordChange` as a convenient abbreviation for coordinate changes on the tangent bundle. We also restate the axioms of `VectorBundleCore` as lemmas involving `extChartAt`. Currently, we need to write `(tangentBundleCore I M).coordChange (achart H x) (achart H y)`, referring explicitly to the atlas of `M`. Since `tangentBundleCore` uses the same base sets as the preferred charts of the base manifold, we wish to work directly with points `x y : M` and the preferred extended charts at those points (`extChartAt`). We find this definition and related lemmas useful in #8483 in shortening proofs. --- .../Manifold/VectorBundle/Tangent.lean | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean index bce81054d2c41..8df736fa3019c 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean @@ -124,6 +124,51 @@ theorem tangentBundleCore_coordChange_achart (x x' z : M) : rfl #align tangent_bundle_core_coord_change_achart tangentBundleCore_coordChange_achart +section tangentCoordChange + +/-- In a manifold `M`, given two preferred charts indexed by `x y : M`, `tangentCoordChange I x y` +is the family of derivatives of the corresponding change-of-coordinates map. It takes junk values +outside the intersection of the sources of the two charts. + +Note that this definition takes advantage of the fact that `tangentBundleCore` has the same base +sets as the preferred charts of the base manifold. -/ +abbrev tangentCoordChange (x y : M) : M → E →L[𝕜] E := + (tangentBundleCore I M).coordChange (achart H x) (achart H y) + +variable {I} + +lemma tangentCoordChange_def {x y z : M} : tangentCoordChange I x y z = + fderivWithin 𝕜 (extChartAt I y ∘ (extChartAt I x).symm) (range I) (extChartAt I x z) := rfl + +lemma tangentCoordChange_self {x z : M} {v : E} (h : z ∈ (extChartAt I x).source) : + tangentCoordChange I x x z v = v := by + apply (tangentBundleCore I M).coordChange_self + rw [tangentBundleCore_baseSet, coe_achart, ← extChartAt_source I] + exact h + +lemma tangentCoordChange_comp {w x y z : M} {v : E} + (h : z ∈ (extChartAt I w).source ∩ (extChartAt I x).source ∩ (extChartAt I y).source) : + tangentCoordChange I x y z (tangentCoordChange I w x z v) = tangentCoordChange I w y z v := by + apply (tangentBundleCore I M).coordChange_comp + simp only [tangentBundleCore_baseSet, coe_achart, ← extChartAt_source I] + exact h + +lemma hasFDerivWithinAt_tangentCoordChange {x y z : M} + (h : z ∈ (extChartAt I x).source ∩ (extChartAt I y).source) : + HasFDerivWithinAt ((extChartAt I y) ∘ (extChartAt I x).symm) (tangentCoordChange I x y z) + (range I) (extChartAt I x z) := + have h' : extChartAt I x z ∈ ((extChartAt I x).symm ≫ (extChartAt I y)).source := by + rw [PartialEquiv.trans_source'', PartialEquiv.symm_symm, PartialEquiv.symm_target] + exact mem_image_of_mem _ h + ((contDiffWithinAt_ext_coord_change I y x h').differentiableWithinAt (by simp)).hasFDerivWithinAt + +lemma continuousOn_tangentCoordChange (x y : M) : ContinuousOn (tangentCoordChange I x y) + ((extChartAt I x).source ∩ (extChartAt I y).source) := by + convert (tangentBundleCore I M).continuousOn_coordChange (achart H x) (achart H y) <;> + simp only [tangentBundleCore_baseSet, coe_achart, ← extChartAt_source I] + +end tangentCoordChange + /-- The tangent space at a point of the manifold `M`. It is just `E`. We could use instead `(tangentBundleCore I M).to_topological_vector_bundle_core.fiber x`, but we use `E` to help the kernel. From 57ca123151b29b04281afbcb84d51d845b62ae22 Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Fri, 5 Jan 2024 11:32:30 +0000 Subject: [PATCH 343/353] feat: refactor lemma `LieModule.dualAnnihilator_ker_traceForm_le_span_weight` (#9047) Also add some API for related results such as `LinearMap.dualCoannihilator_range_eq_ker_flip`, which is not needed here but worth having. Co-authored-by: Junyan Xu --- Mathlib/Algebra/Lie/Killing.lean | 49 +++++++++++++++++--------------- Mathlib/LinearAlgebra/Dual.lean | 16 +++++++++++ 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Mathlib/Algebra/Lie/Killing.lean b/Mathlib/Algebra/Lie/Killing.lean index b735f497dc472..e1fbb04f34613 100644 --- a/Mathlib/Algebra/Lie/Killing.lean +++ b/Mathlib/Algebra/Lie/Killing.lean @@ -473,10 +473,13 @@ end LieAlgebra section Field open LieModule FiniteDimensional -open Submodule (span) +open Submodule (span subset_span) -lemma LieModule.traceForm_eq_sum_finrank_nsmul_mul [LieAlgebra.IsNilpotent K L] - [LinearWeights K L M] [IsTriangularizable K L M] (x y : L) : +namespace LieModule + +variable [LieAlgebra.IsNilpotent K L] [LinearWeights K L M] [IsTriangularizable K L M] + +lemma traceForm_eq_sum_finrank_nsmul_mul (x y : L) : traceForm K L M x y = ∑ χ in weight K L M, finrank K (weightSpace M χ) • (χ x * χ y) := by have hxy : ∀ χ : L → K, MapsTo (toEndomorphism K L M x ∘ₗ toEndomorphism K L M y) (weightSpace M χ) (weightSpace M χ) := @@ -492,26 +495,24 @@ lemma LieModule.traceForm_eq_sum_finrank_nsmul_mul [LieAlgebra.IsNilpotent K L] LinearMap.trace_eq_sum_trace_restrict' hds hfin hxy] exact Finset.sum_congr (by simp) (fun χ _ ↦ traceForm_weightSpace_eq K L M χ x y) +lemma traceForm_eq_sum_finrank_nsmul : + traceForm K L M = ∑ χ : weight K L M, finrank K (weightSpace M (χ : L → K)) • + (weight.toLinear K L M χ).smulRight (weight.toLinear K L M χ) := by + ext + rw [traceForm_eq_sum_finrank_nsmul_mul, ← Finset.sum_attach] + simp + -- The reverse inclusion should also hold: TODO prove this! -lemma LieModule.dualAnnihilator_ker_traceForm_le_span_weight [LieAlgebra.IsNilpotent K L] - [LinearWeights K L M] [IsTriangularizable K L M] [FiniteDimensional K L] : - (LinearMap.ker (traceForm K L M)).dualAnnihilator ≤ span K (range (weight.toLinear K L M)) := by - intro g hg - simp only [Submodule.mem_dualAnnihilator, LinearMap.mem_ker] at hg - by_contra contra - obtain ⟨f : Module.Dual K (Module.Dual K L), hf, hf'⟩ := - Submodule.exists_dual_map_eq_bot_of_nmem contra inferInstance - let x : L := (Module.evalEquiv K L).symm f - replace hf' : ∀ χ ∈ weight K L M, χ x = 0 := by - intro χ hχ - change weight.toLinear K L M ⟨χ, hχ⟩ x = 0 - rw [Module.apply_evalEquiv_symm_apply, ← Submodule.mem_bot (R := K), ← hf', Submodule.mem_map] - exact ⟨weight.toLinear K L M ⟨χ, hχ⟩, Submodule.subset_span (mem_range_self _), rfl⟩ - have hx : g x ≠ 0 := by simpa - refine hx (hg _ ?_) - ext y - rw [LieModule.traceForm_eq_sum_finrank_nsmul_mul, LinearMap.zero_apply] - exact Finset.sum_eq_zero fun χ hχ ↦ by simp [hf' χ hχ] +lemma range_traceForm_le_span_weight : + LinearMap.range (traceForm K L M) ≤ span K (range (weight.toLinear K L M)) := by + rintro - ⟨x, rfl⟩ + rw [LieModule.traceForm_eq_sum_finrank_nsmul, LinearMap.coeFn_sum, Finset.sum_apply] + refine Submodule.sum_mem _ fun χ _ ↦ ?_ + simp_rw [LinearMap.smul_apply, LinearMap.coe_smulRight, weight.toLinear_apply, + nsmul_eq_smul_cast (R := K)] + exact Submodule.smul_mem _ _ <| Submodule.smul_mem _ _ <| subset_span <| mem_range_self χ + +end LieModule /-- Given a splitting Cartan subalgebra `H` of a finite-dimensional Lie algebra with non-singular Killing form, the corresponding roots span the dual space of `H`. -/ @@ -519,6 +520,8 @@ Killing form, the corresponding roots span the dual space of `H`. -/ lemma LieAlgebra.IsKilling.span_weight_eq_top [FiniteDimensional K L] [IsKilling K L] (H : LieSubalgebra K L) [H.IsCartanSubalgebra] [IsTriangularizable K H L] : span K (range (weight.toLinear K H L)) = ⊤ := by - simpa using LieModule.dualAnnihilator_ker_traceForm_le_span_weight K H L + refine eq_top_iff.mpr (le_trans ?_ (LieModule.range_traceForm_le_span_weight K H L)) + rw [← traceForm_flip K H L, ← LinearMap.dualAnnihilator_ker_eq_range_flip, + ker_traceForm_eq_bot_of_isCartanSubalgebra, Submodule.dualAnnihilator_bot] end Field diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 0753e9517e6c9..b83dcc91a128d 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -912,6 +912,7 @@ def dualCoannihilator (Φ : Submodule R (Module.Dual R M)) : Submodule R M := Φ.dualAnnihilator.comap (Module.Dual.eval R M) #align submodule.dual_coannihilator Submodule.dualCoannihilator +@[simp] theorem mem_dualCoannihilator {Φ : Submodule R (Module.Dual R M)} (x : M) : x ∈ Φ.dualCoannihilator ↔ ∀ φ ∈ Φ, (φ x : R) = 0 := by simp_rw [dualCoannihilator, mem_comap, mem_dualAnnihilator, Module.Dual.eval_apply] @@ -1428,6 +1429,15 @@ theorem range_dualMap_eq_dualAnnihilator_ker_of_subtype_range_surjective (f : M exact (ker_rangeRestrict f).symm #align linear_map.range_dual_map_eq_dual_annihilator_ker_of_subtype_range_surjective LinearMap.range_dualMap_eq_dualAnnihilator_ker_of_subtype_range_surjective +theorem ker_dualMap_eq_dualCoannihilator_range (f : M →ₗ[R] M') : + LinearMap.ker f.dualMap = (Dual.eval R M' ∘ₗ f).range.dualCoannihilator := by + ext x; simp [ext_iff (f := dualMap f x)] + +@[simp] +lemma dualCoannihilator_range_eq_ker_flip (B : M →ₗ[R] M' →ₗ[R] R) : + (range B).dualCoannihilator = LinearMap.ker B.flip := by + ext x; simp [ext_iff (f := B.flip x)] + end LinearMap end CommRing @@ -1595,6 +1605,12 @@ theorem dualMap_bijective_iff {f : V₁ →ₗ[K] V₂} : variable {B : V₁ →ₗ[K] V₂ →ₗ[K] K} +@[simp] +lemma dualAnnihilator_ker_eq_range_flip [IsReflexive K V₂] : + (ker B).dualAnnihilator = range B.flip := by + change _ = range (B.dualMap.comp (Module.evalEquiv K V₂).toLinearMap) + rw [← range_dualMap_eq_dualAnnihilator_ker, range_comp_of_range_eq_top _ (LinearEquiv.range _)] + open Function theorem flip_injective_iff₁ [FiniteDimensional K V₁] : Injective B.flip ↔ Surjective B := by From c8d50df101dfbcab82880b4850ce4ece7922d83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 5 Jan 2024 11:32:31 +0000 Subject: [PATCH 344/353] chore: Move `Commute` results earlier (#9440) These lemmas aren't really proved any faster using units, and I will soon need them not to be proved using units. Part of #9411 --- Mathlib/Algebra/Group/Commute/Basic.lean | 34 +++++++++++++ Mathlib/Algebra/Group/Commute/Units.lean | 61 ----------------------- Mathlib/Algebra/Group/Defs.lean | 14 ++++++ Mathlib/Algebra/Group/Semiconj/Basic.lean | 36 +++++++++---- Mathlib/Algebra/Group/Semiconj/Units.lean | 32 ------------ Mathlib/Algebra/GroupPower/Basic.lean | 4 +- Mathlib/Data/Int/Basic.lean | 5 -- 7 files changed, 77 insertions(+), 109 deletions(-) diff --git a/Mathlib/Algebra/Group/Commute/Basic.lean b/Mathlib/Algebra/Group/Commute/Basic.lean index 52526a31626af..ec86249c341d1 100644 --- a/Mathlib/Algebra/Group/Commute/Basic.lean +++ b/Mathlib/Algebra/Group/Commute/Basic.lean @@ -58,4 +58,38 @@ protected theorem div_div_div_comm (hbc : Commute b c) (hbd : Commute b⁻¹ d) end DivisionMonoid +section Group +variable [Group G] {a b : G} + +@[to_additive (attr := simp)] +lemma inv_left_iff : Commute a⁻¹ b ↔ Commute a b := SemiconjBy.inv_symm_left_iff +#align commute.inv_left_iff Commute.inv_left_iff +#align add_commute.neg_left_iff AddCommute.neg_left_iff + +@[to_additive] alias ⟨_, inv_left⟩ := inv_left_iff +#align commute.inv_left Commute.inv_left +#align add_commute.neg_left AddCommute.neg_left + +@[to_additive (attr := simp)] +lemma inv_right_iff : Commute a b⁻¹ ↔ Commute a b := SemiconjBy.inv_right_iff +#align commute.inv_right_iff Commute.inv_right_iff +#align add_commute.neg_right_iff AddCommute.neg_right_iff + +@[to_additive] alias ⟨_, inv_right⟩ := inv_right_iff +#align commute.inv_right Commute.inv_right +#align add_commute.neg_right AddCommute.neg_right + +@[to_additive] +protected lemma inv_mul_cancel (h : Commute a b) : a⁻¹ * b * a = b := by + rw [h.inv_left.eq, inv_mul_cancel_right] +#align commute.inv_mul_cancel Commute.inv_mul_cancel +#align add_commute.neg_add_cancel AddCommute.neg_add_cancel + +@[to_additive] +lemma inv_mul_cancel_assoc (h : Commute a b) : a⁻¹ * (b * a) = b := by + rw [← mul_assoc, h.inv_mul_cancel] +#align commute.inv_mul_cancel_assoc Commute.inv_mul_cancel_assoc +#align add_commute.neg_add_cancel_assoc AddCommute.neg_add_cancel_assoc + +end Group end Commute diff --git a/Mathlib/Algebra/Group/Commute/Units.lean b/Mathlib/Algebra/Group/Commute/Units.lean index ab88e7de6d631..e047ec8da22da 100644 --- a/Mathlib/Algebra/Group/Commute/Units.lean +++ b/Mathlib/Algebra/Group/Commute/Units.lean @@ -99,65 +99,4 @@ theorem _root_.isUnit_mul_self_iff : IsUnit (a * a) ↔ IsUnit a := #align is_add_unit_add_self_iff isAddUnit_add_self_iff end Monoid - -section Group - -variable [Group G] {a b : G} - -@[to_additive] -theorem inv_right : Commute a b → Commute a b⁻¹ := - SemiconjBy.inv_right -#align commute.inv_right Commute.inv_right -#align add_commute.neg_right AddCommute.neg_right - -@[to_additive (attr := simp)] -theorem inv_right_iff : Commute a b⁻¹ ↔ Commute a b := - SemiconjBy.inv_right_iff -#align commute.inv_right_iff Commute.inv_right_iff -#align add_commute.neg_right_iff AddCommute.neg_right_iff - -@[to_additive] -theorem inv_left : Commute a b → Commute a⁻¹ b := - SemiconjBy.inv_symm_left -#align commute.inv_left Commute.inv_left -#align add_commute.neg_left AddCommute.neg_left - -@[to_additive (attr := simp)] -theorem inv_left_iff : Commute a⁻¹ b ↔ Commute a b := - SemiconjBy.inv_symm_left_iff -#align commute.inv_left_iff Commute.inv_left_iff -#align add_commute.neg_left_iff AddCommute.neg_left_iff - -@[to_additive] -protected theorem inv_mul_cancel (h : Commute a b) : a⁻¹ * b * a = b := by - rw [h.inv_left.eq, inv_mul_cancel_right] -#align commute.inv_mul_cancel Commute.inv_mul_cancel -#align add_commute.neg_add_cancel AddCommute.neg_add_cancel - -@[to_additive] -theorem inv_mul_cancel_assoc (h : Commute a b) : a⁻¹ * (b * a) = b := by - rw [← mul_assoc, h.inv_mul_cancel] -#align commute.inv_mul_cancel_assoc Commute.inv_mul_cancel_assoc -#align add_commute.neg_add_cancel_assoc AddCommute.neg_add_cancel_assoc - -end Group - end Commute - -section CommGroup - -variable [CommGroup G] (a b : G) - -@[to_additive (attr := simp)] -theorem inv_mul_cancel_comm : a⁻¹ * b * a = b := - (Commute.all a b).inv_mul_cancel -#align inv_mul_cancel_comm inv_mul_cancel_comm -#align neg_add_cancel_comm neg_add_cancel_comm - -@[to_additive (attr := simp)] -theorem inv_mul_cancel_comm_assoc : a⁻¹ * (b * a) = b := - (Commute.all a b).inv_mul_cancel_assoc -#align inv_mul_cancel_comm_assoc inv_mul_cancel_comm_assoc -#align neg_add_cancel_comm_assoc neg_add_cancel_comm_assoc - -end CommGroup diff --git a/Mathlib/Algebra/Group/Defs.lean b/Mathlib/Algebra/Group/Defs.lean index 96578316890a6..5871222cc782d 100644 --- a/Mathlib/Algebra/Group/Defs.lean +++ b/Mathlib/Algebra/Group/Defs.lean @@ -998,6 +998,10 @@ theorem zpow_ofNat (a : G) : ∀ n : ℕ, a ^ (n : ℤ) = a ^ n #align zpow_of_nat zpow_ofNat #align of_nat_zsmul ofNat_zsmul +@[to_additive (attr := simp, norm_cast) coe_nat_zsmul] +lemma zpow_coe_nat (a : G) (n : ℕ) : a ^ (Nat.cast n : ℤ) = a ^ n := zpow_ofNat .. +#align coe_nat_zsmul coe_nat_zsmul + theorem zpow_negSucc (a : G) (n : ℕ) : a ^ (Int.negSucc n) = (a ^ (n + 1))⁻¹ := by rw [← zpow_ofNat] exact DivInvMonoid.zpow_neg' n a @@ -1263,6 +1267,16 @@ instance (priority := 100) CommGroup.toCancelCommMonoid : CancelCommMonoid G := instance (priority := 100) CommGroup.toDivisionCommMonoid : DivisionCommMonoid G := { ‹CommGroup G›, Group.toDivisionMonoid with } +@[to_additive (attr := simp)] lemma inv_mul_cancel_comm (a b : G) : a⁻¹ * b * a = b := by + rw [mul_comm, mul_inv_cancel_left] +#align inv_mul_cancel_comm inv_mul_cancel_comm +#align neg_add_cancel_comm neg_add_cancel_comm + +@[to_additive (attr := simp)] lemma inv_mul_cancel_comm_assoc (a b : G) : a⁻¹ * (b * a) = b := by + rw [mul_comm, mul_inv_cancel_right] +#align inv_mul_cancel_comm_assoc inv_mul_cancel_comm_assoc +#align neg_add_cancel_comm_assoc neg_add_cancel_comm_assoc + end CommGroup /-! We initialize all projections for `@[simps]` here, so that we don't have to do it in later diff --git a/Mathlib/Algebra/Group/Semiconj/Basic.lean b/Mathlib/Algebra/Group/Semiconj/Basic.lean index 05a807fabfd96..b3ff872fd9cf9 100644 --- a/Mathlib/Algebra/Group/Semiconj/Basic.lean +++ b/Mathlib/Algebra/Group/Semiconj/Basic.lean @@ -9,29 +9,47 @@ import Mathlib.Algebra.Group.Basic #align_import algebra.group.semiconj from "leanprover-community/mathlib"@"a148d797a1094ab554ad4183a4ad6f130358ef64" /-! -# Lemmas about semiconjugate elements of a semigroup +# Lemmas about semiconjugate elements of a group -/ namespace SemiconjBy +variable {G : Type*} section DivisionMonoid - -variable {G : Type*} [DivisionMonoid G] {a x y : G} +variable [DivisionMonoid G] {a x y : G} @[to_additive (attr := simp)] -theorem inv_inv_symm_iff : SemiconjBy a⁻¹ x⁻¹ y⁻¹ ↔ SemiconjBy a y x := - inv_involutive.injective.eq_iff.symm.trans <| by - rw [mul_inv_rev, mul_inv_rev, inv_inv, inv_inv, inv_inv, eq_comm, SemiconjBy] +theorem inv_inv_symm_iff : SemiconjBy a⁻¹ x⁻¹ y⁻¹ ↔ SemiconjBy a y x := by + simp_rw [SemiconjBy, ← mul_inv_rev, inv_inj, eq_comm] #align semiconj_by.inv_inv_symm_iff SemiconjBy.inv_inv_symm_iff #align add_semiconj_by.neg_neg_symm_iff AddSemiconjBy.neg_neg_symm_iff -@[to_additive] -theorem inv_inv_symm : SemiconjBy a x y → SemiconjBy a⁻¹ y⁻¹ x⁻¹ := - inv_inv_symm_iff.2 +@[to_additive] alias ⟨_, inv_inv_symm⟩ := inv_inv_symm_iff #align semiconj_by.inv_inv_symm SemiconjBy.inv_inv_symm #align add_semiconj_by.neg_neg_symm AddSemiconjBy.neg_neg_symm end DivisionMonoid +section Group +variable [Group G] {a x y : G} + +@[to_additive (attr := simp)] lemma inv_symm_left_iff : SemiconjBy a⁻¹ y x ↔ SemiconjBy a x y := by + simp_rw [SemiconjBy, eq_mul_inv_iff_mul_eq, mul_assoc, inv_mul_eq_iff_eq_mul, eq_comm] +#align semiconj_by.inv_symm_left_iff SemiconjBy.inv_symm_left_iff +#align add_semiconj_by.neg_symm_left_iff AddSemiconjBy.neg_symm_left_iff + +@[to_additive] alias ⟨_, inv_symm_left⟩ := inv_symm_left_iff +#align semiconj_by.inv_symm_left SemiconjBy.inv_symm_left +#align add_semiconj_by.neg_symm_left AddSemiconjBy.neg_symm_left + +@[to_additive (attr := simp)] lemma inv_right_iff : SemiconjBy a x⁻¹ y⁻¹ ↔ SemiconjBy a x y := by + rw [← inv_symm_left_iff, inv_inv_symm_iff] +#align add_semiconj_by.neg_right_iff AddSemiconjBy.neg_right_iff + +@[to_additive] alias ⟨_, inv_right⟩ := inv_right_iff +#align semiconj_by.inv_right SemiconjBy.inv_right +#align add_semiconj_by.neg_right AddSemiconjBy.neg_right + +end Group end SemiconjBy diff --git a/Mathlib/Algebra/Group/Semiconj/Units.lean b/Mathlib/Algebra/Group/Semiconj/Units.lean index 065963366ee40..b2a42301446fa 100644 --- a/Mathlib/Algebra/Group/Semiconj/Units.lean +++ b/Mathlib/Algebra/Group/Semiconj/Units.lean @@ -88,38 +88,6 @@ theorem units_val_iff {a x y : Mˣ} : SemiconjBy (a : M) x y ↔ SemiconjBy a x #align add_semiconj_by.add_units_coe_iff AddSemiconjBy.addUnits_val_iff end Monoid - -section Group - -variable [Group G] {a x y : G} - -@[to_additive (attr := simp)] -theorem inv_right_iff : SemiconjBy a x⁻¹ y⁻¹ ↔ SemiconjBy a x y := - @units_inv_right_iff G _ a ⟨x, x⁻¹, mul_inv_self x, inv_mul_self x⟩ - ⟨y, y⁻¹, mul_inv_self y, inv_mul_self y⟩ -#align semiconj_by.inv_right_iff SemiconjBy.inv_right_iff -#align add_semiconj_by.neg_right_iff AddSemiconjBy.neg_right_iff - -@[to_additive] -theorem inv_right : SemiconjBy a x y → SemiconjBy a x⁻¹ y⁻¹ := - inv_right_iff.2 -#align semiconj_by.inv_right SemiconjBy.inv_right -#align add_semiconj_by.neg_right AddSemiconjBy.neg_right - -@[to_additive (attr := simp)] -theorem inv_symm_left_iff : SemiconjBy a⁻¹ y x ↔ SemiconjBy a x y := - @units_inv_symm_left_iff G _ ⟨a, a⁻¹, mul_inv_self a, inv_mul_self a⟩ _ _ -#align semiconj_by.inv_symm_left_iff SemiconjBy.inv_symm_left_iff -#align add_semiconj_by.neg_symm_left_iff AddSemiconjBy.neg_symm_left_iff - -@[to_additive] -theorem inv_symm_left : SemiconjBy a x y → SemiconjBy a⁻¹ y x := - inv_symm_left_iff.2 -#align semiconj_by.inv_symm_left SemiconjBy.inv_symm_left -#align add_semiconj_by.neg_symm_left AddSemiconjBy.neg_symm_left - -end Group - end SemiconjBy /-- `a` semiconjugates `x` to `a * x * a⁻¹`. -/ diff --git a/Mathlib/Algebra/GroupPower/Basic.lean b/Mathlib/Algebra/GroupPower/Basic.lean index 7987521fafe72..71c1aff51bd68 100644 --- a/Mathlib/Algebra/GroupPower/Basic.lean +++ b/Mathlib/Algebra/GroupPower/Basic.lean @@ -3,9 +3,9 @@ Copyright (c) 2015 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Robert Y. Lewis -/ -import Mathlib.Algebra.Group.Commute.Units +import Mathlib.Algebra.Group.Commute.Basic import Mathlib.Algebra.GroupWithZero.Defs -import Mathlib.Tactic.Convert +import Mathlib.Tactic.Common #align_import algebra.group_power.basic from "leanprover-community/mathlib"@"9b2660e1b25419042c8da10bf411aa3c67f14383" diff --git a/Mathlib/Data/Int/Basic.lean b/Mathlib/Data/Int/Basic.lean index be0dd2169bc10..d608336210a56 100644 --- a/Mathlib/Data/Int/Basic.lean +++ b/Mathlib/Data/Int/Basic.lean @@ -88,11 +88,6 @@ lemma natAbs_cast (n : ℕ) : natAbs ↑n = n := rfl @[norm_cast] protected lemma coe_nat_sub {n m : ℕ} : n ≤ m → (↑(m - n) : ℤ) = ↑m - ↑n := ofNat_sub -@[to_additive (attr := simp, norm_cast) coe_nat_zsmul] -theorem _root_.zpow_coe_nat [DivInvMonoid G] (a : G) (n : ℕ) : a ^ (Nat.cast n : ℤ) = a ^ n := - zpow_ofNat .. -#align coe_nat_zsmul coe_nat_zsmul - /-! ### Extra instances to short-circuit type class resolution These also prevent non-computable instances like `Int.normedCommRing` being used to construct From 0c2c47a251778888dfdce286658188278efe6c95 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 5 Jan 2024 11:32:32 +0000 Subject: [PATCH 345/353] feat(Algebra/QuaternionBasis): extensionality for algebra morphisms from quaternions (#9441) This result was basically already here, this just registers it with `ext`. --- Mathlib/Algebra/QuaternionBasis.lean | 21 +++++++++++++++++++ .../LinearAlgebra/CliffordAlgebra/Equivs.lean | 3 +-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Mathlib/Algebra/QuaternionBasis.lean b/Mathlib/Algebra/QuaternionBasis.lean index d1509010654ed..082d1e7a57343 100644 --- a/Mathlib/Algebra/QuaternionBasis.lean +++ b/Mathlib/Algebra/QuaternionBasis.lean @@ -180,4 +180,25 @@ def lift : Basis A c₁ c₂ ≃ (ℍ[R,c₁,c₂] →ₐ[R] A) where congr <;> simp #align quaternion_algebra.lift QuaternionAlgebra.lift +/-- Two `R`-algebra morphisms from a quaternion algebra are equal if they agree on `i` and `j`. -/ +@[ext] +theorem hom_ext ⦃f g : ℍ[R,c₁,c₂] →ₐ[R] A⦄ + (hi : f (Basis.self R).i = g (Basis.self R).i) (hj : f (Basis.self R).j = g (Basis.self R).j) : + f = g := + lift.symm.injective <| Basis.ext hi hj + end QuaternionAlgebra + +namespace Quaternion +variable {R A : Type*} [CommRing R] [Ring A] [Algebra R A] + +open QuaternionAlgebra (Basis) + +/-- Two `R`-algebra morphisms from the quaternions are equal if they agree on `i` and `j`. -/ +@[ext] +theorem hom_ext ⦃f g : ℍ[R] →ₐ[R] A⦄ + (hi : f (Basis.self R).i = g (Basis.self R).i) (hj : f (Basis.self R).j = g (Basis.self R).j) : + f = g := + QuaternionAlgebra.hom_ext hi hj + +end Quaternion diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean index 278eb81150964..0ddab49db907a 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean @@ -357,8 +357,7 @@ theorem ofQuaternion_toQuaternion (c : CliffordAlgebra (Q c₁ c₂)) : @[simp] theorem toQuaternion_comp_ofQuaternion : toQuaternion.comp ofQuaternion = AlgHom.id R ℍ[R,c₁,c₂] := by - apply QuaternionAlgebra.lift.symm.injective - ext1 <;> dsimp [QuaternionAlgebra.Basis.lift] <;> simp + ext : 1 <;> simp #align clifford_algebra_quaternion.to_quaternion_comp_of_quaternion CliffordAlgebraQuaternion.toQuaternion_comp_ofQuaternion @[simp] From cf880ce2037c087a1b55cf77afd149174ac8484c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 5 Jan 2024 11:32:33 +0000 Subject: [PATCH 346/353] =?UTF-8?q?chore:=20Move=20scalar=20compatibility?= =?UTF-8?q?=20instance=20for=20`=E2=84=A4`=20and=20`=E2=84=95`=20on=20ring?= =?UTF-8?q?s=20to=20their=20own=20files=20(#9455)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of #9411. Also corrects some instance names in the docstrings. Co-authored-by: Eric Wieser --- Mathlib.lean | 1 + .../Algebra/Subalgebra/Unitization.lean | 5 +- Mathlib/Algebra/GroupPower/Lemmas.lean | 37 +----------- Mathlib/Algebra/Lie/Free.lean | 4 +- Mathlib/Algebra/Ring/CentroidHom.lean | 1 + Mathlib/Algebra/Ring/Divisibility/Lemmas.lean | 1 + Mathlib/Data/Real/CauSeq.lean | 1 + Mathlib/GroupTheory/GroupAction/Ring.lean | 58 +++++++++++++++++++ 8 files changed, 67 insertions(+), 41 deletions(-) create mode 100644 Mathlib/GroupTheory/GroupAction/Ring.lean diff --git a/Mathlib.lean b/Mathlib.lean index f2911594599ca..776fa53d8bc26 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2197,6 +2197,7 @@ import Mathlib.GroupTheory.GroupAction.Option import Mathlib.GroupTheory.GroupAction.Pi import Mathlib.GroupTheory.GroupAction.Prod import Mathlib.GroupTheory.GroupAction.Quotient +import Mathlib.GroupTheory.GroupAction.Ring import Mathlib.GroupTheory.GroupAction.Sigma import Mathlib.GroupTheory.GroupAction.SubMulAction import Mathlib.GroupTheory.GroupAction.SubMulAction.Pointwise diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Unitization.lean b/Mathlib/Algebra/Algebra/Subalgebra/Unitization.lean index 36397a3317628..be9a753c379de 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Unitization.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Unitization.lean @@ -3,11 +3,10 @@ Copyright (c) 2023 Jireh Loreaux. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux -/ - -import Mathlib.Algebra.Algebra.NonUnitalSubalgebra -import Mathlib.Algebra.Star.Subalgebra import Mathlib.Algebra.Algebra.Unitization import Mathlib.Algebra.Star.NonUnitalSubalgebra +import Mathlib.Algebra.Star.Subalgebra +import Mathlib.GroupTheory.GroupAction.Ring /-! # Relating unital and non-unital substructures diff --git a/Mathlib/Algebra/GroupPower/Lemmas.lean b/Mathlib/Algebra/GroupPower/Lemmas.lean index 32a1e07074ae7..d70f19479e54c 100644 --- a/Mathlib/Algebra/GroupPower/Lemmas.lean +++ b/Mathlib/Algebra/GroupPower/Lemmas.lean @@ -10,6 +10,7 @@ import Mathlib.Algebra.Order.Monoid.WithTop import Mathlib.Data.Nat.Pow import Mathlib.Data.Int.Cast.Lemmas import Mathlib.Algebra.Group.Opposite +import Mathlib.GroupTheory.GroupAction.Ring #align_import algebra.group_power.lemmas from "leanprover-community/mathlib"@"a07d750983b94c530ab69a726862c2ab6802b38c" @@ -511,24 +512,6 @@ theorem nsmul_eq_mul [NonAssocSemiring R] (n : ℕ) (a : R) : n • a = n * a := #align nsmul_eq_mul nsmul_eq_mulₓ -- typeclasses do not match up exactly. -/-- Note that `AddCommMonoid.nat_smulCommClass` requires stronger assumptions on `R`. -/ -instance NonUnitalNonAssocSemiring.nat_smulCommClass [NonUnitalNonAssocSemiring R] : - SMulCommClass ℕ R R := - ⟨fun n x y => by - induction' n with n ih - · simp [zero_nsmul] - · simp_rw [succ_nsmul, smul_eq_mul, mul_add, ← smul_eq_mul, ih]⟩ -#align non_unital_non_assoc_semiring.nat_smul_comm_class NonUnitalNonAssocSemiring.nat_smulCommClass - -/-- Note that `AddCommMonoid.nat_isScalarTower` requires stronger assumptions on `R`. -/ -instance NonUnitalNonAssocSemiring.nat_isScalarTower [NonUnitalNonAssocSemiring R] : - IsScalarTower ℕ R R := - ⟨fun n x y => by - induction' n with n ih - · simp [zero_nsmul] - · simp_rw [succ_nsmul, ← ih, smul_eq_mul, add_mul]⟩ -#align non_unital_non_assoc_semiring.nat_is_scalar_tower NonUnitalNonAssocSemiring.nat_isScalarTower - @[simp, norm_cast] theorem Nat.cast_pow [Semiring R] (n m : ℕ) : (↑(n ^ m) : R) = (↑n : R) ^ m := by induction' m with m ih @@ -596,24 +579,6 @@ theorem zsmul_eq_mul' [Ring R] (a : R) (n : ℤ) : n • a = a * n := by rw [zsmul_eq_mul, (n.cast_commute a).eq] #align zsmul_eq_mul' zsmul_eq_mul' -/-- Note that `AddCommGroup.int_smulCommClass` requires stronger assumptions on `R`. -/ -instance NonUnitalNonAssocRing.int_smulCommClass [NonUnitalNonAssocRing R] : - SMulCommClass ℤ R R := - ⟨fun n x y => - match n with - | (n : ℕ) => by simp_rw [coe_nat_zsmul, smul_comm] - | -[n+1] => by simp_rw [negSucc_zsmul, smul_eq_mul, mul_neg, mul_smul_comm]⟩ -#align non_unital_non_assoc_ring.int_smul_comm_class NonUnitalNonAssocRing.int_smulCommClass - -/-- Note that `AddCommGroup.int_isScalarTower` requires stronger assumptions on `R`. -/ -instance NonUnitalNonAssocRing.int_isScalarTower [NonUnitalNonAssocRing R] : - IsScalarTower ℤ R R := - ⟨fun n x y => - match n with - | (n : ℕ) => by simp_rw [coe_nat_zsmul, smul_assoc] - | -[n+1] => by simp_rw [negSucc_zsmul, smul_eq_mul, neg_mul, smul_mul_assoc]⟩ -#align non_unital_non_assoc_ring.int_is_scalar_tower NonUnitalNonAssocRing.int_isScalarTower - theorem zsmul_int_int (a b : ℤ) : a • b = a * b := by simp #align zsmul_int_int zsmul_int_int diff --git a/Mathlib/Algebra/Lie/Free.lean b/Mathlib/Algebra/Lie/Free.lean index ed701c023455d..b2c5bfcc93ae9 100644 --- a/Mathlib/Algebra/Lie/Free.lean +++ b/Mathlib/Algebra/Lie/Free.lean @@ -3,10 +3,10 @@ Copyright (c) 2021 Oliver Nash. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Oliver Nash -/ -import Mathlib.Algebra.Lie.OfAssociative +import Mathlib.Algebra.FreeNonUnitalNonAssocAlgebra import Mathlib.Algebra.Lie.NonUnitalNonAssocAlgebra import Mathlib.Algebra.Lie.UniversalEnveloping -import Mathlib.Algebra.FreeNonUnitalNonAssocAlgebra +import Mathlib.GroupTheory.GroupAction.Ring #align_import algebra.lie.free from "leanprover-community/mathlib"@"841ac1a3d9162bf51c6327812ecb6e5e71883ac4" diff --git a/Mathlib/Algebra/Ring/CentroidHom.lean b/Mathlib/Algebra/Ring/CentroidHom.lean index 6000aaaefccb1..5fe0f91ff3ab4 100644 --- a/Mathlib/Algebra/Ring/CentroidHom.lean +++ b/Mathlib/Algebra/Ring/CentroidHom.lean @@ -5,6 +5,7 @@ Authors: Yaël Dillies, Christopher Hoskin -/ import Mathlib.Algebra.Algebra.Basic import Mathlib.Algebra.Module.Hom +import Mathlib.GroupTheory.GroupAction.Ring import Mathlib.RingTheory.NonUnitalSubsemiring.Basic import Mathlib.RingTheory.Subsemiring.Basic diff --git a/Mathlib/Algebra/Ring/Divisibility/Lemmas.lean b/Mathlib/Algebra/Ring/Divisibility/Lemmas.lean index c5bb9b1c9172d..65559b3b984b2 100644 --- a/Mathlib/Algebra/Ring/Divisibility/Lemmas.lean +++ b/Mathlib/Algebra/Ring/Divisibility/Lemmas.lean @@ -5,6 +5,7 @@ Authors: Oliver Nash -/ import Mathlib.Algebra.Ring.Divisibility.Basic import Mathlib.Data.Nat.Choose.Sum +import Mathlib.GroupTheory.GroupAction.Ring /-! # Lemmas about divisibility in rings diff --git a/Mathlib/Data/Real/CauSeq.lean b/Mathlib/Data/Real/CauSeq.lean index 6af31e21f5021..956f052341e18 100644 --- a/Mathlib/Data/Real/CauSeq.lean +++ b/Mathlib/Data/Real/CauSeq.lean @@ -9,6 +9,7 @@ import Mathlib.Algebra.Order.Group.MinMax import Mathlib.Algebra.Order.Field.Basic import Mathlib.Algebra.Ring.Pi import Mathlib.GroupTheory.GroupAction.Pi +import Mathlib.GroupTheory.GroupAction.Ring import Mathlib.Init.Align import Mathlib.Tactic.GCongr import Mathlib.Tactic.Ring diff --git a/Mathlib/GroupTheory/GroupAction/Ring.lean b/Mathlib/GroupTheory/GroupAction/Ring.lean new file mode 100644 index 0000000000000..c99e4cf635df7 --- /dev/null +++ b/Mathlib/GroupTheory/GroupAction/Ring.lean @@ -0,0 +1,58 @@ +/- +Copyright (c) 2022 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.Algebra.Ring.Defs +import Mathlib.GroupTheory.GroupAction.Defs + +/-! +# Commutativity and associativity of action of integers on rings + +This file proves that `ℕ` and `ℤ` act commutatively and associatively on (semi)rings. + +## TODO + +Those instances are in their own file only because they require much less imports than any existing +file they could go to. This is unfortunate and should be fixed by reorganising files. +-/ + +open scoped Int + +variable {α : Type*} + +/-- Note that `AddMonoid.nat_smulCommClass` requires stronger assumptions on `α`. -/ +instance NonUnitalNonAssocSemiring.nat_smulCommClass [NonUnitalNonAssocSemiring α] : + SMulCommClass ℕ α α where + smul_comm n x y := by + induction' n with n ih + · simp [zero_nsmul] + · simp_rw [succ_nsmul, smul_eq_mul, mul_add, ← smul_eq_mul, ih] +#align non_unital_non_assoc_semiring.nat_smul_comm_class NonUnitalNonAssocSemiring.nat_smulCommClass + +/-- Note that `AddCommMonoid.nat_isScalarTower` requires stronger assumptions on `α`. -/ +instance NonUnitalNonAssocSemiring.nat_isScalarTower [NonUnitalNonAssocSemiring α] : + IsScalarTower ℕ α α where + smul_assoc n x y := by + induction' n with n ih + · simp [zero_nsmul] + · simp_rw [succ_nsmul, ← ih, smul_eq_mul, add_mul] +#align non_unital_non_assoc_semiring.nat_is_scalar_tower NonUnitalNonAssocSemiring.nat_isScalarTower + +/-- Note that `AddGroup.int_smulCommClass` requires stronger assumptions on `α`. -/ +instance NonUnitalNonAssocRing.int_smulCommClass [NonUnitalNonAssocRing α] : + SMulCommClass ℤ α α where + smul_comm n x y := + match n with + | (n : ℕ) => by simp_rw [coe_nat_zsmul, smul_comm] + | -[n+1] => by simp_rw [negSucc_zsmul, smul_eq_mul, mul_neg, mul_smul_comm] +#align non_unital_non_assoc_ring.int_smul_comm_class NonUnitalNonAssocRing.int_smulCommClass + +/-- Note that `AddCommGroup.int_isScalarTower` requires stronger assumptions on `α`. -/ +instance NonUnitalNonAssocRing.int_isScalarTower [NonUnitalNonAssocRing α] : + IsScalarTower ℤ α α where + smul_assoc n x y := + match n with + | (n : ℕ) => by simp_rw [coe_nat_zsmul, smul_assoc] + | -[n+1] => by simp_rw [negSucc_zsmul, smul_eq_mul, neg_mul, smul_mul_assoc] +#align non_unital_non_assoc_ring.int_is_scalar_tower NonUnitalNonAssocRing.int_isScalarTower From cace5e5a41e710524f0925ac3495cca0592718f8 Mon Sep 17 00:00:00 2001 From: JADekker <114015169+JADekker@users.noreply.github.com> Date: Fri, 5 Jan 2024 13:07:01 +0000 Subject: [PATCH 347/353] feat : Add Gamma distribution (#9408) Add pdf, CDF and measure of Gamma distribution. Add proof that this is indeed a probability distribution. Add proofs that relate the various definitions. TODO: Refactor Probability/Distributions/Exponential.lean using calls to the results in this file. Co-authored-by: David Loeffler --- Mathlib.lean | 1 + .../SpecialFunctions/Gamma/Basic.lean | 39 +++++ .../Distributions/Exponential.lean | 20 +-- Mathlib/Probability/Distributions/Gamma.lean | 147 ++++++++++++++++++ 4 files changed, 189 insertions(+), 18 deletions(-) create mode 100644 Mathlib/Probability/Distributions/Gamma.lean diff --git a/Mathlib.lean b/Mathlib.lean index 776fa53d8bc26..6d47e1ee52f14 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2975,6 +2975,7 @@ import Mathlib.Probability.ConditionalExpectation import Mathlib.Probability.ConditionalProbability import Mathlib.Probability.Density import Mathlib.Probability.Distributions.Exponential +import Mathlib.Probability.Distributions.Gamma import Mathlib.Probability.Distributions.Gaussian import Mathlib.Probability.IdentDistrib import Mathlib.Probability.Independence.Basic diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean index e000d4540f824..7a72ab6af7875 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean @@ -389,6 +389,33 @@ theorem Gamma_conj (s : ℂ) : Gamma (conj s) = conj (Gamma s) := by rw [RingHom.map_add, RingHom.map_one] #align complex.Gamma_conj Complex.Gamma_conj +/-- Expresses the integral over `Ioi 0` of `t ^ (a - 1) * exp (-(r * t))` in terms of the Gamma +function, for complex `a`. -/ +lemma integral_cpow_mul_exp_neg_mul_Ioi {a : ℂ} {r : ℝ} (ha : 0 < a.re) (hr : 0 < r) : + ∫ (t : ℝ) in Ioi 0, t ^ (a - 1) * exp (-(r * t)) = (1 / r) ^ a * Gamma a := by + have aux : (1 / r : ℂ) ^ a = 1 / r * (1 / r) ^ (a - 1) := by + nth_rewrite 2 [← cpow_one (1 / r : ℂ)] + rw [← cpow_add _ _ (one_div_ne_zero <| ofReal_ne_zero.mpr hr.ne'), add_sub_cancel'_right] + calc + _ = ∫ (t : ℝ) in Ioi 0, (1 / r) ^ (a - 1) * (r * t) ^ (a - 1) * exp (-(r * t)) := by + refine MeasureTheory.set_integral_congr measurableSet_Ioi (fun x (hx : 0 < x) ↦ ?_) + rw [mul_cpow_ofReal_nonneg hr.le hx.le, ← mul_assoc, one_div, ← ofReal_inv, + ← mul_cpow_ofReal_nonneg (inv_pos.mpr hr).le hr.le, ← ofReal_mul r⁻¹, inv_mul_cancel hr.ne', + ofReal_one, one_cpow, one_mul] + _ = |1 / r| * ∫ (t : ℝ) in Ioi (r * 0), (1 / r) ^ (a - 1) * t ^ (a - 1) * exp (-t) := by + simp_rw [← ofReal_mul] + rw [integral_comp_mul_left_Ioi (fun x ↦ _ * x ^ (a - 1) * exp (-x)) _ hr, mul_zero, + real_smul, ← one_div] + _ = 1 / r * ∫ (t : ℝ) in Ioi 0, (1 / r) ^ (a - 1) * t ^ (a - 1) * exp (-t) := by + rw [congr_arg Ioi (mul_zero r), _root_.abs_of_nonneg (one_div_pos.mpr hr).le, ofReal_div, + ofReal_one] + _ = 1 / r * (1 / r : ℂ) ^ (a - 1) * (∫ (t : ℝ) in Ioi 0, t ^ (a - 1) * exp (-t)) := by + simp_rw [← integral_mul_left, mul_assoc] + _ = (1 / r) ^ a * Gamma a := by + rw [aux, Gamma_eq_integral ha] + congr 2 with x + rw [ofReal_exp, ofReal_neg, mul_comm] + end GammaDef /-! Now check that the `Γ` function is differentiable, wherever this makes sense. -/ @@ -554,6 +581,18 @@ theorem Gamma_nonneg_of_nonneg {s : ℝ} (hs : 0 ≤ s) : 0 ≤ Gamma s := by · rw [Gamma_zero] · exact (Gamma_pos_of_pos h).le +open Complex in +/-- Expresses the integral over `Ioi 0` of `t ^ (a - 1) * exp (-(r * t))`, for positive real `r`, +in terms of the Gamma function. -/ +lemma integral_rpow_mul_exp_neg_mul_Ioi {a r : ℝ} (ha : 0 < a) (hr : 0 < r) : + ∫ t : ℝ in Ioi 0, t ^ (a - 1) * exp (-(r * t)) = (1 / r) ^ a * Gamma a := by + rw [← ofReal_inj, ofReal_mul, ← Gamma_ofReal, ofReal_cpow (by positivity), ofReal_div] + convert integral_cpow_mul_exp_neg_mul_Ioi (by rwa [ofReal_re] : 0 < (a : ℂ).re) hr + refine _root_.integral_ofReal.symm.trans <| set_integral_congr measurableSet_Ioi (fun t ht ↦ ?_) + norm_cast + rw [← ofReal_cpow (le_of_lt ht), IsROrC.ofReal_mul] + rfl + open Lean.Meta Qq in /-- The `positivity` extension which identifies expressions of the form `Gamma a`. -/ @[positivity Gamma (_ : ℝ)] diff --git a/Mathlib/Probability/Distributions/Exponential.lean b/Mathlib/Probability/Distributions/Exponential.lean index 7f1d7e38afc03..034cb4c4b1d1d 100644 --- a/Mathlib/Probability/Distributions/Exponential.lean +++ b/Mathlib/Probability/Distributions/Exponential.lean @@ -7,6 +7,7 @@ Authors: Claus Clausen, Patrick Massot import Mathlib.Analysis.SpecialFunctions.Gaussian import Mathlib.Probability.Notation import Mathlib.Probability.Cdf +import Mathlib.Probability.Distributions.Gamma /-! # Exponential distributions over ℝ @@ -30,26 +31,9 @@ open scoped ENNReal NNReal Real open MeasureTheory Real Set Filter Topology - /-- A Lebesgue Integral from -∞ to y can be expressed as the sum of one from -∞ to 0 and 0 to x -/ -lemma lintegral_Iic_eq_lintegral_Iio_add_Icc {y z : ℝ} (f : ℝ → ℝ≥0∞) (hzy : z ≤ y) : - ∫⁻ x in Iic y, f x = (∫⁻ x in Iio z, f x) + ∫⁻ x in Icc z y, f x := by - rw [← Iio_union_Icc_eq_Iic hzy, lintegral_union measurableSet_Icc] - rw [Set.disjoint_iff] - rintro x ⟨h1 : x < _, h2, _⟩ - linarith - lemma lintegral_eq_lintegral_Ici_add_Iio (f : ℝ → ℝ≥0∞) (c : ℝ) : ∫⁻ x, f x = (∫⁻ x in Ici c, f x) + ∫⁻ x in Iio c, f x := by - have union : univ = {x : ℝ | x ≥ c} ∪ {x : ℝ | x < c} := by - ext x; simp [le_or_lt] - calc - ∫⁻ x, f x = ∫⁻ x in univ, f x ∂volume := (set_lintegral_univ f).symm - _ = ∫⁻ x in {x | x ≥ c} ∪ {x | x < c} , f x ∂volume := by rw [← union] - _ = _ := by - apply lintegral_union (isOpen_gt' c).measurableSet - rw [Set.disjoint_iff] - rintro x ⟨hxge : x ≥ _, hxlt : x < _⟩ - linarith + rw [← lintegral_add_compl f (measurableSet_Ici (a := c)), compl_Ici] namespace ProbabilityTheory diff --git a/Mathlib/Probability/Distributions/Gamma.lean b/Mathlib/Probability/Distributions/Gamma.lean new file mode 100644 index 0000000000000..8ab6181d25d5b --- /dev/null +++ b/Mathlib/Probability/Distributions/Gamma.lean @@ -0,0 +1,147 @@ +/- +Copyright (c) 2024 Josha Dekker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Josha Dekker +-/ + +import Mathlib.Analysis.SpecialFunctions.Gaussian +import Mathlib.Probability.Notation +import Mathlib.Probability.Cdf +import Mathlib.Analysis.SpecialFunctions.Gamma.Basic + +/-! # Gamma distributions over ℝ + +Define the Gamma Measure over the Reals + +## Main definitions +* `gammaPdfReal`: the function `a r x ↦ r ^ a / (Gamma a) * x ^ (a-1) * exp (-(r * x))` + for `0 ≤ x` or `0` else, which is the probability density function of a Gamma distribution with + shape `a` and rate `r` (when `ha : 0 < a ` and `hr : 0 < r`). +* `gammaPdf`: `ℝ≥0∞`-valued pdf, + `gammaPdf a r = ENNReal.ofReal (gammaPdfReal a r)`. +* `gammaMeasure`: a Gamma measure on `ℝ`, parametrized by its shape `a` and rate `r`. +* `gammaCdfReal`: the CDF given by the definition of CDF in `ProbabilityTheory.Cdf` applied to the + Gamma measure. +-/ + +open scoped ENNReal NNReal + +open MeasureTheory Real Set Filter Topology + +/-- A Lebesgue Integral from -∞ to y can be expressed as the sum of one from -∞ to 0 and 0 to x -/ +lemma lintegral_Iic_eq_lintegral_Iio_add_Icc {y z : ℝ} (f : ℝ → ℝ≥0∞) (hzy : z ≤ y) : + ∫⁻ x in Iic y, f x = (∫⁻ x in Iio z, f x) + ∫⁻ x in Icc z y, f x := by + rw [← Iio_union_Icc_eq_Iic hzy, lintegral_union measurableSet_Icc] + rw [Set.disjoint_iff] + rintro x ⟨h1 : x < _, h2, _⟩ + linarith + +namespace ProbabilityTheory + +section GammaPdf + +/-- The pdf of the gamma distribution depending on its scale and rate-/ +noncomputable +def gammaPdfReal (a r x : ℝ) : ℝ := + if 0 ≤ x then r ^ a / (Gamma a) * x ^ (a-1) * exp (-(r * x)) else 0 + +/-- The pdf of the Gamma distribution, as a function valued in `ℝ≥0∞` -/ +noncomputable +def gammaPdf (a r x : ℝ) : ℝ≥0∞ := + ENNReal.ofReal (gammaPdfReal a r x) + +lemma gammaPdf_eq (a r x : ℝ) : + gammaPdf a r x = ENNReal.ofReal (if 0 ≤ x then + r ^ a / (Gamma a) * x ^ (a-1) * exp (-(r * x)) else 0) := rfl + +lemma gammaPdf_of_neg {a r x : ℝ} (hx : x < 0) : gammaPdf a r x = 0 := by + simp only [gammaPdf_eq, if_neg (not_le.mpr hx), ENNReal.ofReal_zero] + +lemma gammaPdf_of_nonneg {a r x : ℝ} (hx : 0 ≤ x) : + gammaPdf a r x = ENNReal.ofReal (r ^ a / (Gamma a) * x ^ (a-1) * exp (-(r * x))) := by + simp only [gammaPdf_eq, if_pos hx] + +/-- the Lebesgue integral of the Gamma pdf over nonpositive reals equals 0 -/ +lemma lintegral_gammaPdf_of_nonpos {x a r : ℝ} (hx : x ≤ 0) : + ∫⁻ y in Iio x, gammaPdf a r y = 0 := by + rw [set_lintegral_congr_fun (g := fun _ ↦ 0) measurableSet_Iio] + · rw [lintegral_zero, ← ENNReal.ofReal_zero] + · simp only [gammaPdf_eq, ge_iff_le, ENNReal.ofReal_eq_zero] + apply ae_of_all _ fun a (_ : a < _) ↦ by rw [if_neg (by linarith)] + +/-- The gamma pdf is measurable. -/ +lemma measurable_gammaPdfReal (a r : ℝ) : Measurable (gammaPdfReal a r) := + Measurable.ite measurableSet_Ici (((measurable_id'.pow_const _).const_mul _).mul + (measurable_id'.const_mul _).neg.exp) measurable_const + +/-- the Gamma pdf is positive for all positive reals -/ +lemma gammaPdfReal_pos {x a r : ℝ} (ha : 0 < a) (hr : 0 < r) (hx : 0 < x) : + 0 < gammaPdfReal a r x := by + simp only [gammaPdfReal, if_pos hx.le] + positivity + +/-- The Gamma pdf is nonnegative -/ +lemma gammaPdfReal_nonneg {a r : ℝ} (ha : 0 < a) (hr : 0 < r) (x : ℝ) : + 0 ≤ gammaPdfReal a r x := by + unfold gammaPdfReal + split_ifs <;> positivity + +open Measure + +/-- The pdf of the Gamma distribution integrates to 1 -/ +@[simp] +lemma lintegral_gammaPdf_eq_one {a r : ℝ} (ha : 0 < a) (hr : 0 < r) : + ∫⁻ x, gammaPdf a r x = 1 := by + have leftSide : ∫⁻ x in Iio 0, gammaPdf a r x = 0 := by + rw [set_lintegral_congr_fun measurableSet_Iio + (ae_of_all _ (fun x (hx : x < 0) ↦ gammaPdf_of_neg hx)), lintegral_zero] + have rightSide : ∫⁻ x in Ici 0, gammaPdf a r x = + ∫⁻ x in Ici 0, ENNReal.ofReal (r ^ a / Gamma a * x ^ (a - 1) * exp (-(r * x))) := + set_lintegral_congr_fun measurableSet_Ici (ae_of_all _ (fun _ ↦ gammaPdf_of_nonneg)) + rw [← ENNReal.toReal_eq_one_iff, ← lintegral_add_compl _ measurableSet_Ici, compl_Ici, + leftSide, rightSide, add_zero, ← integral_eq_lintegral_of_nonneg_ae] + · simp_rw [integral_Ici_eq_integral_Ioi, mul_assoc] + rw [integral_mul_left, integral_rpow_mul_exp_neg_mul_Ioi ha hr, div_mul_eq_mul_div, + ← mul_assoc, mul_div_assoc, div_self (Gamma_pos_of_pos ha).ne', mul_one, + div_rpow zero_le_one hr.le, one_rpow, mul_one_div, div_self (rpow_pos_of_pos hr _).ne'] + · rw [EventuallyLE, ae_restrict_iff' measurableSet_Ici] + exact ae_of_all _ (fun x (hx : 0 ≤ x) ↦ by positivity) + · apply (measurable_gammaPdfReal a r).aestronglyMeasurable.congr + refine (ae_restrict_iff' measurableSet_Ici).mpr <| ae_of_all _ fun x (hx : 0 ≤ x) ↦ ?_ + simp_rw [gammaPdfReal, eq_true_intro hx, ite_true] + +end GammaPdf + +open MeasureTheory + +/-- Measure defined by the Gamma distribution -/ +noncomputable +def gammaMeasure (a r : ℝ) : Measure ℝ := + volume.withDensity (gammaPdf a r) + +lemma isProbabilityMeasureGamma {a r : ℝ} (ha : 0 < a) (hr : 0 < r) : + IsProbabilityMeasure (gammaMeasure a r) where + measure_univ := by simp [gammaMeasure, lintegral_gammaPdf_eq_one ha hr] + +section GammaCdf + +/-- CDF of the Gamma distribution -/ +noncomputable +def gammaCdfReal (a r : ℝ) : StieltjesFunction := + cdf (gammaMeasure a r) + +lemma gammaCdfReal_eq_integral {a r : ℝ} (ha : 0 < a) (hr : 0 < r) (x : ℝ) : + gammaCdfReal a r x = ∫ x in Iic x, gammaPdfReal a r x := by + have : IsProbabilityMeasure (gammaMeasure a r) := isProbabilityMeasureGamma ha hr + rw [gammaCdfReal, cdf_eq_toReal, gammaMeasure, withDensity_apply _ measurableSet_Iic] + refine (integral_eq_lintegral_of_nonneg_ae ?_ ?_).symm + · exact ae_of_all _ fun b ↦ by simp only [Pi.zero_apply, gammaPdfReal_nonneg ha hr] + · exact (measurable_gammaPdfReal a r).aestronglyMeasurable.restrict + +lemma gammaCdfReal_eq_lintegral {a r : ℝ} (ha : 0 < a) (hr : 0 < r) (x : ℝ) : + gammaCdfReal a r x = ENNReal.toReal (∫⁻ x in Iic x, gammaPdf a r x) := by + have : IsProbabilityMeasure (gammaMeasure a r) := isProbabilityMeasureGamma ha hr + simp only [gammaPdf, gammaCdfReal, cdf_eq_toReal] + simp only [gammaMeasure, measurableSet_Iic, withDensity_apply, gammaPdf] + +end GammaCdf From e3d1c7ac9287a32cf97e7344cf6a2fa3643a55c7 Mon Sep 17 00:00:00 2001 From: Xavier Xarles Date: Fri, 5 Jan 2024 13:39:42 +0000 Subject: [PATCH 348/353] feat(Mathlib/Algebra/Ring/Basic): Subsingleton, NoZeroDivisors and IsDomain (#9407) Added some results relating NoZeroDivisors and IsDomain for Ring. Co-authored-by: Xavier Xarles <56635243+XavierXarles@users.noreply.github.com> Co-authored-by: Eric Wieser --- Mathlib/Algebra/Ring/Basic.lean | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Mathlib/Algebra/Ring/Basic.lean b/Mathlib/Algebra/Ring/Basic.lean index bfd8bfba3da46..42bf56eebf1bb 100644 --- a/Mathlib/Algebra/Ring/Basic.lean +++ b/Mathlib/Algebra/Ring/Basic.lean @@ -188,6 +188,11 @@ instance (priority := 100) NoZeroDivisors.to_isCancelMulZero [Ring α] [NoZeroDi exact sub_eq_zero.1 ((eq_zero_or_eq_zero_of_mul_eq_zero h).resolve_right hb) } #align no_zero_divisors.to_is_cancel_mul_zero NoZeroDivisors.to_isCancelMulZero +/-- In a ring, `IsCancelMulZero` and `NoZeroDivisors` are equivalent. -/ +lemma isCancelMulZero_iff_noZeroDivisors [Ring α] : + IsCancelMulZero α ↔ NoZeroDivisors α := + ⟨fun _ => IsRightCancelMulZero.to_noZeroDivisors _, fun _ => inferInstance⟩ + lemma NoZeroDivisors.to_isDomain [Ring α] [h : Nontrivial α] [NoZeroDivisors α] : IsDomain α := { NoZeroDivisors.to_isCancelMulZero α, h with .. } @@ -198,4 +203,29 @@ instance (priority := 100) IsDomain.to_noZeroDivisors [Ring α] [IsDomain α] : IsRightCancelMulZero.to_noZeroDivisors α #align is_domain.to_no_zero_divisors IsDomain.to_noZeroDivisors +instance Subsingleton.to_isCancelMulZero [Mul α] [Zero α] [Subsingleton α] : IsCancelMulZero α where + mul_right_cancel_of_ne_zero hb := (hb <| Subsingleton.eq_zero _).elim + mul_left_cancel_of_ne_zero hb := (hb <| Subsingleton.eq_zero _).elim + +instance Subsingleton.to_noZeroDivisors [Mul α] [Zero α] [Subsingleton α] : NoZeroDivisors α where + eq_zero_or_eq_zero_of_mul_eq_zero _ := .inl (Subsingleton.eq_zero _) + +lemma isDomain_iff_cancelMulZero_and_nontrivial [Semiring α] : + IsDomain α ↔ IsCancelMulZero α ∧ Nontrivial α := + ⟨fun _ => ⟨inferInstance, inferInstance⟩, fun ⟨_, _⟩ => {}⟩ + +lemma isCancelMulZero_iff_isDomain_or_subsingleton [Semiring α] : + IsCancelMulZero α ↔ IsDomain α ∨ Subsingleton α := by + refine ⟨fun t ↦ ?_, fun h ↦ h.elim (fun _ ↦ inferInstance) (fun _ ↦ inferInstance)⟩ + rw [or_iff_not_imp_right, not_subsingleton_iff_nontrivial] + exact fun _ ↦ {} + +lemma isDomain_iff_noZeroDivisors_and_nontrivial [Ring α] : + IsDomain α ↔ NoZeroDivisors α ∧ Nontrivial α := by + rw [← isCancelMulZero_iff_noZeroDivisors, isDomain_iff_cancelMulZero_and_nontrivial] + +lemma noZeroDivisors_iff_isDomain_or_subsingleton [Ring α] : + NoZeroDivisors α ↔ IsDomain α ∨ Subsingleton α := by + rw [← isCancelMulZero_iff_noZeroDivisors, isCancelMulZero_iff_isDomain_or_subsingleton] + end NoZeroDivisors From 710ecf07b6341bb7c2eaaa859d11eb203908074e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Fri, 5 Jan 2024 14:50:13 +0000 Subject: [PATCH 349/353] feat(Algebra/Homology): left shifting cochains (#9054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR, we study the behaviour of cochains (of the complex of homomorphisms) with respect to shifts on the source. In particular, we obtain an additive equivalence `leftShiftAddEquiv K L n a n' h : Cochain K L n ≃+ Cochain K⟦a⟧ L n'` when `h : n + a = n'`. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- Mathlib/Algebra/GroupPower/NegOnePow.lean | 9 + .../HomotopyCategory/HomComplexShift.lean | 310 +++++++++++++++++- 2 files changed, 314 insertions(+), 5 deletions(-) diff --git a/Mathlib/Algebra/GroupPower/NegOnePow.lean b/Mathlib/Algebra/GroupPower/NegOnePow.lean index e3de679ff6df6..fbc302478a720 100644 --- a/Mathlib/Algebra/GroupPower/NegOnePow.lean +++ b/Mathlib/Algebra/GroupPower/NegOnePow.lean @@ -86,4 +86,13 @@ lemma negOnePow_eq_iff (n₁ n₂ : ℤ) : Int.even_iff_not_odd, Int.even_iff_not_odd] tauto +@[simp] +lemma negOnePow_mul_self (n : ℤ) : (n * n).negOnePow = n.negOnePow := by + suffices Even (n * (n - 1)) by + simpa [mul_sub, mul_one, negOnePow_eq_iff] using this + rw [even_mul] + by_cases h : Even (n - 1) + · exact Or.inr h + · exact Or.inl (by simpa using Int.even_add_one.2 h) + end Int diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexShift.lean b/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexShift.lean index 12d6df70373be..d0103b2dbd1c4 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexShift.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexShift.lean @@ -15,10 +15,11 @@ study how these cochains behave with respect to the shift on the complexes `K` and `L`. When `n`, `a`, `n'` are integers such that `h : n' + a = n`, -we obtain `rightShiftAddEquiv K L n a n' h : Cochain K L n ≃+ Cochain K L⟦a⟧ n'`. -This definition does not involve signs, but the analogous definition for -the shift on the first variable `K` shall involve signs (TODO), as we follow the -conventions appearing in the introduction of +we obtain `rightShiftAddEquiv K L n a n' h : Cochain K L n ≃+ Cochain K (L⟦a⟧) n'`. +This definition does not involve signs, but the analogous definition +of `leftShiftAddEquiv K L n a n' h' : Cochain K L n ≃+ Cochain (K⟦a⟧) L n'` +when `h' : n + a = n'` does involve signs, as we follow the conventions +appearing in the introduction of [Brian Conrad's book *Grothendieck duality and base change*][conrad2000]. ## References @@ -52,6 +53,20 @@ lemma rightShift_v (a n' : ℤ) (hn' : n' + a = n) (p q : ℤ) (hpq : p + n' = q dsimp only [rightShift] simp only [mk_v] +/-- The map `Cochain K L n → Cochain (K⟦a⟧) L n'` when `n + a = n'`. -/ +def leftShift (a n' : ℤ) (hn' : n + a = n') : Cochain (K⟦a⟧) L n' := + Cochain.mk (fun p q hpq => (a * n' + ((a * (a-1))/2)).negOnePow • + (K.shiftFunctorObjXIso a p (p + a) rfl).hom ≫ γ.v (p+a) q (by linarith)) + +lemma leftShift_v (a n' : ℤ) (hn' : n + a = n') (p q : ℤ) (hpq : p + n' = q) + (p' : ℤ) (hp' : p' + n = q) : + (γ.leftShift a n' hn').v p q hpq = (a * n' + ((a * (a - 1))/2)).negOnePow • + (K.shiftFunctorObjXIso a p p' + (by rw [← add_left_inj n, hp', add_assoc, add_comm a, hn', hpq])).hom ≫ γ.v p' q hp' := by + obtain rfl : p' = p + a := by linarith + dsimp only [leftShift] + simp only [mk_v] + /-- The map `Cochain K (L⟦a⟧) n' → Cochain K L n` when `n' + a = n`. -/ def rightUnshift {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) : Cochain K L n := @@ -66,6 +81,37 @@ lemma rightUnshift_v {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : dsimp only [rightUnshift] simp only [mk_v] +/-- The map `Cochain (K⟦a⟧) L n' → Cochain K L n` when `n + a = n'`. -/ +def leftUnshift {n' a : ℤ} (γ : Cochain (K⟦a⟧) L n') (n : ℤ) (hn : n + a = n') : + Cochain K L n := + Cochain.mk (fun p q hpq => (a * n' + ((a * (a-1))/2)).negOnePow • + (K.shiftFunctorObjXIso a (p - a) p (by linarith)).inv ≫ γ.v (p-a) q (by linarith)) + +lemma leftUnshift_v {n' a : ℤ} (γ : Cochain (K⟦a⟧) L n') (n : ℤ) (hn : n + a = n') + (p q : ℤ) (hpq : p + n = q) (p' : ℤ) (hp' : p' + n' = q) : + (γ.leftUnshift n hn).v p q hpq = (a * n' + ((a * (a-1))/2)).negOnePow • + (K.shiftFunctorObjXIso a p' p (by linarith)).inv ≫ γ.v p' q (by linarith) := by + obtain rfl : p' = p - a := by linarith + rfl + +/-- The map `Cochain K L n → Cochain (K⟦a⟧) (L⟦a⟧) n`. -/ +def shift (a : ℤ) : Cochain (K⟦a⟧) (L⟦a⟧) n := + Cochain.mk (fun p q hpq => (K.shiftFunctorObjXIso a p _ rfl).hom ≫ + γ.v (p + a) (q + a) (by linarith) ≫ (L.shiftFunctorObjXIso a q _ rfl).inv) + +lemma shift_v (a : ℤ) (p q : ℤ) (hpq : p + n = q) (p' q' : ℤ) + (hp' : p' = p + a) (hq' : q' = q + a) : + (γ.shift a).v p q hpq = (K.shiftFunctorObjXIso a p p' hp').hom ≫ + γ.v p' q' (by rw [hp', hq', ← hpq, add_assoc, add_comm a, add_assoc]) ≫ + (L.shiftFunctorObjXIso a q q' hq').inv := by + subst hp' hq' + rfl + +lemma shift_v' (a : ℤ) (p q : ℤ) (hpq : p + n = q) : + (γ.shift a).v p q hpq = γ.v (p + a) (q + a) (by linarith) := by + simp only [shift_v γ a p q hpq _ _ rfl rfl, shiftFunctor_obj_X, shiftFunctorObjXIso, + HomologicalComplex.XIsoOfEq_rfl, Iso.refl_hom, Iso.refl_inv, comp_id, id_comp] + @[simp] lemma rightUnshift_rightShift (a n' : ℤ) (hn' : n' + a = n) : (γ.rightShift a n' hn').rightUnshift n hn' = γ := by @@ -82,6 +128,22 @@ lemma rightShift_rightUnshift {a n' : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : γ.rightUnshift_v n hn' p (p + n) rfl q hpq, shiftFunctorObjXIso, assoc, Iso.hom_inv_id, comp_id] +@[simp] +lemma leftUnshift_leftShift (a n' : ℤ) (hn' : n + a = n') : + (γ.leftShift a n' hn').leftUnshift n hn' = γ := by + ext p q hpq + rw [(γ.leftShift a n' hn').leftUnshift_v n hn' p q hpq (q-n') (by linarith), + γ.leftShift_v a n' hn' (q-n') q (by linarith) p hpq, Linear.comp_units_smul, + Iso.inv_hom_id_assoc, smul_smul, Int.units_mul_self, one_smul] + +@[simp] +lemma leftShift_leftUnshift {a n' : ℤ} (γ : Cochain (K⟦a⟧) L n') (n : ℤ) (hn' : n + a = n') : + (γ.leftUnshift n hn').leftShift a n' hn' = γ := by + ext p q hpq + rw [(γ.leftUnshift n hn').leftShift_v a n' hn' p q hpq (q-n) (by linarith), + γ.leftUnshift_v n hn' (q-n) q (by linarith) p hpq, Linear.comp_units_smul, smul_smul, + Iso.hom_inv_id_assoc, Int.units_mul_self, one_smul] + @[simp] lemma rightShift_add (a n' : ℤ) (hn' : n' + a = n) : (γ₁ + γ₂).rightShift a n' hn' = γ₁.rightShift a n' hn' + γ₂.rightShift a n' hn' := by @@ -89,6 +151,19 @@ lemma rightShift_add (a n' : ℤ) (hn' : n' + a = n) : dsimp simp only [rightShift_v _ a n' hn' p q hpq _ rfl, add_v, add_comp] +@[simp] +lemma leftShift_add (a n' : ℤ) (hn' : n + a = n') : + (γ₁ + γ₂).leftShift a n' hn' = γ₁.leftShift a n' hn' + γ₂.leftShift a n' hn' := by + ext p q hpq + dsimp + simp only [leftShift_v _ a n' hn' p q hpq (p + a) (by linarith), add_v, comp_add, smul_add] + +@[simp] +lemma shift_add (a : ℤ) : + (γ₁ + γ₂).shift a = γ₁.shift a + γ₂.shift a:= by + ext p q hpq + simp [shift_v'] + variable (K L) /-- The additive equivalence `Cochain K L n ≃+ Cochain K L⟦a⟧ n'` when `n' + a = n`. -/ @@ -101,7 +176,22 @@ def rightShiftAddEquiv (n a n' : ℤ) (hn' : n' + a = n) : right_inv γ := by simp map_add' γ γ' := by simp -variable {K L} +/-- The additive equivalence `Cochain K L n ≃+ Cochain (K⟦a⟧) L n'` when `n + a = n'`. -/ +@[simps] +def leftShiftAddEquiv (n a n' : ℤ) (hn' : n + a = n') : + Cochain K L n ≃+ Cochain (K⟦a⟧) L n' where + toFun γ := γ.leftShift a n' hn' + invFun γ := γ.leftUnshift n hn' + left_inv γ := by simp + right_inv γ := by simp + map_add' γ γ' := by simp + +/-- The additive map `Cochain K L n →+ Cochain (K⟦a⟧) (L⟦a⟧) n`. -/ +@[simps!] +def shiftAddHom (n a : ℤ) : Cochain K L n →+ Cochain (K⟦a⟧) (L⟦a⟧) n := + AddMonoidHom.mk' (fun γ => γ.shift a) (by simp) + +variable (n) @[simp] lemma rightShift_zero (a n' : ℤ) (hn' : n' + a = n) : @@ -115,6 +205,26 @@ lemma rightUnshift_zero (a n' : ℤ) (hn' : n' + a = n) : change (rightShiftAddEquiv K L n a n' hn').symm 0 = 0 apply _root_.map_zero +@[simp] +lemma leftShift_zero (a n' : ℤ) (hn' : n + a = n') : + (0 : Cochain K L n).leftShift a n' hn' = 0 := by + change leftShiftAddEquiv K L n a n' hn' 0 = 0 + apply _root_.map_zero + +@[simp] +lemma leftUnshift_zero (a n' : ℤ) (hn' : n + a = n') : + (0 : Cochain (K⟦a⟧) L n').leftUnshift n hn' = 0 := by + change (leftShiftAddEquiv K L n a n' hn').symm 0 = 0 + apply _root_.map_zero + +@[simp] +lemma shift_zero (a : ℤ) : + (0 : Cochain K L n).shift a = 0 := by + change shiftAddHom K L n a 0 = 0 + apply _root_.map_zero + +variable {K L n} + @[simp] lemma rightShift_neg (a n' : ℤ) (hn' : n' + a = n) : (-γ).rightShift a n' hn' = -γ.rightShift a n' hn' := by @@ -127,12 +237,36 @@ lemma rightUnshift_neg {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn change (rightShiftAddEquiv K L n a n' hn).symm (-γ) = _ apply _root_.map_neg +@[simp] +lemma leftShift_neg (a n' : ℤ) (hn' : n + a = n') : + (-γ).leftShift a n' hn' = -γ.leftShift a n' hn' := by + change leftShiftAddEquiv K L n a n' hn' (-γ) = _ + apply _root_.map_neg + +@[simp] +lemma leftUnshift_neg {n' a : ℤ} (γ : Cochain (K⟦a⟧) L n') (n : ℤ) (hn : n + a = n') : + (-γ).leftUnshift n hn = -γ.leftUnshift n hn := by + change (leftShiftAddEquiv K L n a n' hn).symm (-γ) = _ + apply _root_.map_neg + +@[simp] +lemma shift_neg (a : ℤ) : + (-γ).shift a = -γ.shift a := by + change shiftAddHom K L n a (-γ) = _ + apply _root_.map_neg + @[simp] lemma rightUnshift_add {n' a : ℤ} (γ₁ γ₂ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) : (γ₁ + γ₂).rightUnshift n hn = γ₁.rightUnshift n hn + γ₂.rightUnshift n hn := by change (rightShiftAddEquiv K L n a n' hn).symm (γ₁ + γ₂) = _ apply _root_.map_add +@[simp] +lemma leftUnshift_add {n' a : ℤ} (γ₁ γ₂ : Cochain (K⟦a⟧) L n') (n : ℤ) (hn : n + a = n') : + (γ₁ + γ₂).leftUnshift n hn = γ₁.leftUnshift n hn + γ₂.leftUnshift n hn := by + change (leftShiftAddEquiv K L n a n' hn).symm (γ₁ + γ₂) = _ + apply _root_.map_add + @[simp] lemma rightShift_smul (a n' : ℤ) (hn' : n' + a = n) (x : R) : (x • γ).rightShift a n' hn' = x • γ.rightShift a n' hn' := by @@ -140,6 +274,20 @@ lemma rightShift_smul (a n' : ℤ) (hn' : n' + a = n) (x : R) : dsimp simp only [rightShift_v _ a n' hn' p q hpq _ rfl, smul_v, Linear.smul_comp] +@[simp] +lemma leftShift_smul (a n' : ℤ) (hn' : n + a = n') (x : R) : + (x • γ).leftShift a n' hn' = x • γ.leftShift a n' hn' := by + ext p q hpq + dsimp + simp only [leftShift_v _ a n' hn' p q hpq (p + a) (by linarith), smul_v, Linear.comp_smul, + smul_comm x] + +@[simp] +lemma shift_smul (a : ℤ) (x : R) : + (x • γ).shift a = x • (γ.shift a) := by + ext p q hpq + simp [shift_v'] + variable (K L R) /-- The linear equivalence `Cochain K L n ≃+ Cochain K L⟦a⟧ n'` when `n' + a = n` and @@ -149,6 +297,20 @@ def rightShiftLinearEquiv (n a n' : ℤ) (hn' : n' + a = n) : Cochain K L n ≃ₗ[R] Cochain K (L⟦a⟧) n' := (rightShiftAddEquiv K L n a n' hn').toLinearEquiv (fun x γ => by simp) +/-- The additive equivalence `Cochain K L n ≃+ Cochain (K⟦a⟧) L n'` when `n + a = n'` and +the category is `R`-linear. -/ +@[simps!] +def leftShiftLinearEquiv (n a n' : ℤ) (hn : n + a = n') : + Cochain K L n ≃ₗ[R] Cochain (K⟦a⟧) L n' := + (leftShiftAddEquiv K L n a n' hn).toLinearEquiv (fun x γ => by simp) + +/-- The linear map `Cochain K L n ≃+ Cochain (K⟦a⟧) (L⟦a⟧) n` when the category is `R`-linear. -/ +@[simps!] +def shiftLinearMap (n a : ℤ) : + Cochain K L n →ₗ[R] Cochain (K⟦a⟧) (L⟦a⟧) n where + toAddHom := shiftAddHom K L n a + map_smul' _ _ := by simp + variable {K L R} @[simp] @@ -156,6 +318,17 @@ lemma rightShift_units_smul (a n' : ℤ) (hn' : n' + a = n) (x : Rˣ) : (x • γ).rightShift a n' hn' = x • γ.rightShift a n' hn' := by apply rightShift_smul +@[simp] +lemma leftShift_units_smul (a n' : ℤ) (hn' : n + a = n') (x : Rˣ) : + (x • γ).leftShift a n' hn' = x • γ.leftShift a n' hn' := by + apply leftShift_smul + +@[simp] +lemma shift_units_smul (a : ℤ) (x : Rˣ) : + (x • γ).shift a = x • (γ.shift a) := by + ext p q hpq + simp [shift_v'] + @[simp] lemma rightUnshift_smul {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn : n' + a = n) (x : R) : (x • γ).rightUnshift n hn = x • γ.rightUnshift n hn := by @@ -168,6 +341,18 @@ lemma rightUnshift_units_smul {n' a : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : (x • γ).rightUnshift n hn = x • γ.rightUnshift n hn := by apply rightUnshift_smul +@[simp] +lemma leftUnshift_smul {n' a : ℤ} (γ : Cochain (K⟦a⟧) L n') (n : ℤ) (hn : n + a = n') (x : R) : + (x • γ).leftUnshift n hn = x • γ.leftUnshift n hn := by + change (leftShiftLinearEquiv R K L n a n' hn).symm (x • γ) = _ + apply map_smul + +@[simp] +lemma leftUnshift_units_smul {n' a : ℤ} (γ : Cochain (K⟦a⟧) L n') (n : ℤ) + (hn : n + a = n') (x : Rˣ) : + (x • γ).leftUnshift n hn = x • γ.leftUnshift n hn := by + apply leftUnshift_smul + lemma rightUnshift_comp {m : ℤ} {a : ℤ} (γ' : Cochain L (M⟦a⟧) m) {nm : ℤ} (hnm : n + m = nm) (nm' : ℤ) (hnm' : nm + a = nm') (m' : ℤ) (hm' : m + a = m') : (γ.comp γ' hnm).rightUnshift nm' hnm' = @@ -178,6 +363,27 @@ lemma rightUnshift_comp {m : ℤ} {a : ℤ} (γ' : Cochain L (M⟦a⟧) m) {nm : comp_v _ _ (show n + m' = nm' by linarith) p (p + n) q (by linarith) (by linarith), γ'.rightUnshift_v m' hm' (p + n) q (by linarith) (p + n + m) rfl, assoc] +lemma leftShift_comp (a n' : ℤ) (hn' : n + a = n') {m t t' : ℤ} (γ' : Cochain L M m) + (h : n + m = t) (ht' : t + a = t') : + (γ.comp γ' h).leftShift a t' ht' = (a * m).negOnePow • (γ.leftShift a n' hn').comp γ' + (by rw [← ht', ← h, ← hn', add_assoc, add_comm a, add_assoc]) := by + ext p q hpq + have h' : n' + m = t' := by linarith + dsimp + simp only [Cochain.comp_v _ _ h' p (p + n') q rfl (by linarith), + γ.leftShift_v a n' hn' p (p + n') rfl (p + a) (by linarith), + (γ.comp γ' h).leftShift_v a t' (by linarith) p q hpq (p + a) (by linarith), + smul_smul, Linear.units_smul_comp, assoc, Int.negOnePow_add, ← mul_assoc, ← h', + comp_v _ _ h (p + a) (p + n') q (by linarith) (by linarith)] + congr 2 + rw [add_comm n', mul_add, Int.negOnePow_add] + +@[simp] +lemma leftShift_comp_zero_cochain (a n' : ℤ) (hn' : n + a = n') (γ' : Cochain L M 0) : + (γ.comp γ' (add_zero n)).leftShift a n' hn' = + (γ.leftShift a n' hn').comp γ' (add_zero n') := by + rw [leftShift_comp γ a n' hn' γ' (add_zero _) hn', mul_zero, Int.negOnePow_zero, one_smul] + lemma δ_rightShift (a n' m' : ℤ) (hn' : n' + a = n) (m : ℤ) (hm' : m' + a = m) : δ n' m' (γ.rightShift a n' hn') = a.negOnePow • (δ n m γ).rightShift a m' hm' := by by_cases hnm : n + 1 = m @@ -207,6 +413,78 @@ lemma δ_rightUnshift {a n' : ℤ} (γ : Cochain K (L⟦a⟧) n') (n : ℤ) (hn simp only [rightUnshift_rightShift, γ'.δ_rightShift a n' m' hn m hm', rightUnshift_units_smul, smul_smul, Int.units_mul_self, one_smul] +lemma δ_leftShift (a n' m' : ℤ) (hn' : n + a = n') (m : ℤ) (hm' : m + a = m') : + δ n' m' (γ.leftShift a n' hn') = a.negOnePow • (δ n m γ).leftShift a m' hm' := by + by_cases hnm : n + 1 = m + · have hnm' : n' + 1 = m' := by linarith + ext p q hpq + dsimp + rw [(δ n m γ).leftShift_v a m' hm' p q hpq (p+a) (by linarith), + δ_v n m hnm _ (p+a) q (by linarith) (p+n') (p+1+a) (by linarith) (by linarith), + δ_v n' m' hnm' _ p q hpq (p+n') (p+1) (by linarith) rfl, + γ.leftShift_v a n' hn' p (p+n') rfl (p+a) (by linarith), + γ.leftShift_v a n' hn' (p+1) q (by linarith) (p+1+a) (by linarith)] + simp only [shiftFunctor_obj_X, shiftFunctorObjXIso, HomologicalComplex.XIsoOfEq_rfl, + Iso.refl_hom, id_comp, Linear.units_smul_comp, shiftFunctor_obj_d', + Linear.comp_units_smul, smul_add, smul_smul] + congr 2 + · rw [← hnm', add_comm n', mul_add, mul_one] + simp only [Int.negOnePow_add, ← mul_assoc, Int.units_mul_self, one_mul] + · simp only [← Int.negOnePow_add, ← hn', ← hm', ← hnm] + congr 1 + linarith + · have hnm' : ¬ n' + 1 = m' := fun _ => hnm (by linarith) + rw [δ_shape _ _ hnm', δ_shape _ _ hnm, leftShift_zero, smul_zero] + +lemma δ_leftUnshift {a n' : ℤ} (γ : Cochain (K⟦a⟧) L n') (n : ℤ) (hn : n + a = n') + (m m' : ℤ) (hm' : m + a = m') : + δ n m (γ.leftUnshift n hn) = a.negOnePow • (δ n' m' γ).leftUnshift m hm' := by + obtain ⟨γ', rfl⟩ := (leftShiftAddEquiv K L n a n' hn).surjective γ + dsimp + simp only [leftUnshift_leftShift, γ'.δ_leftShift a n' m' hn m hm', leftUnshift_units_smul, + smul_smul, Int.units_mul_self, one_smul] + +@[simp] +lemma δ_shift (a m : ℤ) : + δ n m (γ.shift a) = a.negOnePow • (δ n m γ).shift a := by + by_cases hnm : n + 1 = m + · ext p q hpq + dsimp + simp only [shift_v', sub_add_cancel, shiftFunctor_obj_d', + δ_v n m hnm _ p q hpq (q - 1) (p + 1) rfl rfl, + δ_v n m hnm _ (p + a) (q + a) (by linarith) (q - 1 + a) (p + 1 + a) + (by linarith) (by linarith), + smul_add, Linear.units_smul_comp, Linear.comp_units_smul, add_right_inj] + rw [smul_comm] + · rw [δ_shape _ _ hnm, δ_shape _ _ hnm, shift_zero, smul_zero] + +lemma leftShift_rightShift (a n' : ℤ) (hn' : n' + a = n) : + (γ.rightShift a n' hn').leftShift a n hn' = + (a * n + (a * (a - 1)) / 2).negOnePow • γ.shift a := by + ext p q hpq + simp only [leftShift_v _ a n hn' p q hpq (p + a) (by linarith), + rightShift_v _ a n' hn' (p + a) q (by linarith) (q + a) (by linarith), units_smul_v, shift_v'] + dsimp + rw [id_comp, comp_id] + +lemma rightShift_leftShift (a n' : ℤ) (hn' : n + a = n') : + (γ.leftShift a n' hn').rightShift a n hn' = + (a * n' + (a * (a - 1)) / 2).negOnePow • γ.shift a := by + ext p q hpq + simp only [rightShift_v _ a n hn' p q hpq (q + a) (by linarith), + leftShift_v _ a n' hn' p (q + a) (by linarith) (p + a) (by linarith), units_smul_v, shift_v'] + dsimp + rw [id_comp, comp_id] + +/-- The left and right shift of cochains commute only up to a sign. -/ +lemma leftShift_rightShift_eq_negOnePow_rightShift_leftShift + (a n' n'' : ℤ) (hn' : n' + a = n) (hn'' : n + a = n'') : + (γ.rightShift a n' hn').leftShift a n hn' = + a.negOnePow • (γ.leftShift a n'' hn'').rightShift a n hn'' := by + rw [leftShift_rightShift, rightShift_leftShift, smul_smul, ← hn'', add_comm n a, mul_add, + Int.negOnePow_add, Int.negOnePow_add, Int.negOnePow_add, Int.negOnePow_mul_self, + ← mul_assoc, ← mul_assoc, Int.units_mul_self, one_mul] + end Cochain namespace Cocycle @@ -227,6 +505,28 @@ def rightUnshift {n' a : ℤ} (γ : Cocycle K (L⟦a⟧) n') (n : ℤ) (hn : n' rw [Cochain.δ_rightUnshift _ n hn (n + 1) (n + 1 - a) (by linarith), δ_eq_zero, Cochain.rightUnshift_zero, smul_zero]) +/-- The map `Cocycle K L n → Cocycle (K⟦a⟧) L n'` when `n + a = n'`. -/ +@[simps!] +def leftShift (γ : Cocycle K L n) (a n' : ℤ) (hn' : n + a = n') : + Cocycle (K⟦a⟧) L n' := + Cocycle.mk (γ.1.leftShift a n' hn') _ rfl (by + simp only [Cochain.δ_leftShift _ a n' (n' + 1) hn' (n + 1) (by linarith), + δ_eq_zero, Cochain.leftShift_zero, smul_zero]) + +/-- The map `Cocycle (K⟦a⟧) L n' → Cocycle K L n` when `n + a = n'`. -/ +@[simps!] +def leftUnshift {n' a : ℤ} (γ : Cocycle (K⟦a⟧) L n') (n : ℤ) (hn : n + a = n') : + Cocycle K L n := + Cocycle.mk (γ.1.leftUnshift n hn) _ rfl (by + rw [Cochain.δ_leftUnshift _ n hn (n + 1) (n + 1 + a) rfl, + δ_eq_zero, Cochain.leftUnshift_zero, smul_zero]) + +/-- The map `Cocycle K L n → Cocycle (K⟦a⟧) (L⟦a⟧) n`. -/ +@[simps!] +def shift (γ : Cocycle K L n) (a : ℤ) : + Cocycle (K⟦a⟧) (L⟦a⟧) n := + Cocycle.mk (γ.1.shift a) _ rfl (by simp) + end Cocycle end CochainComplex.HomComplex From b180173c90858e2031655e09a7165dbf1048324a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Fri, 5 Jan 2024 14:50:14 +0000 Subject: [PATCH 350/353] feat(Algebra/Homology): morphisms from the homotopy cofiber (#9447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR, we obtain `HomologicalComplex.homotopyCofiber.descEquiv` which expresses that if `φ : F ⟶ G` is a morphism of homological complexes, then a morphism `homotopyCofiber φ ⟶ K` is uniquely determined by a morphism `α : G ⟶ K` and a homotopy from `φ ≫ α` to `0`. --- Mathlib/Algebra/Homology/HomotopyCofiber.lean | 140 +++++++++++++++++- 1 file changed, 139 insertions(+), 1 deletion(-) diff --git a/Mathlib/Algebra/Homology/HomotopyCofiber.lean b/Mathlib/Algebra/Homology/HomotopyCofiber.lean index 3c4e3799651b4..c40dcc9bdef3f 100644 --- a/Mathlib/Algebra/Homology/HomotopyCofiber.lean +++ b/Mathlib/Algebra/Homology/HomotopyCofiber.lean @@ -18,7 +18,7 @@ When we assume `hc : ∀ j, ∃ i, c.Rel i j` (which holds in the case of chain or cochain complexes indexed by `ℤ`), then for any homological complex `K`, there is a bijection `HomologicalComplex.homotopyCofiber.descEquiv φ K hc` between `homotopyCofiber φ ⟶ K` and the tuples `(α, hα)` with -`α : G ⟶ K` and `hα : Homotopy (φ ≫ α) 0` (TODO). +`α : G ⟶ K` and `hα : Homotopy (φ ≫ α) 0`. We shall also study the cylinder of a homological complex `K`: this is the homotopy cofiber of the morphism `biprod.lift (𝟙 K) (-𝟙 K) : K ⟶ K ⊞ K`. @@ -229,4 +229,142 @@ noncomputable def homotopyCofiber : HomologicalComplex C c where · simp [homotopyCofiber.inlX_d' φ j k hjk hk] · simp + +namespace homotopyCofiber + +/-- The right inclusion `G ⟶ homotopyCofiber φ`. -/ +@[simps!] +noncomputable def inr : G ⟶ homotopyCofiber φ where + f i := inrX φ i + +section + +variable (hc : ∀ j, ∃ i, c.Rel i j) + +/-- The composition `φ ≫ mappingCone.inr φ` is homotopic to `0`. -/ +noncomputable def inrCompHomotopy : + Homotopy (φ ≫ inr φ) 0 where + hom i j := + if hij : c.Rel j i then inlX φ i j hij else 0 + zero i j hij := dif_neg hij + comm j := by + obtain ⟨i, hij⟩ := hc j + rw [prevD_eq _ hij, dif_pos hij] + by_cases hj : c.Rel j (c.next j) + · simp only [comp_f, homotopyCofiber_d, zero_f, add_zero, + inlX_d φ i j _ hij hj, dNext_eq _ hj, dif_pos hj, + add_neg_cancel_left, inr_f] + · rw [dNext_eq_zero _ _ hj, zero_add, zero_f, add_zero, homotopyCofiber_d, + inlX_d' _ _ _ _ hj, comp_f, inr_f] + +lemma inrCompHomotopy_hom (i j : ι) (hij : c.Rel j i) : + (inrCompHomotopy φ hc).hom i j = inlX φ i j hij := dif_pos hij + +lemma inrCompHomotopy_hom_eq_zero (i j : ι) (hij : ¬ c.Rel j i) : + (inrCompHomotopy φ hc).hom i j = 0 := dif_neg hij + +end + +section + +variable (α : G ⟶ K) (hα : Homotopy (φ ≫ α) 0) + +/-- The morphism `homotopyCofiber φ ⟶ K` that is induced by a morphism `α : G ⟶ K` +and a homotopy `hα : Homotopy (φ ≫ α) 0`. -/ +noncomputable def desc : + homotopyCofiber φ ⟶ K where + f j := + if hj : c.Rel j (c.next j) + then fstX φ j _ hj ≫ hα.hom _ j + sndX φ j ≫ α.f j + else sndX φ j ≫ α.f j + comm' j k hjk := by + obtain rfl := c.next_eq' hjk + dsimp + simp [dif_pos hjk] + have H := hα.comm (c.next j) + simp only [comp_f, zero_f, add_zero, prevD_eq _ hjk] at H + split_ifs with hj + · simp only [comp_add, d_sndX_assoc _ _ _ hjk, add_comp, assoc, H, + d_fstX_assoc _ _ _ _ hjk, neg_comp, dNext, AddMonoidHom.mk'_apply] + abel + · simp only [d_sndX_assoc _ _ _ hjk, add_comp, assoc, add_left_inj, H, + dNext_eq_zero _ _ hj, zero_add] + +lemma desc_f (j k : ι) (hjk : c.Rel j k) : + (desc φ α hα).f j = fstX φ j _ hjk ≫ hα.hom _ j + sndX φ j ≫ α.f j := by + obtain rfl := c.next_eq' hjk + apply dif_pos hjk + +lemma desc_f' (j : ι) (hj : ¬ c.Rel j (c.next j)) : + (desc φ α hα).f j = sndX φ j ≫ α.f j := by + apply dif_neg hj + +@[reassoc (attr := simp)] +lemma inlX_desc_f (i j : ι) (hjk : c.Rel j i) : + inlX φ i j hjk ≫ (desc φ α hα).f j = hα.hom i j := by + obtain rfl := c.next_eq' hjk + dsimp [desc] + rw [dif_pos hjk, comp_add, inlX_fstX_assoc, inlX_sndX_assoc, zero_comp, add_zero] + +@[reassoc (attr := simp)] +lemma inrX_desc_f (i : ι) : + inrX φ i ≫ (desc φ α hα).f i = α.f i := by + dsimp [desc] + split_ifs <;> simp + +@[reassoc (attr := simp)] +lemma inr_desc : + inr φ ≫ desc φ α hα = α := by aesop_cat + +@[reassoc (attr := simp)] +lemma inrCompHomotopy_hom_desc_hom (hc : ∀ j, ∃ i, c.Rel i j) (i j : ι) : + (inrCompHomotopy φ hc).hom i j ≫ (desc φ α hα).f j = hα.hom i j := by + by_cases hij : c.Rel j i + · dsimp + simp only [inrCompHomotopy_hom φ hc i j hij, desc_f φ α hα _ _ hij, + comp_add, inlX_fstX_assoc, inlX_sndX_assoc, zero_comp, add_zero] + · simp only [Homotopy.zero _ _ _ hij, zero_comp] + +lemma eq_desc (f : homotopyCofiber φ ⟶ K) (hc : ∀ j, ∃ i, c.Rel i j) : + f = desc φ (inr φ ≫ f) (Homotopy.trans (Homotopy.ofEq (by simp)) + (((inrCompHomotopy φ hc).compRight f).trans (Homotopy.ofEq (by simp)))) := by + ext j + by_cases hj : c.Rel j (c.next j) + · apply ext_from_X φ _ _ hj + · simp [inrCompHomotopy_hom _ _ _ _ hj] + · simp + · apply ext_from_X' φ _ hj + simp + +end + +lemma descSigma_ext_iff {K : HomologicalComplex C c} + (x y : Σ (α : G ⟶ K), Homotopy (φ ≫ α) 0) : + x = y ↔ x.1 = y.1 ∧ (∀ (i j : ι) (_ : c.Rel j i), x.2.hom i j = y.2.hom i j) := by + constructor + · rintro rfl + tauto + · obtain ⟨x₁, x₂⟩ := x + obtain ⟨y₁, y₂⟩ := y + rintro ⟨rfl, h⟩ + simp only [Sigma.mk.inj_iff, heq_eq_eq, true_and] + ext i j + by_cases hij : c.Rel j i + · exact h _ _ hij + · simp only [Homotopy.zero _ _ _ hij] + +/-- Morphisms `homotopyCofiber φ ⟶ K` are uniquely determined by +a morphism `α : G ⟶ K` and a homotopy from `φ ≫ α` to `0`. -/ +noncomputable def descEquiv (K : HomologicalComplex C c) (hc : ∀ j, ∃ i, c.Rel i j) : + (Σ (α : G ⟶ K), Homotopy (φ ≫ α) 0) ≃ (homotopyCofiber φ ⟶ K) where + toFun := fun ⟨α, hα⟩ => desc φ α hα + invFun f := ⟨inr φ ≫ f, Homotopy.trans (Homotopy.ofEq (by simp)) + (((inrCompHomotopy φ hc).compRight f).trans (Homotopy.ofEq (by simp)))⟩ + right_inv f := (eq_desc φ f hc).symm + left_inv := fun ⟨α, hα⟩ => by + rw [descSigma_ext_iff] + aesop_cat + +end homotopyCofiber + end HomologicalComplex From 401d91423d3f391ed8af1b0212c02bb0d2de3a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 5 Jan 2024 17:56:11 +0000 Subject: [PATCH 351/353] chore: Downgrade `Algebra.Associated` (#9459) Part of #9411 --- Mathlib/Algebra/Associated.lean | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Mathlib/Algebra/Associated.lean b/Mathlib/Algebra/Associated.lean index 680c895bef388..1c909dcee25d0 100644 --- a/Mathlib/Algebra/Associated.lean +++ b/Mathlib/Algebra/Associated.lean @@ -3,8 +3,6 @@ Copyright (c) 2018 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Jens Wagemaker -/ -import Mathlib.Algebra.Divisibility.Basic -import Mathlib.Algebra.GroupPower.Lemmas import Mathlib.Algebra.Parity #align_import algebra.associated from "leanprover-community/mathlib"@"2f3994e1b117b1e1da49bcfb67334f33460c3ce4" @@ -306,7 +304,7 @@ variable [CommMonoid α] {a : α} theorem Irreducible.not_square (ha : Irreducible a) : ¬IsSquare a := by rw [isSquare_iff_exists_sq] rintro ⟨b, rfl⟩ - exact not_irreducible_pow one_lt_two.ne' ha + exact not_irreducible_pow (by decide) ha #align irreducible.not_square Irreducible.not_square theorem IsSquare.not_irreducible (ha : IsSquare a) : ¬Irreducible a := fun h => h.not_square ha From 26ccd1e9cdd53bee750bb6fba6f40db23a7d88f5 Mon Sep 17 00:00:00 2001 From: Xavier Xarles Date: Fri, 5 Jan 2024 18:57:29 +0000 Subject: [PATCH 352/353] feat (Mathlib/Algebra/Regular/Basic.lean): Add lemmas on RightRegular (#9464) A couple of lemmas on RightRegular that could be useful for future work on Localization --- Mathlib/Algebra/Regular/Basic.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Mathlib/Algebra/Regular/Basic.lean b/Mathlib/Algebra/Regular/Basic.lean index 56ec13a6f3950..1d72eeaac3c6e 100644 --- a/Mathlib/Algebra/Regular/Basic.lean +++ b/Mathlib/Algebra/Regular/Basic.lean @@ -88,6 +88,15 @@ theorem IsLeftRegular.right_of_commute {a : R} fun x y xy => h <| (ca x).trans <| xy.trans <| (ca y).symm #align is_left_regular.right_of_commute IsLeftRegular.right_of_commute +theorem IsRightRegular.left_of_commute {a : R} + (ca : ∀ b, Commute a b) (h : IsRightRegular a) : IsLeftRegular a := by + simp_rw [@Commute.symm_iff R _ a] at ca + exact fun x y xy => h <| (ca x).trans <| xy.trans <| (ca y).symm + +theorem Commute.isRightRegular_iff {a : R} (ca : ∀ b, Commute a b) : + IsRightRegular a ↔ IsLeftRegular a := + ⟨IsRightRegular.left_of_commute ca, IsLeftRegular.right_of_commute ca⟩ + theorem Commute.isRegular_iff {a : R} (ca : ∀ b, Commute a b) : IsRegular a ↔ IsLeftRegular a := ⟨fun h => h.left, fun h => ⟨h, h.right_of_commute ca⟩⟩ #align commute.is_regular_iff Commute.isRegular_iff From c6529053211bed9dd64a3ad40836b30ff1e3eac9 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 6 Jan 2024 05:23:43 +0000 Subject: [PATCH 353/353] fix(Analysis/NormedSpace/OperatorNorm): muddled norm and nnnorm (#9473) This is a lemma about `nnnorm`, but it seems one of the arguments was forgotten. --- Mathlib/Analysis/NormedSpace/OperatorNorm.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm.lean index 8a2d176302e92..72eae739234a7 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm.lean @@ -370,7 +370,7 @@ theorem op_nnnorm_le_of_lipschitz {f : E →SL[σ₁₂] F} {K : ℝ≥0} (hf : op_norm_le_of_lipschitz hf #align continuous_linear_map.op_nnnorm_le_of_lipschitz ContinuousLinearMap.op_nnnorm_le_of_lipschitz -theorem op_nnnorm_eq_of_bounds {φ : E →SL[σ₁₂] F} (M : ℝ≥0) (h_above : ∀ x, ‖φ x‖ ≤ M * ‖x‖) +theorem 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 #align continuous_linear_map.op_nnnorm_eq_of_bounds ContinuousLinearMap.op_nnnorm_eq_of_bounds